Original AJAX code with no JQuery. Note the definition of someVar at the very beginning.
req.onreadystatechange = function() {
if (req.readyState == 4) {
//CODE HERE
var someVar = ....
//method() should be called when AJAX call returns
someVar.method();
if (req.status != 200) {
// error code
someVar.doSomething();
} else if (req.responseText) {
//other code
someVar.doSomethingElse();
}
}
};
req.send(null);
My best attempt at JQuery. Note the code duplication:
$.get(url)
.done(function(data){
var someVar = ....
someVar.method();
someVar.doSomethingElse();
})
.fail(function(){
var someVar = ...
someVar.method();
someVar.doSomething();
});
Is there anyway to run code BEFORE done and fail (which is why always doesnt work in this case)?
Looking at the jqXHR documentation, done, fail, always and then should be invoked in the order they are registered - have you tried putting the shared code in an always before the other functions?
Here's a jsBin showing this in action; just be sure to leave the console open.
EDIT
This is a bit gimmicky, but if you're really deadset on not having a variable in the parent scope, there is some degree of shared context between the functions you can use. A jQuery ajax request is it's own object, and as such you can share data on this object between calls on it.
So, you could share the code like so:
$.get()
.always(function() {
this.someVar = ...
this.someVar.doMethod();
}).done(function() {
this.someVar.doneFunction();
}).fail(function() {
this.someVar.failFunction();
})
If you were to do this though, I'd be a bit more cautious with my variable conventions - probably would try to prefix someVar with something application-specific (like myApp_someVar).
Related
$(function(){
var astronautsData;
$.getJSON('http://api.open-notify.org/astros.json', doSomething);
function doSomething(data) {
astronautsData = data;
}
alert(astronautsData.people[0].name)
});
I would like to be able to use the data in every function I make, that's why I tried to put it in the variable astronautsData, but unfortunately astronautsdata is undefined.
You can access astronautsData inside doSomething.your alert() will get executed
before getJSON. that's why you are getting undefined.
$(function(){
var astronautsData;
$.getJSON('http://api.open-notify.org/astros.json', doSomething);
function doSomething(data) {
astronautsData = data;
alert(astronautsData.people[0].name)
}
});
Here you must understand one thing that getJSON is 'async'. Your alert method trying to show the data which gonna come in future. In order to solve this problem, you must use 'then', 'done' or 'fail' like below.
$(function(){
var astronautsData;
//Assign your getjson request
var jsonRequest = $.getJSON('http://api.open-notify.org/astros.json');
//This function runs once the getJSON method is success
jsonRequest.done(function(data){
astronautsData = data;
});
//This function runs after the success of getJSON
jsonRequest.then(function(){
//Here you have to do your alert ( This alert will give data )
alert(astronautsData);
});
//This alert will give undefined value as this line of code and getjson request runs parallelly
alert(astronautsData);
});
Your .getJSON is asynchronous.
Try using a Promise to wait for your call to be done :
prom = new Promise((resolve, reject) => {
$.getJSON('http://api.open-notify.org/astros.json', function(){
astronautsData = data;
resolve('Ajax done');
});
});
prom.then((successMessage) => {
console.log(successMessage);
alert(astronautsData.people[0].name)
});
Exposing variables in window/global scope is bad in my opinion. You should wrap it in a function (like a class of sorts) and expose it like this:
function Values(type) {
this.value1 = "something";
}
From this point you can use prototype to define additional functions on "Values" like so:
Values.prototype.doStuff = function() {
return this.value1 + ' addsomething';
};
Inside of the prototype function you can define/return promises or do whatever you want including assigning values to the instance. You can also assign the instance to a global variable to make it a singleton of sorts. Granted your still using a global variable for that but its the instance of Values assigned to the variable not the actual values that are stored.
This is a bit of an over simplification perhaps, but in a way this is how the global variables for lodash or jquery work, although they have a LOT more going on to check for existing global variables and such before attempting to define it on global scope as typically you want to avoid that.
you can use var at global scope (outside of all functions) to declare a global variable:
<script>
var astronautsData;
$(function(){
$.getJSON('http://api.open-notify.org/astros.json', doSomething);
function doSomething(data) {
astronautsData = data;
}
alert(astronautsData.people[0].name)
});
</script>
use global.astronautsData if you want it to be global
I have a javascript function that uses an ajax function to post to a php script and a variable used to determine if the result comes back as true or false. In php, I would normally assign the function to a variable such as this:
$insert_item = $process->insert_item($item_array);
If ($insert_item->error)
{
//error detected, do something
}
I have not been able to accomplish this with javascript. Instead, I get a [object object] return if I assign a function to a variable. As a cheap alternative, I am trying to use a global variable to write any errors:
var error = false;
function update_db(formInput) {
$.post(action.php, formInput, function(data) {
if (data != 0) {
error = true
}
});
return error;
}
var updateDb = update_db(form_data);
if (updateDb) {
alert("error detected");
In this example, 'error' comes back as false despite the ajax function updating it to true. I have read all about javascript hoisting, but have yet to find a solution. Is there anyway around this? My problem stems completely from the ajax function which I have also tried accessing directly to return any vars (like I easily do in PHP) but I have had no luck!
As a side note, I find it interesting that I can access 'error' within the ajax function (returns as false) but not able to change it.
For our internal js framework, to ensure good usage of the framework, I want to forbid the usage of Ajax requests in some parts of the framework.
Is there a way to achieve something similar to this:
function doSomething() {
instructions with ajax calls...
withAjaxForbidden(function() {
instructions using ajax calls should raise exception here
});
instructions with ajax calls...
}
Is it possible to implement something like withAjaxForbidden?
Note that obviously I expect the ajax system to be leaved in a consistent state in case an error is thrown.
Just create your own ajax function and make it dependent on some global variable. After that you can just remove the regular ajax functions from the scope and you're done :)
var ajaxEnabled = true;
function withAjaxForbidden(f){
ajaxEnabled = false;
f();
ajaxEnabled = true;
}
function ajax(...){
if(!ajaxEnabled)throw 'Ajax requests are forbidden within this block';
...
}
Here's a fiddle as an example: http://jsfiddle.net/u98b7bk3/1/
<div id="console">
No messages yet
</div>
<script type="text/javascript">
// Disable Ajax globally, to keep it working for your own library make
// sure you save this locally before overwriting
XMLHttpRequest = undefined;
</script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
// Try an ajax request with jQuery
$.ajax('/').always(function(data, status, error){
$('#console').html("data: " + data + "<br>status: " + status + "<br>error: " + error);
});
</script>
Local variables override global variables within the function's scope. Simply create a variable for each native and library ajax function and set it to undefined from within your protected function. It will be prevented from being able to make use of the functions and variables by the same name. As long as they are set using "var" it should only affect the function's scope and not the global scope.
Edit: This may not be exactly what you were looking for, but as far as I know the precise way you want to accomplish this is not possible due to variable scoping but if you don't mind the extra code around your AJAX-restricted code you can use this method. Unlike the other answer this will work asynchronously and does not affect global variables, which makes it much less likely that problems will occur from the use of this code:
Edit 2 (with jQuery support):
var testFunction = (function($){
// Global to local/lexical:
var XMLHttpRequest = undefined;
var eval = undefined;
var setTimeout = undefined;
var setInterval = undefined;
var Function = undefined;
var window = undefined;
$ = (function($){ if($) {
var newjq = function(s, c) {
// Reroute main function
return $(s, c);
};
var jQueryBlacklist = {
// Initialize blacklist
"ajax": true,
"post": true,
"get": true,
"getJSON": true,
"getScript": true
};
for(i in $) // Reconstruct Object
if($.hasOwnProperty(i)
&& !jQueryBlacklist[i])
newjq[i] = $[i];
return newjq;
} }($));
// Real testFunction() below:
return function() {
// AJAX-forbidden code
// $.ajax should be undefined
}
}($));
// $.ajax should work normally here
testFunction(); // not in here
// $.ajax should work normally here
Click here to see the fiddle
For debugging, I'm using Google Chrome. I don't know what I'm doing wrong in my code... all I'm doing is looking for the ready state to change. It's throwing the following error:
TypeError: Property 'onreadystatechange' of object # is not a function
Here's the code:
function startup() {
// For fetching without refresh
// Define new connection
var connect_to = new XMLHttpRequest();
// Open it with the necessary details
connect_to.open('GET', 'light.php?function_id=2');
// Send it
connect_to.send();
// Now, when it comes back, evaluate it for it's ready state and status (readyState equalling 4 and status equalling 200)
connect_to.onreadystatechange(function () {
if (connect_to.readyState == 4 && connect_to.status == 200) {
// Declare where this is going to be put
var plant_into = document.getElementById('intendedContent').innerHTML;
// Put the recieved text into it
plant_into = connect_to.responseText;
}
})
}
It is event so you have to assign function to it, it can have multiple functions attached:
connect_to.onreadystatechange = function (){body};
This () is operator for calling functions, if you put it after something it will try to run function with such name. If you do Foo() then it will try to find Foo and if it will not find it then it will be error. So your usage of ready state changed look like you want to call method passing function to it as a parameter.
I have an interesting question here that may sound pretty silly, but here goes. Using jQuery's ready function I have defined some functions like so:
$(function(){
var function1 = function(data){
//do something
}
var function2 = function(data){
//do something else
}
});
For some reason, in order for IE to render what I am using correctly, it must be done in the $(document).ready() function. However, I need to trigger these functions once I have a dataset from the server-side. So I thought I would do something like this:
Object.Namespace.callFunction = function(data){
function1(data);
}
...to be placed outside the ready function in a script so that I could call it directly.
Unfortunately, I know this doesn't work because well, it does not seem logical and I have tried it!. I made all these functions arbitrary because it does not matter the content, but rather the concept. I have also tried using event handlers to trigger the function once I get that data -- to no avail! What is the best way to make functions inside the $(document).ready() global?
If you are defining global functions there is no reason to have them in the document ready. The only things that should go in the document ready are things that need to wait until the document is ready in order to act. Defining function can happen before the document is ready.
// Defining the functions in the global scope.
var function1 = function(data){
//do something that requires the dom to be ready.
}
var function2 = function(data){
//do something else that requires the dom to be ready.
}
$(function() {
// Running the functions when the document is ready.
function1();
function2();
});
If you (for stylistic reasons) want to write the function inline with your $(document).ready, You can do it this way:
var app={}; /*Use whatever your apps name is, abbreviated (something short)*/
$(function()
{
app.function1 = function(data) { };
app.function2 = function(data) { };
// now you can call all functions inside and outside this ready function with the app. prefix
// if you also want a local reference to the function without the app. prefix, you can do:
var function1 = app.function1 = function(data) { };
});
what about
function function1(data){
//do something
}
function function2(data){
//do something else
}
$(function(){
// if you need to call inside ready
function1();
function2();
});