Angular using fetched data outside function scope? - javascript

I'm returning a JSON object via a $http.get. I'm able to get the result set, and it's an array, but when I try to access the object outside the fetch() I'm getting undefined. Not sure what I'm missing, in order to do this, any help is appreciated.
Thanks Jimi.
myObject.fetch().then(function(myData) {
$scope.myData = myData;
});
console.log($scope.myData)

Your $scope.myData is undefined until fetch() finishes execution and calls the passed callback function.
in your example, console.log() is being called before the completion of myObject.fetch()
In the following example, it will most probably work (don't do it!)
setTimeout(function(){
console.log($scope.myData)
}, 2000);
I'm not telling you to do it this way, actually its a very bad way. best practice is to use that scope variable within the callback function only, since that where its actually set.

Related

How to understand asynchronous Meteor.call on the client side

I'm working on a Meteor project and want to get the return value of Meteor.call in template helpers on client side. At very first, I just set a variable in the call back function and get the variable's value outside the Meteor.call. I found out the code after Meteor.call doesn't execute at all. Then I searched a bit and use Session, it works. But I don't really understand the reason. Here's my original code and modified code. Can anyone explain a bit for me? Thanks!!
Original wrong code: html
<div id="text-result-main">
<h2>{{title}}</h2>
</div>
js
Template.texts.helpers({
title: function(){
var index = Router.current().params.index;
Meteor.call('getTitle', index,function(error, result){
titles = result;
});
console.log(titles);
return titles;
}});
Collection text.js
Text = new Mongo.Collection("text");
Meteor.methods({
'getTitle': function(myindex){
return Text.findOne({index: myindex}).title;
}});
The working code: js
Template.texts.helpers({
title: function(){
var index = Router.current().params.index;
Meteor.call('getTitle', index,function(error, result){
Session.set("titles",result);
});
console.log(Session.get("titles"));
return Session.get("titles");
}});
Notice that I didn't publish Collection Text to the client at all because it's just so huge. Every time when I refresh the page when running the wrong code, I can't see the content of "title" or see it on the console. But when I set the session, it works. I don't really understand how it works here. Thanks
There is two issues Asynchronicity and Reactivity
This affectation
Meteor.call('getTitle', index,function(error, result){
titles = result;
});
inside the meteor call is executed but in a asynch way. So the return of your helper is immediately called, and return a empty value.
Try it out in the console of your browser.
But then, why your template render correctly with {{title}} when you use a Session Variable ?
It's because the Session is a reactive data source, witch means that every change to it trigger a re-computation of all templates involving this piece of data.
Here is a timeline:
Methods is called
Return empty value
Method is executed, setting variable value
If the Variable is a reactive data source, template is re-computed. ( in your case, the session is a reactive data source. )
To go further
I would use a reactive var in that case, it's very close from a session variable, but the scope is limited to a template.
A good read on Reactive data source: http://richsilv.github.io/meteor/meteor-reactive-data-types/
The problem is the fact that Meteor.call() is asynchronous when paired with a callback.
So when title() starts executing, it does not wait for your Meteor.call() invocation to return a result (or possibly an error). It continues execution. This is called asynchronous execution.
In short, you are trying to log the value for the key titles which doesn't exist in Session (since the state of your asynchronous Meteor call is unknown, at this point of time).
Try moving the console log statement into the callback paired with your Meteor.call() and you can see the result once it has successfully been set in Session.
A workaround to your problem is to make your Meteor.call() synchronous like this:
Template.texts.helpers({
title: function(){
var index = Router.current().params.index;
var result = Meteor.call('getTitle', index); // <--- this is synchronous code now
Session.set("titles",result);
console.log(Session.get("titles"));
return Session.get("titles");
}});
Removing the callback makes Meteor.call() behave synchronously.
If you do not pass a callback on the server, the method invocation
will block until the method is complete. It will eventually return the
return value of the method, or it will throw an exception if the
method threw an exception.
(from http://docs.meteor.com/api/methods.html#Meteor-call)
Why not use something like this:
title: function(){
var index = Router.current().params.index;
var a = Text.findOne({index: myindex}).title;
console.log(a);
return a;
without methods

Backbone: fetch and scope

Think I been staring at this to long but, I'm trying to bring an object outside the scope of the fetch success method when it completes the fetch.
cars.fetch().complete(function(){
newSuggested = cars.models.filter(function (model) {
return _.contains(model.attributes.suggestedTo, storedVin)
});
})
console.log(newSuggested) //undefined
How can I get the newSuggested outside the fetch scope after it successfully fetched?
Unless you have declared newSuggested somewhere above in the code, it is a global variable on the window (this is not the problem, just pointing it out).
The reason it is undefined where you are logging it, is because when that console.log statement is run, the fetch has not completed.
Whatever you are going to do with newSuggested, you need to do it from within the complete callback function.
// declare the variable using var, so it is not global
var newSuggested;
cars.fetch().complete(function(){
newSuggested = cars.models.filter(function (model) {
return _.contains(model.attributes.suggestedTo, storedVin)
});
console.log(newSuggested); // works!
// do something with newSuggested here, hard to tell what you are trying to do.
probablyUpdateViewInSomeWay(newSuggested);
});
// fetch not complete here!
// this is not a scope problem, but an async problem.
// complete callback has not been called yet.
console.log(newSuggested) //undefined, this is expected
Side note: complete is deprecated in jQuery 1.8, so you should use done instead.
Your script is correct, you can even explicitly use window.newSuggested to make the variable global (though is default like this).
You have to move the console.log after "complete" as call order in the execution flow
cars.fetch().complete(function(){
window.newSuggested = cars.models.filter(function (model) {
return _.contains(model.attributes.suggestedTo, storedVin)
});
global_log();
})
function global_log(){console.log(newSuggested);};

How to get value of property in javascript object?

I have an object which has status property. But I can't get the value of this property. Here is my code sample:
console.log("Resource.query()");
console.log(Resource.query());
console.log("Resource.query().status");
console.log(Resource.query().status);
Here is Chrome console:
As you see Resource.query().status returns undefined while Resource.query() returns the object. My question is how can I get the value of status ?
Thanks in advance.
query() is run asynchronously as noted in the tutorial (emphasis added):
$scope.phones = Phone.query();
This is a simple statement that we want to query for all phones. An important thing to notice in the code above is that we don't pass any callback functions when invoking methods of our Phone service. Although it looks as if the result were returned synchronously, that is not the case at all. What is returned synchronously is a "future" — an object, which will be filled with data when the XHR response returns. Because of the data-binding in Angular, we can use this future and bind it to our template. Then, when the data arrives, the view will automatically update.
try this:
Resource.query()[0].status

jQuery function execution order

I am having a problem, or perhaps a lack of understanding, with the jQuery execution order of $.get() function. I want to retrieve some information from a database server to use in the $.ready() function. As you all know, when the get returns, it passes the data to a return handler that does something with the data. In my case I want to assign some values to variables declared inside the ready handler function. But the problem is, the return handler of $.get() does not execute until after ready has exited. I was wondering if (a) am I doing this right/is there a better way or if (b) there was a way around this (that is, force the get return handler to execute immediately or some other fix I'm not aware of). I have a feeling this is some closure thing that I'm not getting about JavaScript.
As per request, I'll post an example of what I mean:
$(function() {
var userID;
$.get(uri, function(returnData) {
var parsedData = JSON.parse(returnData);
userID = parsedData.userID;
});
});
So as you can see, I'm declaring a variable in ready. Then using a get call to the database to retrieve the data needed. Then I parse the JSON that is returned and assign the userID to the variable declared before. I've tested it with a couple alerts. An alert after the get shows userID as undefined but then an alert in get's return handler shows it to be assigned.
$.get() is asynchronous. You have to use a callback to fill your variable and do the computation after the request is complete. Something like:
$(document).ready(function(){
$.get( "yourUrl", function( data, textStatus, jqXHR ) {
var myData = data; // data contains the response content
// perform your processing here...
registerHandlers( myData ); // you can only pass "data" off course...
});
});
// your function to register the handlers as you said you need to.
function registerHandlers( data ) {
// registering handlers...
}
$.get is an ajax request. A in AJAX stand for asynchronous, so script won't wait for this request to finish, but instead will proceed further with your code.
You can either use complete callback or you can use $.ajax and set async to false to perform synchronous request.
The $.get() function executes an async httprequest, so the callback function will be executed whenever this request returns something. You should handle this callback outside of $.ready()
Maybe if you explain exactly what do you want to do, it would be easier to help!
Are you looking for something like:
$(document).ready(function(){
var variable1, variable 2;
$.get('mydata.url', function(data){
variable1 = data.mydata1;
variable2 = data.mydata2;
});
});
If you declare the variables first, then you can set their values within the get call. You can add a function call at the end of the get handler to call a separate function using these values? Without some kind of example, its hard to go into any more detail.
Without seeing the full code, my guess is that you should declare your variable outside $.ready; initialize it in ready for the initial page load; then update it from the get callback handler.
for example
var x = ""; // declaration
$(document).ready(function() { x = "initial value"; });
$.get(...).success(function() { x = "updated from ajax"; });

JSONP function call issue

i set up a webservice thats cross domain and needs to be contacted via json with padding
on a simple jquery codeline like this, i am successfull getting back json data.
$.getJSON("http://server/series/hist?jsonp=?", function(data){
console.log(data);
});
the webservice, will wrap the result in a function, whenever "jsonp" exists within in the url.
for those cases i used a default function name like:
myfunction({"a":1})
jquery helps me out here, and trys to call the function, that isnt existing ("myfunction()"). what i am trying to achieve instead is a simple call of the callback function (see above), to handle the data locally.
can you point me in the right direction?
thank you
I'm not quite sure what your problem actually is, but:
Interpretation 1
Assuming that by "locally" you mean "without using a callback":
That is impossible. JSON-P cannot work synchronously as it depends on the addition of a <script> element (which won't be processed until the current function has finished executing).
Interpretation 2
Assuming that by that isnt existing ("myfunction()") you mean "Your webservice always uses the function name myfunction:
Fix the webservice. jsonp=? means "Randomly generate a function name and pass it as the jsonp parameter.
The webservice must use that parameter to determine the function name used, and not use a fixed value such as myfunction.
Interpretation 3
You don't want to use JSON-P as the input, but to call your anonymous function directly.
You can't. It isn't stored anywhere you can access it. You have to rewrite your code so it isn't passed directly to getJSON:
function myFunction(data){
console.log(data);
}
$.getJSON("http://server/series/hist?jsonp=?", myfunction);
myfunction({"a":1})

Categories