I have seen simple example Ajax source codes in many online tutorials. What I want to know is whether using the source code in the examples are perfectly alright or not?
Is there anything more to be added to the code that goes into a real world application?
What all steps are to be taken to make the application more robust and secure?
Here is a sample source code I got from the web:
function getChats() {
xmlHttp=GetXmlHttpObject();
if (xmlHttp==null) {
return;
}
var url="getchat.php?latest="+latest;
xmlHttp.onreadystatechange=stateChanged;
xmlHttp.open("GET",url,true);
xmlHttp.send(null);
}
function GetXmlHttpObject() {
var xmlHttp=null;
try {
xmlHttp=new XMLHttpRequest();
} catch (e) {
try {
xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
}
}
return xmlHttp;
}
The code you posted is missing one important ingredient: the function stateChanged.
If you don't quite understand the code you posted yourself, then what happens is when the call to getchats.php is complete, a function "stateChanged" is called and that function will be responsible for handling the response. Since the script you're calling and the function itself is prefixed with "gets" then I'm pretty sure the response is something you're going to be interested in.
That aside, there are a number of ways to improve on the code you posted. I'd guess it works by declaring a single "xmlHttp" object and then making that available to every function (because if it doesn't, the stateChanged function has no way of getting the response). This is fine until you run an AJAX request before the last one (or last few) haven't replied yet, which in that case the object reference is overwritten to the latest request each time.
Also, any AJAX code worth its salt provides functionality for sucess and failure (server errors, page not found, etc.) cases so that the appriopiate message can be delivered to the user.
If you just want to use AJAX functionality on your website then I'd point you in the direction of jQuery or a similar framework.
BUT if you actually want to understand the technology and what is happening behind the scenes, I'd continue doing what you're doing and asking specific questions as you try to build a small lightweight AJAX class on your own. This is how I done it, and although I use the jQuery framework today.. I'm still glad I know how it works behind the scenes.
I would use a framework like DOMAssistant which has already done the hard work for you and will be more robust as well as adding extra useful features.
Apart from that, you code looks like it would do the job.
I would honestly recommend using one of the many libraries available for Ajax. I use prototype myself, while others prefer jQuery. I like prototype because it's pretty minimal. The Prototype Ajax tutorial explains it well. It also allows you to handle errors easily.
new Ajax.Request('/some_url',
{
method:'get',
onSuccess: function(transport){
var response = transport.responseText || "no response text";
alert("Success! \n\n" + response);
},
onFailure: function(){ alert('Something went wrong...') }
});
Related
I have the same code (more or less) working fine in Java, but when I write it in javascript, I end up with 404's. I can't figure out what I'm doing wrong and it's driving me crazy!
gapi.client.load('translate', 'v2', function () {
gapi.client.language.languages.list().execute(function (response) {
response.data.forEach(function(language){
console.log(JSON.stringify(language));
});
});
"language":
{"code":404,"message":"Not Found","data":[{"domain":"global","reason":"notFound","message":"Not Found"}],"error":{"code":404,"message":"Not Found","data":[{"domain":"global","reason":"notFound","message":"Not Found"}]}}
I can see in the console the following POST data to https://content.googleapis.com/rpc?key=MY_API_KEY:
[{"jsonrpc":"2.0","id":"gapiRpc","method":"language.languages.list","apiVersion":"v1"}]
Should that say v1?
By contrast, the REST URL is https://www.googleapis.com/language/translate/v2/languages?key=MY_API_KEY (and it's a GET) and it works fine.
You are right that this was a bug in gapi.client.load. This bug has been fixed and you should no longer run into 404s.
Using JQuery.load(), I change the content of my website's mainWindow to allow the user to switch between tabs. For each tab, there is one or multiple scipts that contain functions that are executed once the tab content is loaded.
Obviously when switching to the tab for the first time, the script has to be fetched from the server and interpreted, but this shouldn't happen if the user switches back to the tab later on. So, to put it short:
Load() html
make sure javascript functions exist, otherwise load script and interpret it.
call a a function on the javascript after the DOM is rebuilt.
Step one and two have to be complete before step 3 is performed.
At the moment, I am using nested callbacks to realize this:
function openFirstTab(){
$("#mainWindow").load("firstTab.php", function(){
if(typeof(onloadfFirstTab) != "function"){
jQuery.getScript("assets/js/FirstTab.js", function(){
onloadFirstTab();
});
}
else{
onloadFirstTab();
}
} );
}
but I feel that there should be a better way.
You can't write the code entirely synchronously since you can't load script synchronously after page load ( unless you do a synchronous XHR request and eval the results - not recommended ).
You've got a couple of choices. There are pre-existing dependency management libs like RequireJS which may fit the bill here, or if you just need to load a single file you can do something like this to clean up your code a bit rather than using if/else:
function loadDependencies() {
// For the sake of example, the script adds "superplugin" to the jQuery prototype
return $.getScript( "http://mysite.com/jquery.superplugin.js" );
}
function action() {
// If superplugin hasn't been loaded yet, then load it
$.when( jQuery.fn.superplugin || loadDependencies() ).done(function() {
// Your dependencies are loaded now
});
}
This makes use of jQuery Deferreds/Promises to make the code much nicer.
If you don't want to load the JS more than once and you are going to dynamically load it, then the only way to know whether it's already loaded is to test for some condition that indicates it has already been loaded. The choices I'm aware of are:
The simplest I know of is what you are already doing (check for the existence of a function that is defined in the javascript).
You could also use a property on each tab (using jQuery's .data() that you set to true after you load the script.
You could write the dynamically loaded code so that it knows how to avoid re-initializing itself if it has already been loaded. In that case, you just load it each time, but the successive times don't do anything. Hint, you can't have any statically defined globals and you have to test if it's already been loaded before it runs its own initialization code.
(Haven't tested it yet, so I am not sure if it works, especially since I didn't yet really understand scope in javascript:)
function require(scripts, callback){
var loadCount = 0;
function done(){
loadCount -=1;
if (loadCount==0){
callback();
}
}
for ( var script in scripts){
if (!script.exitsts()){
loadCount +=1;
jQuery.getScript(script.url, done);
}
}
}
This function takes an array of scripts that are required and makes sure all of them are interpreted before it calls the callback().
The "script" class:
function script(url, testFunc){
this.url =url;
this.testFunction = testFunc;
this.exists = function(){
if(typeof(testFunction)=="function"){
return true;
}
else{
return false;
}
}
}
Where the test-function is a function that is defined (only) in the concerned script.
PS:
To enable caching in JQuery and thus prevent the browser from doing a GET request every time getScript() is called, you can use one of the methods that are presented here.
Even though unnecessary GET - requests are avoided, the script is still getting interpreted every time getScript() is called. This might sometimes be the desired behavior. But in many cases, there is no need to re-interpret library functions. In these cases it makes sense to avoid calling getScript() if the required library functions are already available. (As it is done in this example with script.exists().
i'm trying to lock a row in a db-table when a user is editing the entry.
So there's a field in the table lockthat I set 1 on page load with php.
Then I was trying to unlock the entry (set it 0) when the page is unloaded.
This is my approach. It works fine in IE but not in Firefox, Chrome etc....
The window.onbeforeunload works in all browsers, I tested that.
They just don't do the Request
BUT
if I simple put an alert after req.send(); it works in some browsers but not safari or chrome. So I tried putting something else after it just so that's there's other stuff to do after the request but it doesn't work.
function test() {
var req = new Request({
url: 'inc/ajax/unlock_table.php?unlock_table=regswimmer&unlock_id=',
});
req.send();
alert('bla'); // ONLY WORKS WITH THIS !?!?!?
}
window.onbeforeunload = test;
i've already tried different ways to do the request but nothing seems to work. And the request itself works, just not in this constellation.
ANY help would be appreciated!
Thanks
the request is asynchronous by default. this means it will fork it and not care of the complete, which may or may not come (have time to finish). by placing the alert there you ensure that there is sufficient time for the request to complete.
basically, you may be better off trying one of these things:
add async: false to the request object options. this will ensure the request's completion before moving away.
use an image instead like a tracking pixel.
move over to method: "get" which is a bit faster as it does not contain extra headers and cookie info, may complete better (revert to this if async is delayed too much)
you can do the image like so (will also be $_GET)
new Element("img", {
src: "inc/ajax/unlock_table.php?unlock_table=regswimmer&unlock_id=" + someid + "&seed=" + $random(0, 100000),
styles: {
display: "none"
}
}).inject(document.body);
finally, use window.addEvent("beforeunload", test); or you may mess up mootools' internal garbage collection
Even though I've been using mootools for a while now, I haven't really gotten into playing with the natives yet. Currently I'm trying to extend events by adding a custom addEvent method beside the original. I did that using the following code(copied from mootools core)
Native.implement([Element, Window, Document], {
addMyEvent:function(){/* code here */}
}
Now the problem is that I can't seem to figure out, how to properly overwrite the existing fireEvent method in a way that I can still call the orignal method after executing my own logic.
I could probably get the desired results with some ugly hacks but I'd prefer learning the elegant way :)
Update: Tried a couple of ugly hacks. None of them worked. Either I don't understand closures or I'm tweaking the wrong place. I tried saving Element.fireEvent to a temporary variable(with and without using closures), which I would then call from the overwritten fireEvent function(overwritten using Native.implement - the same as above). The result is an endless loop with fireEvent calling itself over and over again.
Update 2:
I followed the execution using firebug and it lead me to Native.genericize, which seems to act as a kind of proxy for the methods of native classes. So instead of referencing the actual fireEvent method, I referenced the proxy and that caused the infinite loop. Google didn't find any useful documentation about this and I'm a little wary about poking around under the hood when I don't completely understand how it works, so any help is much appreciated.
Update 3 - Original problem solved:
As I replied to Dimitar's comment below, I managed to solve the original problem by myself. I was trying to make a method for adding events that destroy themselves after a certain amount of executions. Although the original problem is solved, my question about extending natives remain.
Here's the finished code:
Native.implement([Element, Window, Document], {
addVolatileEvent:function(type,fn,counter,internal){
if(!counter)
counter=1;
var volatileFn=function(){
fn.run(arguments);
counter-=1;
if(counter<1)
{
this.removeEvent(type,volatileFn);
}
}
this.addEvent(type,volatileFn,internal);
}
});
is the name right? That's the best I could come up with my limited vocabulary.
document.id("clicker").addEvents({
"boobies": function() {
console.info("nipple police");
this.store("boobies", (this.retrieve("boobies")) ? this.retrieve("boobies") + 1 : 1);
if (this.retrieve("boobies") == 5)
this.removeEvents("boobies");
},
"click": function() {
// original function can callback boobies "even"
this.fireEvent("boobies");
// do usual stuff.
}
});
adding a simple event handler that counts the number of iterations it has gone through and then self-destroys.
think of events as simple callbacks under a particular key, some of which are bound to particular events that get fired up.
using element storage is always advisable if possible - it allows you to share data on the same element between different scopes w/o complex punctures or global variables.
Natives should not be modded like so, just do:
Element.implement({
newMethod: function() {
// this being the element
return this;
}
});
document.id("clicker").newMethod();
unless, of course, you need to define something that applies to window or document as well.
I have an ajax-enabled WCF service that returns a set of JSON objects back to the browser. The service has a simple function that calls a business layer dll. This then returns the objects to the calling method.
Below is the service implementation (minus the Imports statements):
<ServiceContract(Namespace:="")> _
<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)> _
<ServiceBehavior(IncludeExceptionDetailInFaults:=True, MaxItemsInObjectGraph:=5000)> _
Public Class NoteService
<OperationContract()> _
Public Function GetAllInsuredNotes(ByVal insuredID As Integer) As List(Of NoteExport)
Dim allNotes As New List(Of NoteExport)
Using nr As New NoteRepository()
allNotes = nr.GetInsuredNotesForExport(insuredID)
If allNotes Is Nothing Then
Throw New InvalidOperationException("The operation to retrieve notes caused an error.")
End If
End Using
Return allNotes.ToList()
End Function
The Javascript to call my service is as follows:
function exportToExcel(sender, eventArgs) {
var insuredID = $('input[id*=hdnInsuredID]').val();
NoteService.GetAllInsuredNotes(insuredID, OnNoteGetSuccess, OnNoteGetFailure, null);
}
function OnNoteGetSuccess(result) {
var insuredID = $('input[id*=hdnInsuredID]').val();
OutputExcel(insuredID, result);
return true;
}
function OnNoteGetFailure(result) {
alert('There was an error retrieving notes for export. Please contact the help desk for assistance.');
return false;
}
Basically my problem is this. Everything seems to work fine from the server side function standpoint. Every time I call the function client side, the server side code executes and the result is generated. However, the success callback function only gets called periodically. I can invoke the function several times and only have the callback executed once. The problem seems to grow worse the larger the result set returned.
I could understand if it was related to the MaxObjectsInGraph setting, but the problem isn't that the result never comes back if I have a large amount of data. It will come back sometimes every forth or fifth try, sometimes 2 tries in a row, sometimes 1 in ten tries. It seems very random.
I have spent at least 2 days racking my brain on this one and can't seem to discover the solution. Does anyone have any insight on this?
Ok, I figured out what was happening and thought I'd post it here in case anyone else experiences this kind of issue. Using fiddler was the tool that put me on the right track.
Basically, the link button I was using to make the call to the javascript function was calling a full page postback, not just calling the javascript function. So if the request was small enough, the response to the web service call came quickly and the web page ran the callback function with the new JSON data it received. As the data sets got larger, sometimes the response would come back in time for the page to process the results. However, sometimes the response wouldn't come back until the full page postback was complete and the reference to the callback function was lost. So it would get back the JSON data but wouldn't know what to do with it.
So I had the javascript function called by the link button always return false to cancel the post back and the problem was solved.
I only had one other issue to deal with and that was setting the MaxObjectsInGraph setting for the service to a high enough value to account for the JSON size coming back. The only thing I still find odd is that if this setting was not high enough, I would get a challenge response box asking for a login name for the first couple of attempts, then the service would just come back with an unknown status code.
In any case, I hope this post proves helpful to someone else.
I don't think we can help you figure it out either unless we have the JavaScript definition for
NoteService.GetAllInsuredNotes(insuredId, CallBack1, CallBack2, WhatIsThisParam)