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.
Related
In my CodeIgniter 2 controller I call a model method which returns a ReactPHP promise, and I want to load a CodeIgniter view in the function called by that promise's ->then() method. How can I do this? What happens instead is the controller method returns nothing, so I get a blank page in the browser.
Here is a simplified example illustrating what I'm trying to do:
class My_class extends My_Controller {
function my_method() {
$this->my_model->returns_a_promise()->then(function ($data) {
// How can I pass the promise's resolved value to the template here?
// It seems this never gets called, because my_method() returns
// before we get here. :(
$this->load->view('my_view', $data);
});
}
}
Is there any way to tell the controller method not to send output to the browser until after the promise has resolved?
I'm not sure what are you trying to do but if you want to stop view from outputting and return it as a string then output it with echo yourself you can do this:
$view = this->load->view('my_view', $data, TRUE);
Now you have the view as a var string you can use it to do what you are trying to do.
It turns out the code in my original question does work. So the question is the answer. But the reason it wasn't working for me was that returns_a_promise() was not returning a resolved promise, so ->then() was not called and the view was not rendered. In order to make it return a resolved promise, I had to call $deferred->resolve(); in the code that returned the promise.
The upshot of this is that this code example demonstrates it is possible to run asynchronous PHP (via ReactPHP in this case) in CodeIgniter controller methods. My particular use case is to run many database queries concurrently in the CodeIgniter model.
try this:
function my_method() {
$data = array();
$data['promise'] =$this->my_model->returns_a_promise();
$data['view'] = 'my_view';
$this->load->view('my_view', $data);
}
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.
I have a Location collection, and I have back a JSON response from the serve r on fetch including the root title with format:
{'locations':[
{
"id": 1,
"address": 'first address'
},{
"id": 2,
"address": 'second address'
}
]}
I've read everywhere that is best practice to use promise's methods over backbone success and error callbacks but here is the thing. I have override the parse method on the Location collection to return the array, but it appears that using the promises methods the parse method isn't called at all. So for example:
var Locations = new Backbone.Collection.extend({...})
var locations = new Locations()
locations.fetch().then(function(response){
console.log(response)
})
returns an Object literal with property locations which has the value of the Array of locations. But if I use
locations.fetch({
success: function(response){
console.log(response)
}
})
I get the wanted behavior, that is the object with constructor Locations and all the models in it.
Plus if I remove the root title of the JSON response on the backend and remove the parse method override on the collection, with the promise methods I'm getting an object with constructor Array, while with the success callback I'm getting an object with constructor Locations.
So my question is, if it is better to use the promise's methods how to adopt them with the similar behavior as the success and error callbacks?
Requsted update:
Here is the parse function in the Locations collections
var Locations = new Backbone.Collection.extend({
parse: function(response){
return response['locations']
}
})
Use the collection directly:
locations.fetch().then(function(){
console.log(locations);
})
The fetch method returns the jqXHR promise that makes the request, so it returns the raw response received from the server. The promise doesn't know about the parsing of the response.
The reason that passing a success callback as an option to fetch worked for you is: (See Collection.fetch documentation)
The options hash takes success and error callbacks which will both be passed (collection, response, options) as arguments.
So if use pass a success callback to fetch, the first argument is actually collection, not response.
I just have started writing AJAX functions using jquery. Here i am calling myfunction(). where check.php is returning {"count":1} or {"count":0} for which myfunction is always returning retval=false . But for {"count":1} it should return true. I dont know where i am wrong. Below is the code i am using.
function myfunction(){
var retval=false;
if($('#tag').val() != ''){
var query=$( "#tag" ).val();
$.getJSON("check.php",{
q: query
},function(data){
if(data.count==0){
$('#formerrormsg').html('Error msg');
}
else{
retval=true;
}
});
}
return retval;
}
Please Help me to understand this.
That is because, $.getJSON(..) is asynchronous. The below is what jQuery doc says about the third parameter you are passing (function(data){...}):
success(data, textStatus, jqXHR): A callback function that is executed if the request succeeds.
The function which set retval to true is executed when the AJAX call succeeds; not when you call myfunction()
There are two way you could get around this:
Make your AJAX call synchronous; the function wont return until the response is received. (Not a great idea, UI might freeze)
Modify your code -- the asynchronous way. Typically, call the function (that would ideally be depending on the return value) from within the "success-function" defined as the 3rd parameter.
It is an AJAX (asynchronous) request so return retval; is returning before the AJAX success function executes, hence always returns false. You need to change your implementation to wait for that request before returning and using retval.
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.