Using the result of an AJAX call as an AMD module [duplicate] - ajax

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I'm using RequireJS while prototyping an application. I'm "faking" a real database by loading a json file via ajax.
I have several modules that need this json file, which I noticed results in multiple http requests. Since I'm already using RequireJS, I thought to myself "hey, why not load this json file as another module". Since a module can return an object, it seemed reasonable.
So I tried this:
// data.js
define(function(require){
const $ = require('jquery')
var data = {}
$.getJSON('/path/to/data.json', function(json_data){
data = json_data
})
// this does not work because getJSON is async
return data
})
// some_module.js
define(function(require){
const my_data = require('data')
console.log(data) // undefined, but want it to be an object
})
I understand why what I'm doing is not working. I'm not sure what the best way to actually do this would be though.
Things I don't want to do:
Change getJSON to async: false
add a while (data == null) {} before trying to return data
Is there an AMD-y want to accomplish what I'm trying to do? I'm sure there's a better approach here.
Edit
I just tried this. It works, but I'm not sure if this is a good or terrible idea:
// in data.js
return $.getJSON('/path/to/data.json')
// in some_module.js
const my_data = require('data')
my_data.then(function(){
console.log(my_data.responseText)
// do stuff with my_data.responseText
})
My concern is (1) browser support (this is a "promise", right?) and (2) if multiple modules do this at the same time, will it explode.

Because this question is specifically referring to using JQuery, you can actually do this without a native promise using JQuery's deferred.then().
// in data.js
return $.getJSON('/path/to/data.json')
// in some_module.js
const my_data = require('data') // this is a JQuery object
// using JQuery's .then(), not a promise
my_data.then(function(){
console.log(my_data.responseText)
// do stuff with my_data.responseText
})
Based on the description of then() in JQuery's docs, it looks like this is using a promise behind the scenes:
As of jQuery 1.8, the deferred.then() method returns a new promise that can filter the status and values of a deferred through a function, replacing the now-deprecated deferred.pipe() method. [...]
Callbacks are executed in the order they were added. Since deferred.then returns a Promise, other methods of the Promise object can be chained to this one, including additional .then() methods.
Since JQuery's .then() does work in IE, I guess they are polyfilling the promise for IE behind the scenes.

Related

How to manipulate async scope in angularjs

I have this defined in controller
$scope.files = {};
Then I have a ajax call to get data and pass to $scope.files;
In the same controller. I have a ng-click function which I want to manipulate $scope.files
How to do that because it is async. I tried and the $scope.files always return blank {}
$scope.click = function() {
//Do something to $scope.files;
}
My fault. this is not related to async. I can actually get the data.
My problem is the return data is object and I tried to use .length to get the length of object so it always return 0 and {}. And I found .length for array.
and Object.keys(a) for object sizes
Looks like you need to use promise/deferred implementation. Promises allow you to execute code and once the promise is returned then continue.

Making an Ajax request using data from previous ajax request

I am attempting to write an Angular page to communicate with my Nodejs server, but I have ran into a snag.
I need to use multiple Ajax requests that rely on the data from previous ajax requests to work.
So Ajax request #1 provides data that is used by all other Ajax requests, and Ajax request #2 uses data from ajax request #1 to get the data that Ajax request #3 needs.
Since Angular is asynchronous, how can I make my script wait for the data from the first one before making the next ajax call.
id = ajax()
Wait for data
token = ajax(id)
wait for data
gametoken = ajax(id, token)
wait for data
Chandermani is correct, just remember to make sure to make the variables you need available in the scope that you need it.
var id,token,gametoken;
$http.get('http://host.com/first')
.then(function(result){
id=result;
return $http.get('http://host.com/second/'+id);
}
.then(function(result){
token = result
return $http.get('http://host.com/third'+id+'/'+token);
}
.then(function(result){
gametoken = result;
//Do other code here that requires id,token and gametoken
}
EDIT:
You don't have to chain the promises. If you want to make a call at a later date and you want to make sure the promises have resolved you can use $q.all();
var id,token,gametoken;
var p1 = $http.get('http://host.com/first')
.then(function(result){
id=result;
}
// Later on to make your new second call
$q.all([p1]).then(function(){
//Make second call knowing that the first has finished.
}
$q.all() takes an array so you can put in multiple promises if you want and it will wait until they have all resolved.

Make Wordpress Ajax calls work with global variables to reduce database queries

I posted this earlier on wordpress.stackexchange.com. However, never got a reply. Hence, trying my luck here.
I am hereby providing a detailed description of what I need and what I have done for this issue of mine. I am open to any workable solution around what I have done or maybe new suggestions.
I need to make use of user data that is retrieved using the following:
$user_data = get_user_by('login', get_query_var('user_login'));
The above code uses the username passed as a query_var in the URL. All works until here.
I make use of the above code in several Ajax callbacks (handled by admin-ajax.php) on single page load. Since, the site is targeted as a high volume site. All these Ajax requests lead to several database query for the same data. So the obvious idea to save some database queries is to pass the data to a global variable like below:
$_GLOBALS['user_data'] = get_user_by('login', get_query_var('user_login'));
And then use the same in the Ajax callbacks. Here's problem. None of the Ajax callback functions see the global $user_data variable. Before you ask, yes I have declared the global inside callback as well.
So, the obvious answer would be: why not use wp_localize_script and pass the $user_data to the Ajax callback via javascript like bellow:
In PHP:
wp_localize_script('jquery', 'ajaxVars', array( 'ajaxurl' => admin_url('admin-ajax.php'), 'user_data' => $user_data));
In Javascript:
jQuery.ajax({
url: ajaxVars.ajaxurl,
type:'POST',
async: false,
cache: false,
timeout: 10000,
data: 'action=ajax_callback&user_data=' + ajaxVars.user_data,
success: function(value) {
alert(value);
},
error: function() {
alert(error);
}
});
However, this poses two questions:
Can an object that get_user_by('login', get_query_var('user_login')); returns be handled by wp_localize_script()?
If the answer to above question is yes, then would it not pose a security threat since the object would contain sensitive user information?
To overcome the global variable being not available to Ajax callbacks, I declared it directly in functions.php (without wrapping it inside a function). However, get_query_var('user_login') does not return any data when used directly inside functions.php making this futile exercise (You have to add it inside a function and call it via an action).
So, the question remains: how do I stop making $user_data = get_user_by('login', get_query_var('user_login')); calls for every Ajax request? Or is there a way I could get get_query_var('user_login') to work inside functions.php directly (without wrapping it inside a function) or a workaround?
Or maybe some completely new out of the box thinking?
All these Ajax requests lead to several database query for the same
data. So the obvious idea to save some database queries is to pass the
data to a global variable like below:
$_GLOBALS['user_data'] = get_user_by('login', get_query_var('user_login'));
And then use the same in the Ajax callbacks.
Each request that your application receives, AJAX or otherwise, lives completely in isolation: the code handling the requests does not share any state between them (besides whatever is persisted to a database). A global (or constant, or property, or variable, or anything) you define in one request will never be available to subsequent requests unless you store it somewhere.
There are a number of approaches to reducing the number of queries these requests are creating. One would be to retrieve the required user data on page load and pass it to subsequent requests. E.g.:
var user = 'someUser';
$.get('user-data.php?user=' + user, function(user_data) {
$.ajax('some-endpoint.php', {
type: 'POST',
data: { user: user_data },
success: function() { /* ... */ }
});
$.ajax('some-other-endpoint.php', {
type: 'POST',
data: { user: user_data },
success: function() { /* ... */ }
});
});
Alternatively, if it's the currently logged in user you're working with you can write their details to a JavaScript object on initial page load for use later.
var userData = <?php get_currentuserinfo(); echo json_encode($current_user); ?>;
Another option would be to ensure that the get_user_by results were being cached, either by Wordpress, MySQL or some other caching layer. That way it doesn't particularly matter how many times your code calls the method.
In general if lots of your endpoints are sharing functionality, you could probably stand to refactor some of that code.

setCallbackHandler function with multiple inputs

I am sure there is a simple answer to this one, I'm just too new to Ajax to see it.
I am using CF 9 and i am trying to setup the callbackfuntion to take multiple inputs, however, I don't know the default name of the results from the ajax call.
here is what works:
var mySSN = document.getElementById("SSN");
var cfc = new myajax();
cfc.setCallbackHandler(UpdateValidationNotes);
cfc.ValidateSSN(mySSN.value);
And here is what i am trying to do:
var mySSN = document.getElementById("SSN");
var cfc = new myajax();
cfc.setCallbackHandler(UpdateValidationNotes(MyField, AjaxResults);
cfc.ValidateSSN(mySSN.value);
However, i don't know how to reference the ajax results since the callback handler is doing it automagically. Can anyone help out the lose newbie?
Thanks
Give a try like this,
var mySSN = document.getElementById("SSN");
var cfc = new myajax();
cfc.setCallbackHandler(function(AjaxResults) {UpdateValidationNotes(MyField, AjaxResults);});
cfc.ValidateSSN(mySSN.value);
The callback handler function can only take one argument, which will be passed to your handler function automagically. This will be the return value from the CFC that the proxy has deserialized from JSON to a JavaScript representation.(see CFAjaxProxy docmentation)
When you call setCallbackHandler, you just pass the function with no arguments.
It looks like you are trying to determine which field you just validated to possibly display a notice if it doesn't validate. In such cases, what I do is submit the field name to the server and have the server return it back in the response.

in jQuery what is the difference between $.myFunction and $.fn.myFunction?

I'm delving into writing plugins for jQuery and I'm trying to understand the distinction between $.f and $.fn.f
I've seen pluggin authors use both, or sometimes assign $.f = $.fn.f
Can someone explain this to me, reasoning, benefits, etc?
Looking at the jQuery source code will clear things up. By the way, jQuery and $ refer to the same object, and this is how the jQuery object is defined:
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context );
}
jQuery is a function and in Javascript, a function is also an object of the type Function. So jQuery.f or $.f attaches f to the jQuery Function object, or call it the jQuery class if you will.
if you look at jQuery's source, you'll see that jQuery.prototype has been assigned to jQuery.fn
jQuery.fn = jQuery.prototype
So, whenever you attach a method (or property) to jQuery.fn, as in jQuery.fn.f = .., or $.fn.f = .., or jQuery.prototype.f = .., or $.prototype.f = .., that method will be available to all instances of this jQuery class (again, there are no classes in Javascript, but it may help in understanding).
Whenever you invoke the jQuery() function, as in jQuery("#someID"), a new jQuery instance is created on this line:
return new jQuery.fn.init( selector, context );
and this instance has all the methods we attached to the prototype, but not the methods that were attached directly to the Function object.
You will get an exception if you try calling a function that wasn't defined at the right place.
$.doNothing = function() {
// oh noez, i do nuttin
}
// does exactly as advertised, nothing
$.doNothing();
var jQueryEnhancedObjectOnSteroids = $("body");
// Uncaught TypeError: Object #<an Object> has no method 'doNothing'
jQueryEnhancedObjectOnSteroids.doNothing();
Oh, and finally to cut a long thread short and to answer your question - doing $.f = $.fn.f allows you to use the function as a plugin or a utility method (in jquery lingo).
The $.f is a utility function whereas $.fn.f is a jQuery plugin / method.
A utility function is basically a function within the jQuery namespace that is useful for performing some operation, for example, $.isArray(obj) checks if an object obj is an array. It is useful to put functions in the jQuery namespace if you'll use them often and also to avoid global namespace pollution.
jQuery methods on the other hand operate on jQuery objects/wrapped sets. For example, $(document.body).append('<p>Hello</p>'); will append a paragraph containing Hello to the body element of the document. $.fn is a shorthand for $.prototype in later versions of jQuery (it wasn't always in earlier versions of the library). You would use this when writing your own plugins.
The $.fn.f is simply a shortcut to jQuery.prototype
By using the fn, you can add plugin methods without using the extend method:
jQuery.fn.myPlugin = function(opts) { ... }

Resources