I'm working on a PHP / AJAX application and it's quickly becoming unmanageable!
The application is designed to work much like a a desktop application so almost every user action results in an AJAX call.
For every one of these actions I have some jQuery that posts the data to my PHP script and runs a corresponding PHP function that handles the server side actions.
That means in my jQuery file i'll have something like this:
$('.delete-project').on('click', function(){
// Ajax request to http://myapp.co.uk/ajax/delete_project
});
$('.delete-user').on('click', function(){
// Ajax request to http://myapp.co.uk/ajax/delete_user
});
$('.delete-keyword').on('click', function(){
// Ajax request to http://myapp.co.uk/ajax/delete_keyword
});
I'm sure there is a better way of doing things, but how is it generally done to avoid lots of similar code? The above actions could possible rolled into one 'delete' ajax request which posts the item type and a database ID but a lot of my functions post different data and require different parameters so wouldn't fit so neatly under one jQuery handler.
I've tried finding some resources on how an AJAX application should be put together but all I can find is beginner tutorials on making AJAX requests etc, not how to write a scalable AJAX application.
Just to be clear I know how AJAX works, I'm just trying to find the best way of implementing it in terms of reducing the jQuery and PHP needed where possible.
Are there any good resources that deal with this sort of thing?
You can roll all those into one delete function by using attributes in HTML, for example:
$('.delete').on('click', function(){
var delete = $(this).attr('data-delete');
// Ajax request to http://myapp.co.uk/ajax/delete_{delete}
});
Then your HTML would be something like:
Delete
More information on data-attributes
Not sure if this would help but you could create some functions to reduce your code as it grows. For starters you could prevent duplicating of the ajax call by putting the jQuery .ajax function in a custom wrapper function of your own. For example:
function ajaxGet(myUrl, queryString, successCallback, errorCallback) {
if(queryString) myUrl+= "?" + queryString;
$.ajax({
url: myUrl,
type: "GET",
data: null,
success: function (res) {
if(!successCallback) return;
else successCallback(res);
},
failure: function (res) {
if(!errorCallback) return;
else errorCallback(res);
}
},
By creating a wrapper function, you can pass in the needed data without duplicating the $.ajax call code over and over in each of the click functions. You can also create a similar function for an ajax call using post. You could then dynamically build the click functions to further reduce your code:
function buildClicks() {
setupClick([url], [data], [success], [error], [$(elem)]);
setupClick([url], [data], [success], [error], [$(elem)]);
setupClick([url], [data], [success], [error], [$(elem)]);
}
//Setup clicks for each button or link
function setupClick(url, data, success, error, elem) {
elem.click(function () {
ajaxGet(url, data, success, error);
});
}
In this example I'm assuming your using a "GET" and adding a query string. You could easily adapt this to pass, a JSON formatted object for example, using a custom "POST" function. In that case [data] would be an object not a query string.
Sorry this code isn't the clearest. Let me explain it a little more. The buildClicks function would allow you to setup multiple click events on different elements by passing in the required data. I'm not sure if you are passing any data, but the above functions would allow for it. By dynamically creating the clicks you can avoid duplicating the .click code over and over. Just call the buildClicks function on document ready as such.
$(document).ready(function () { buildClicks(); });
NOTE: The success and error callbacks are functions that will be executed when your call either completes successfully or errors out. If you do not wish to use these they can be ommitted or null can be passed in. Make sure if you do pass in functions that you leave off the "()" on the end of the function name. Otherwise the functions will be executed prior to the success or failure of the ajax call. For example:
ajaxGet("http://testurl.com", null, ajaxSuccess, ajaxFailure);
ajaxSuccess() {
}
ajaxFailure() {
}
You could set an ID attributes to that buttons and a class like submit-button.
Then hang a handler on that $('.submit-button') while using an ID attribute value to define the URL to call, like that:
$('.submit-button').on('click', function(){
$action = $(this).attr('id'); //lets say the ID's value is 'delete_project'
$url = 'http://myapp.co.uk/ajax/' + $action;
// Ajax request to http://myapp.co.uk/ajax/delete_project is done
});
Anyway any web application that tends to be like a desktop one is only a bunch of JS and few HTML with some PHP behind... That is always badly maintanable...
I used [extJs][1] once for this, which led to using only jQuery and their modules while no (or just a minimum of) HTML was needed to write...
Not a copy-and-paste-solution, but maybe you find some more ideas how to build a scalable client-server application when looking for how REST APIs are built. I find REST a very good structure to keep a clear server-side API when building such apps, and i'm sure there are tutorials around how to do the corresponding client-part cleanly too.
In my application I do quite a lot of ajax calls too. I found that the easiest way to do things was to create myself a wrapper for all ajax calls such as:
var MySite = function()
{
AjaxWrapper : function(type,url,data,callback,noloading)
{
$.ajax({
type: type,
url: url,
data: data,
success:function(json)
{
if(json.status === true)
{
if(typeof callback === 'function')
{
callback(json);
} else {
// A generic success handler
}
} else {
// An error handler
}
}
});
};
}();
then you'd call it like:
MySite.AjaxWrapper("GET", "somehref", {}, function(json)
{
// json has the result of your json callback
// you could also make this a separate function
// or not have it
});
this let's you call your ajax on just about anything you want. You could then use something like data attributes, or just the standard href for anything that requires ajax and add an event to all links that pass through this function. Or, if you wanted some to do certain things just make the callback function different for those.
I'm finding this hard to explain, but this is what I've used for a couple of ajax-rich projects and it makes things so much easier!
For an example for your case you could then use something like:
$('a[class|="delete"]').on("click", function()
{
MySite.AjaxWrapper("POST", $(this).attr("href"), {param:number1}, DeleteHandler);
});
The way I would do this would be to have a single function for all actions:
$('.actions').on('click', function (e) {
e.preventDefault();
var action = $(this).data('action'),
id = $(this).data('id');
$.get('/local/handler.php', {
'action': action,
'id': id
}, function () {
// Callback stuff here
});
});
And HTML:
Delete Project
Delete User
Delete Keywork
And the PHP file should have if statements based on the action parameter that performs the requested action.
EDIT:
This way your not limited to just delete actions, so you can scale your app in the future.
Also, If the different actions become a large list (e.g. deletes of many kinds, updates, adding), I would create a separate PHP file for each action and include them in one master file. This will allow for easy scaling.
Related
I am looking to display the total number of files in a database. To clarify, say I had a website where people could upload pictures of their cars, and I wanted to display a live number of how many pictures there are, what would be the best way to do this? Javascript, php? A mix? I envision a div with a number saying "Total Pictures: x" and where x would be whatever the live total is. I plan on using MySQL to store all the data on the website. Is this even recommended to have something communicate with the server this much? Is there a name for displaying a live number? Thanks!
If you are thinking to use the AngularJS way, you could create a Poller service which polls every second (assuming your /counter.php returns json):
app.factory('Poller', function($http, $timeout) {
var data = { response: {}};
var poller = function() {
$http.get('/counter.php').then(function(r) {
data.response = r.data;
$timeout(poller, 1000);
});
};
poller();
return {
data: data
};
});
Then your controller:
app.controller('CounterCtrl', function(Poller, $scope){
$scope.counter = Poller.data;
});
And finally in your view:
{{counter.response}}
You can read more about $http
Set up a PHP script that queries the database and returns the total file upload count. After that, you can use JavaScript on the page to periodically call the server in a specified interval of time and fetch the count data from your PHP script. Using jQuery and GET, you can do something like this:
jQuery(function($){
setInterval(function(){
$.get( '/counter.php', function(fileUploadCount){
$('#counter').html( fileUploadCount );
});
},20000); // 20 seconds
});
In your HTML:
<p><span id='counter'>xx</span> files have been uploaded so far!</p>
Hope this helps!
How live do you want it to be? Just whenever someone updates the site it's going to have the new value or do you actually want it to update in near real-time?
If it's the latter you have to use Javascript against some kind of API that returns the amount of files in the database. I can't help you with that bit since you are using PHP, but it shouldn't be too hard. Just return some JSON looking something like
{ fileCount: 45020 }
Client-side you have a few options. You have the different javascript frameworks like AngularJS and EmberJS (and many more), as well as just 'plain old' javascript and frameworks like jQuery
The keyword is really AJAX, even if that is just a sort of buzzword for using javascript to make websites dynamic.
I am a fan of using AngularJS because it's easy, but I'll try to give you some pointers for using jQuery first. Note that I have not used jQuery in years now.
The jQuery way
jQuery has a function called jQuery.getJSON(), and according to the documentation you can use that function something like this:
// Assign handlers immediately after making the request,
// and remember the jqxhr object for this request
var jqxhr = $.getJSON( "http://example.com/api/fileCount.json")
.done(function(data) { console.log(data) })
.fail(function() { console.log( "error" ); })
.always(function() { console.log( "complete" ); });
So this means we can call an endpoint and fetch some data using jQuery.
Here is a link to a tutorial about the basics of jQuery by the way.
jQuery makes us able to do things like this:
<div id="divTest1"></div>
<script type="text/javascript">
$("#divTest1").text("Hello, world!");
</script>
When that is executed the div with id "divTest1" will contain the text 'Hello, world!'.
That sounds like something we could use here!
Javascript also has this really nice function called setTimeout(), which allows us to make it call a function later.
This describes how to use jQuery with setTimeout()
As you can see it also shows us jQuery.documentReady(), which is an event that fires when the website is finished loading, so it is a good place to put code we want executed.
The example below shows how to use jQuery to hide a div with id=div after 3 seconds.
jQuery(document).ready(function () {
setTimeout( "jQuery('#div').hide();",3000 ); //hide a div after 3 seconds
});
Combining these things you should be able to make a repeating call that fetches data from your server and then updates a div or another element with the data you have fetched.
Just create a function which uses jQuery.getJSON() to fetch data, and then at the bottom of that add a setTimeout call to run itself in X seconds (however often you want it to update).
In jQuery.documentReady() you call that function the first time the document loads.
And in the .done() bit of the getJSON() call you add the data you got from the server to your div with whatever html you want. I showed you how to use $("#divTest1").text(), but there is also a .html() which acts the same but you should use it to add html to a element.
The angular way would be to use AngularJS's $http to do the same thing, but I wouldn't recommend learning AngularJS until you have a bit of a better grasp on Javascript.
When you do though, I highly recommend it. It's a much better approach than using jQuery.
You can read about AngularJS here
I hope this helps!
In my website I will have a "browse catalogue" button, which, onclick will change several elements of the page to display the catalogue element. I dont want a full page reload because several elements such as the nav bars and news feed will stay the same.
My question is how can i change several different divs with ajax onclick?
Essentially im not sure how to do place several different components in different divs across a page.
And i know there's a limit on simultaneous ajax calls, so im sure the proper way to do it wouldnt be to make a unique ajax call for each of my divs.
A little guidance would be great.
Using jQuery, you can get an json array of elements for each block that needs to be updated:
In your html page:
$.get("page.php?id=42",
function(result){
$('#title').text(result['title']);
$('#description').text(result['description']);
$('#price').text(result['price']);
}, "json");
In page.php:
$result = array('title' => 'foo', 'description' => 'bar', 'price' => 3);
echo json_encode($result);
header('Content-Type: application/json');
die();
I'm not sure if the right decision will be to send several ajax requests. Just create a request with unique attribute value, in so shape that server will know which blocks you need. On server side all required blocks concatenate in json object, and return it to client. After just parse object on blocks that should be. For example
$.ajax({
url : 'http://your.server.doment',
data : 'block[]=1&block[]=7&block[]=15',
type : 'post',
dataType : 'json',
success : function (object){
for( el in object) { $('#block_'+el).html(object[el]); }
}
});
you can use json
example
php request ajax
$div1="<table><tr><td>x</td></tr></table>";
$div2="<table><tr><td>x</td></tr></table>";
$div3="<table><tr><td>x</td></tr></table>";
$json = '{"div1":"'.$div1.'","div2":"'.$div2.'","div3":"'.$div3.'"}';
return $json;
uses jquery
$.ajax({url: 'ajax/test.php',
success: function(data) {
var obj = JSON.parse(data);
$("mydiv1").html(obj.div1);
$("mydiv2").html(obj.div2);
$("mydiv3").html(obj.div3);
}});
if you have a error in the parce function
replace spaces
example
$arr =array("\n","\t");
$div1= str_replace($arr,"",$div1);
Practically, ten or more elements updated in parallel on the page (each by a separate ajax) will not make such a big difference (unless you can test it with your website deployed into productive environment and prove I am wrong).
Nonetheless, if you wish to compact all the data exchange to one single request/response ajax call - it is very well possible but does require certain flexibility on the server side (see http://php.net/manual/en/function.json-encode.php).
I.e. one of the possible solutions is to produce json response on the server side, that generates a key-value pairs (JSON - javascript {} object) with keys being id of your elements and values being (new) html.
There are tons of ajax JS frameworks as jQuery, prototype, dojo, etc. (I will pick jQuery for this one).
Ajax request
$.ajax({
...
})
See http://api.jquery.com/jQuery.ajax/
Server response
// Assume we got
// var data = {key1:'html1',key2: 'html2'};
// Ajax handle can look like
success(data) {
$.each(data, function(key, val){
//console.log(key, val);
// Do some checks here.. But key should indicate #id of html elements
$(key).empty().append(html);
});
}
This is a basic outline but should keep you going into the right direction.
I have an issue when trying to get Javascript to execute functions in my desired order. I'm trying to get a jQuery modal form to load information based on a certain selection. I have two SELECT boxes that need to be loaded, but the contents of the second SELECT box depend entirely on the selected value of the first SELECT box.
I made the following functions to request the information I need:
function get_Subjects(varID, callback){
$.post("../vars/get_SID.php", { vid : varID },
function(result){
getInfo('tbsubjectdiv', '../vars/findSubjectlist.php?sid='+result);
});
callback();
}
function get_Selectedfields(varID, callback){
$.post("../vars/requestTblock.php", { vid : varID },
function(result){
populateForm('tbWiz', result);
document.form_tbWiz.varname.disabled = true;
$('.trSearch').hide();
$('.trValueset').hide();
});
callback();
}
function get_TextblockType(varID, callback){
$.post("../vars/requestVtype.php", { vid : varID },
function(result){
if(result == 0){ //Opzoeken
$('.trSearch').show();
}else if(result == 1){ //Datum vergelijken
$('.trSearch').show();
$('.trValueset').show();
}else if(result == 2){ //Percentage
//
}
});
callback();
}
The first function checks the MySQL database for the selected value
of the FIRST SELECT field, and loads the results into the second
SELECT field.
The second function requests the rest of the rest of the form data, and populates the form using populateForm(). It also hides
certain parts of my form in preparation for function three.
The third function basically requests which parts of the form have to be displayed, because that's not always the same.
The whole idea behind this is that I want to use populateForm() to populate all of the form fields. In order for populateForm() to properly set the selected SELECT option, the particular SELECT field must first contain the OPTION it needs to select. Makes sense. I try to make sure of this with my first function, which will load all of the OPTIONs. THEN I try to use the get_Selectedfields() to populate all the proper values. This is not what happens though. No matter what I try to do, getInfo() in the first function is ALWAYS being called LAST. This makes it impossible for populateForm() to select the proper option, which is driving me mad.
I'm trying to "force" the execution-order by doing this:
function getTextblock(var_ID){
get_Subjects(var_ID, function() {
get_Selectedfields(var_ID, function() {
get_Textblocktype(var_ID, function() {
// Done
});
});
});
}
When I realised it still did not work the way I wanted, I decided to use Chrome's Developer Tools to check the order in which everything is executed. It all works as expected, but at the very end it jumps straight back to getInfo(), which is part of the FIRST function I called. I'm absolutely clueless as to why getInfo() gets executed last. If this just gets executed at the very beginning, where I want it to execute, it would all work fine.
You have to call the callback in the callback function of the post request:
function get_Subjects(varID, callback){
$.post("../vars/get_SID.php", { vid : varID },
function(result){
getInfo('tbsubjectdiv', '../vars/findSubjectlist.php?sid='+result);
callback();
});
}
function get_Selectedfields(varID, callback){
$.post("../vars/requestTblock.php", { vid : varID },
function(result){
populateForm('tbWiz', result);
document.form_tbWiz.varname.disabled = true;
$('.trSearch').hide();
$('.trValueset').hide();
callback();
});
}
function get_TextblockType(varID, callback){
$.post("../vars/requestVtype.php", { vid : varID },
function(result){
if(result == 0){ //Opzoeken
$('.trSearch').show();
}else if(result == 1){ //Datum vergelijken
$('.trSearch').show();
$('.trValueset').show();
}else if(result == 2){ //Percentage
//
}
callback();
});
}
The POST is being handled asynchronously in your functions so your "callback" is really just being executed almost immediately after your initial call, whereas the callback of $.post is being executed after the post has occurred. Does that help you sort things out? You will probably need to kick off the rest of the process in the callback of $.post("../vars/get_SID.php", { vid : varID }...
$.post is shorthand for $.ajax so you can read up a bit more in the jQuery docs, but I would not suggest switching to synchronous requests. If you absolutely must have one request finished before the next can execute then kicking off that next step from the callback is the way to go.
You're using ajax. The first a is for asynchronous. If you called the functions from the function(result) blocks then they would occur in order.
Alternatively (and this isn't a great idea but you can do it) use the $.ajax() object and set async to false.
As you don't know how long long an ajax request will actually take, you can only chain events within the ajax response:
function getTextblock(var_ID){
$.post(YOUR_TARGET, YOUR_DATA, function(result){
YOUR_CODE
// CHAIN HERE, call new function or sub ajax request
});
}
Wesley,
The javascript will execute always on the predefined order. If you put a bunch of "alerts()" in the middle of your code, you can taste that.
But this is not true for callbacks, because they will be moved to the bottom of execution stack on javascript where we can't determine the order, since they are called by a AJAX return which by definition is asynchronous.
Even though your ajax executes in a millisecond, the callback will not be executed until all methods in your script block have finished.
You have, actually three options:
Chain all the methods sequence in callbacks. Please, don't call a callback!! It inst supposed to be you, but the "system" that will call those.
// The data you need first
function myStartPoint() {
$.post(url, function(result) {
// do what you need with this result (this is your callback, but anonymous)
// then, call the next step
secondPoint();
});
}
function secondPoint() {
$.post(url, function(result) {
// again, the callback is anonymous... your hardly need to declare something named callback
// chain how many points as you need
nextPoint();
}
}
"Force" the ajax to be synchronous with async:false option. This can cause performance issues.
The ugliest of all is to use the damned setTimeout which is very, very wrong, but will work in your case because, the setTimeout will put the method on the bottom of execution stack even after those callbacks which are expected to be fast. Seriously, I just put this option because eventually someone would say it... Do not take this path.
Before I begin, I'm using PHP and JS lib Prototype to handle Ajax in my code.
So my problem is the following:
I'm using the following function to load a php file into a target DIV
function ajaxUpdater(id, url)
{
new Ajax.Updater('targetDiv', 'data.php', {asynchronous: true});
}
using the onClick function within a button, I grab the contents of data.php and display it in a DIV with the id of 'targetDiv'.
the problem is this.
There are certain things within data.php that i want to have hidden and only shown when an event is triggered.
I've been trying loads of different solutions, but nothing seems to work.
(just to add to the confusion, functions work when data.php is opened individually, but not when data.php is loaded using my ajax function.
Any help or clues or anything will be much appreciated!
Hiroki,
I'd suggest passing some a parameter with your Ajax method and using some logic in data.php to pick and choose what data to send back. Here's an example of how I pass parameters with my prototype calls.
new Ajax.Updater('targetDiv', 'data.php', {
parameters: { myParam1: 'hello', myParam2: 'world'}
});
The go into your data.php file to create some logic. Note that by default, prototype's method to send params is POST, but you can always change that by declaring method: 'get' in the same Ajax.Updater call, like so:
new Ajax.Updater('targetDiv', 'data.php', {
method: 'get',
parameters: { myParam1: 'hello', myParam2: 'world'}
});
Check out the AJAX section of the Prototype API. In it, it talks about an option you can use called 'evalJS' that you can set to true. When you have this option set, any javascript returned by the updater will be evaluated and ran like normal.
function ajaxUpdater(id, url) {
new Ajax.Updater('targetDiv', 'data.php', {
asynchronous: true,
evalJS: true
});
}
I'm having a really difficult time understanding how this all works together. I've fiddled for a few days with this and have been unable to come up with any results. I'm trying to fill in a text field in a form, and when the form is submitted, I want to add the text to my sqlite db using ajax.
I understand that you need a $.get call in jquery which is triggered on the form's submit. That seems to work fine as I can trigger js alert boxes from there. However, when I pass the address of the php script which has lines to add to the sqlite db using PDO, nothing is added to the db. However, when I run this php script from using php cli, something will get added to the db.
I seem to be missing an essential step here. I would really appreciate it if someone could bridge this gap for me!
Edit:
As requested by Martin here's some code:
My php generates some list like this with a form in the middle:
<ul>
<li>hello</li>
<li id="formItem">
<form action="" method="post">
<input type=text name="content"/>
</form>
</li>
<li>world</li>
</ul>
Then my jquery code looks to add whatever is in the textbox right above it on the list does an ajax call. This is inside a $(document).ready(function(){.
$("form").submit(function() {
var inputText = $("input").val();
$.ajax({
type: "POST",
url: "add.php",
data: inputText,
success: function() {
$('#formItem').prev().after(
"<li>" + inputText + "</li>"
)}
});
});
My add.php file looks like this and it will insert something into my db if I execute the php script on the cli:
<?php
$base = new PDO('sqlite:todo.db');
$sql = $base->prepare("INSERT INTO ThisTable (content, priority) VALUES ('lolololol', 1);");
$sql->execute();
$base = null;
?>
Do not forget that HTTP is a stateless protocol. Each HTTP request you make to your webserver is treated the same. This stands for whether the HTTP request was made using AJAX or not.
What I'm trying to say is that AJAX is a client side implementation. All AJAX means is that you can interact with your webserver without having to reload your page. Implementing an AJAX request for the first time in JavaScript is often a brain bender, because the requirement of callbacks and the general asynchronous nature of the interaction makes it difficult to grasp.
On the server however, there should be nothing to worry about. An AJAX request is still an HTTP request, so whether you navigate to http://www.yourwebsite.com/ajax/interact.php?a=1&b=2 in your browser, or make a HTTP GET request using AJAX, your PHP script will still behave exactly the same. If you var_dump($_GET); in either situation, you will get an array whose a and b members equal 1 and 2 respectively.
If you can emulate the AJAX request in your browser successfully by navigating to the URL manually, that's the server work done.
Having established that, your JavaScript should look something like this:
$('#yourForm').bind('submit', function (event) {
jQuery.get('/ajax/interact.php', 'a=1&b=2', function (response) {
alert("AJAX request succeeded, response from the server was: " + response);
});
event.preventDefault();
});
Once you're confident using jQuery's AJAX methods, you might want to look at methods such as serialize() to help you out, and you can develop your jQuery code to something as follows:
$('form.ajax').live('submit', function (event) {
var self = $(this);
jQuery[(self.attr('method') || 'get').toLowerCase()](self.attr('action'), self.serialize(), function (response) {
alert("AJAX request succeeded, response from the server was: " + response);
});
event.preventDefault();
});
Hope this helps :)
Your submit function should return false;