My webpage needs to send/receieve several ajax operations when being used. Currently I use one ajax handler to handle all events. All ajax requests are sent/received using this format "(type) | {json string}".
A piece of js code will handler the ajax requests/responses: parsing response text -> getting type -> select...case doing something in each type case.
This works but as ajax events grow there are too many cases like from 0 to 99. Well it's not likely to be an easy job for maintenance or further developing.
Maybe I need to split the single ajax handler to mulitiple ones? Then how does the browser know which ajax response should be sent to the specific handler?
Any advice is appreciated.
Currently the code looks like this: (one of the pages using simple javascript, no framework used)
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
//alert(xmlhttp.responseText);
var reply = decodeArray(xmlhttp.responseText); //convert to json object and some other stuff
switch (reply.type) {
case 0:
case 1:
....
}
This is one of the fundamental challenges with software engineering. You have a task that you do repeatedly, but the details change slightly with each variation, so how do you reuse code and keep things clean....every substantial app has this problem.
You need to use a design approach that enforces good Separation of Concerns. I usually develop on API for my app that is completely separate from other parts of the app. My API does one thing and one thing only -- it communicates with the server.
It has no application specific code.
This means I can reuse my api in different apps, if necessary. It also means I can test my API independently of the app.
So lets say you need to do something like loadObject. The applications sees
App.API = {
loadObject: function(params, onSuccess, onFail) {...}
}
The key to keeping this decouples is the onSuccess and onFail callbacks. The application that is using the API passes in these functions; so the API knows nothing of the application specific logic -- all it knows is that if fires these callbacks appropriately. The callbacks are methods that take arguments that are the response data; all the API does is pass the response data to the callback.
Since most of the time, the details of your ajax calls have lots of common items, I also would create some sort of XhrWrapper that fires requests. So in your loadObjects you would use your xhr helper to make the request
xhr.sendRequest(url, method, onSuccess, onFail);
This way all the tedium of firing xhrs is minimized.
Obviously, you can go further; for example, most of the time failure is bad, so my xhr wrapper will have a default onFail implementation, and specific API methods can pass in an override, only if it makes sense.
Related
So far when creating AJAX requests I have been posting to a separate PHP file. Is it possible to create a jQuery AJAX request that calls a PHP function rather than posts to a separate page?
If you could send me any examples or documentation would be great.
I believe there's a fundamental misunderstanding of how the technology works here.
AJAX (Javascript), Flash, or any client-sided technology cannot directly call PHP functions (or other languages running on the server).
This is true for going the other way around as well (eg: PHP can't call JS functions).
Client and server codes reside on different machines, and they communicate through the HTTP protocol (or what have you). HTTP works roughly like this:
Client (eg: browser) sends a REQUEST -> Server processes request and sends a RESPONSE -> Client gets and displays and/or processes the response
You have to see these requests and responses as messages. Messages cannot call functions on a server-side language directly 1, but can furnish enough information for them to do so and get a meaningful message back from the server.
So you could have a handler that processes and dispatches these requests, like so:
// ajax_handler.php
switch ($_POST['action']) {
case 'post_comment':
post_comment($_POST['content']);
break;
case '....':
some_function();
break;
default:
output_error('invalid request');
break;
}
Then just have your client post requests to this centralized handler with the correct parameters. Then the handler decides what functions to call on the server side, and finally it sends a response back to the client.
1 Technically there are remote procedure calls (RPCs), but these can get messy.
AJAX requests call a URL (make a HTTP request), not a file, in most cases the URL is translated by the server to point at a file (or a php script in your case), but everything that happens from the HTTP request to the response that is received is up to you (on your server).
There are many PHP frameworks that map URL's to specific php functions, AJAX is just an asynchronous way to access a URL and receive a response.
Said URL CAN trigger the server to call a specific function and send back a response. But it is up to you to structure your URL's and server side code as such.
If you're asking whether you can call any arbitrary PHP function with AJAX the answer is no*, for obvious security reasons (in addition to the technical reasons). You could make a PHP script that does different things depending on what parameter it's given (for example, execute a single function) if you don't want to create multiple separate files.
*Although you could make a script that would execute any arbitrary PHP command coming from the client, but that would be very, very, very unwise.
Short answer is "no" but the real answer is that you can fake it. NullUserException's answer is good. You create a server that will take the function name and its parameters. Then the server executes the function, and returns the value.
This was done a while back via a protocol called XML-RPC. There was also an effort called JSON-RPC that used some JS techniques.
One things that's cool about JS is that you can do things like this:
var base64_decode = create_remote_call('base64_decode');
function create_remote_call(name) {
return function(x) {
jQuery.getJSON('url/server.php',
{func:name,arg:x},
function(d){return d;});
}
}
A call to base64_decode('sarefdsfsaes') will make a ajax request and return the value.
That code probably won't work because it hasn't been tested, but it's a function that produces a function that will call the server, and then return the value. Handling more than one argument requires more work.
All that said... in my experience, it's usually good to make all network communications explicit instead of disguising it as a regular function.
you may achieve the same result using a bridge, like my phery library http://phery-php-ajax.net you can call PHP functions directly from Javascript and deal with the value. The AJAX is bound to DOM elements, so you can manipulate the calling DOM or just use jQuery from the PHP side. An example would be:
Phery::instance()->set(array(
'phpfunction' => function(){
return PheryResponse::factory()->jquery('body')->addClass('whoops');
}
))->process();
and in the javascript side (or HTML)
phery.remote('phpfunction');
the equivalent to the https://stackoverflow.com/a/7016986/647380 from John Kawakami answer, using phery is:
function base64($data){
return !empty($data['encode']) ? base64_encode($data['content']) : base64_decode($data['content']);
}
Phery::instance()->set(array(
'base64' => 'base64'
))->process();
function base64(content, decode, output){
phery.remote('base64', {'content': content, 'encode': decode ? 1 : 0}, {'type':'text'}).done(output);
}
base64('asdf', false, function(data){
console.log(data); // or assign to some variable
});
since AJAX is asynchronous and you can't just return a value from the AJAX call, you need a callback, but this would suffice.
In my previous angularjs project I used interceptors to intercept the http calls, and to be able to serve mock data instead of the real data from the server. I found it very useful throughout the development process.
My question is, how could I do this without angularjs (In my current project I use another framework, which does not have interceptors)?
Is there any other http library out there, that supports this? How could I achive this using jquery's or superagent's http capabilities?
So i found the following script: https://github.com/creotiv/AJAX-calls-intercepter/blob/master/index.html
Here is a live fiddle: http://jsfiddle.net/0eyadb88/1/
I'm not going to go over everything in the script as simply it looks like it does handle the XMLHttpRequest as i commented on. To what extent this works, well that would be just some testing of course and should be able to be expanded.
i've added a non jquery ajax call (testing with chrome here) and it handles that as well.
The main section to pay attention to is
(function (open) {
XMLHttpRequest.prototype.open = function (method, url, async, user, pass) {
alert('Intercept');
open.call(this, method, url + ".ua", async, user, pass);
};
})(XMLHttpRequest.prototype.open);
Personally i would use this approach unless a decent libary is around, but of course if such a libary exists. please do let us know ;)
Otherwise cleaning up the script or using that one in general should be fairly easy.
You should check out dfournier/plasticine. I developed this library in order to intercept a request and fake the response or intercept server response and modify it. I use it at work and the backend team is not ready but we already defined the API.
I am attempting to make multiple http get requests in js. but I'm a total noob. I would not be opposed to jQuery either. The idea is I make a call to my server so I can populate a js chart.
var client;
function handler() {
if(client.readyState == 4 && client.status == 200) {
// make a chart
}
}
window.onload = function() {
client = new XMLHttpRequest();
client.onreadystatechanged = handler;
client.open("GET", "http://someurl/stuff");
client.send();
}
so the above is the basic idea of a web request. It seems that the handler acts a callback or event. this works when creating one get request. but if I make two or more, then I get mixed results. sometimes all requests will work, other times none, or just one. the error that occurs is the connection has not been closed.
The primary issue with this code is that it uses the same global variables (e.g. client) which will just fail for multiple requests as they become clobbered.
(The issue that the order of the handler invocations is undefined due to the asynchronous nature of the requests is only secondary to the lack of re-entrancy of creating/using the XHR object in the given code - there is no way that the handler is guaranteed the correct XHR object when it access the client variable!)
Closures and objects avoid this issue but .. just use jQuery (or whatever library you prefer that provides a nice XHR interface, preferably with Promises).
Since you "would not be opposed to jquery", then use it. Take care to only do work from within the callbacks (or promise handlers) using the returned data they provide - this is because the requests are, well, asynchronous.
I am trying to use knockout and I wonder myself how it works REALLY from a network point of view : where can I see the "calls" from the browser client to the server to retrieve data?
I mean : I used to use Ajax calls to populate forms, tables... => we can see the ajax calls to the server. Same thing when I need to submit a form : I can see the ajax calls.
That means I can debug with Firefbug and see the parameters sent/ the response received, inluding the headers (request/response).
With knocknout, the data in the form are "binding" automatically by the framework ko. So, does someone know how it works really? how the calls are done? is there any way to "see" the data flow?
From a network point of view, nothing changes when using knockout. You'll still need to make AJAX calls to populate your view models, but they're outside the framework, not part of it. This means that you can still put a breakpoint on your AJAX calls and observe the stuff being sent and received.
A major code departure is that your network calls will probably now exist within a knockout viewmodel.
var someVm = function(data) {
var self = this;
self.Id = ko.observable(data.Id);
// ...
self.getItems = function() {
// AJAX call here, now method on a vm
}
}
However, as TJ Crowder points out - the key mechanic of knockout is binding a client side view model to a user interface, either for data population or visibility control in a single page application. Networking is something you'll have to handle, but it's not part of knockout. Most likely, you'll make small changes in your placement of AJAX calls.
It's based on the publish-subscribe pattern.
Whenever something is changed it notifies about it.
Here's some info about it http://msdn.microsoft.com/en-us/magazine/hh201955.aspx
i'm building a app with backbone.js, now i wanna adding a global loading effect when backbone.js is making http request to the server, this is a single page webapp, so there are lots of asynchronous http requests. I think i can modify the Backbone.sync method to make this easy. How can i do this?
Post a sample of code
// let's say there is a function to generate the loading and remove it
// mask.create();
// mask.remove();
var BookList = Backbone.Collection.extend({
model:Book,
url:'/api/list/1',
});
var list = new BookList();
list.bind('reset', function(){
$('.content').html('');
list.each(function(book){
self.addOne(book);
})
});
list.fetch();
It sounds like you're looking to connect your display to the sync for UI feedback. You don't want to muddling concerns though so you don't want the sync itself to care about the presentation. The default sync implementation provides some events (and there's likely more covered in the docs):
Whenever a model or collection begins a sync with the server, a
"request" event is emitted. If the request completes successfully
you'll get a "sync" event, and an "error" event if not.
So you could start with binding to those events, but either way you should stick to some kind of approach where "sync" remains focused on its responsibility.
#MattWhipple is absolutely correct about separation of concerns: you shouldn't mix UI logic to the persistence layer. However that doesn't mean that you shouldn't override the Backbone.sync method, as long as you provide a decoupling mechanism to separate the concerns.
One such mechanism is the mediator pattern, i.e. using a global event bus to publish and consume messages. As it happens, Backbone provides just such a mechanism with the evented global Backbone object. You can override your sync to trigger an event:
Backbone.trigger("request:start");
And listen to it in the UI layer:
Backbone.on("request:start", callback);
In this way neither layer has to know of each other, and you can still achieve the global request handling.
Furthermore, if all you want is to catch all AJAX requests and you don't care whether they originated from Backbone, you can drop one level lower to listen to jQuery's global events and leave Backbone out of it altogether.