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);};
Related
Im tryin to access my $rootScope.newBloodneeded but I cant access it outside the function, I tried rootscope so I can call it as global but still it gives me undefined
.controller('editbloodrequestCtrl', function($scope,Bloodrequest,$rootScope,$routeParams) {
$rootScope.newBloodneeded;
Bloodrequest.getBloodrequest($routeParams.id).then(function(data) {
if (data.data.success) {
$scope.newBloodneeded = data.data.bloodrequest.blood_component;
$rootScope.newBloodneeded = $scope.newBloodneeded;
//gives me output when I console here
} else {
app.errorMsg = data.data.message; // Set error message
}
});
console.log($rootScope.newBloodneeded); //gives me undefined
}
Assuming $rootScope is working correctly, this is a problem of asynchronicity NOT scope—when you try to run:
console.log($rootScope.newBloodneeded); //gives me undefined
...getBloodRequest has not necessarily finished. You set the $rootScope.newBloodneeded in the then, which is ONLY run after getBloodRequest resolves, which may be far, far after your console log finishes.
Bloodrequest.getBloodrequest($routeParams.id).then(function(data) {
...
$rootScope.newBloodneeded = $scope.newBloodneeded;
...
One fun test you can try is to wrap that console log in setTimeout for a LONG time (when you are guaranteed/sure that getBloodRequest has finished). That should prove to you that timing is the issue, not one of function scoping.
Basically:
setTimeout(() => console.log($rootScope.newBloodneeded), 10000000000) // or whatever timing guarantees completion
The solution here is to also chain whatever logic that requires $rootScope.newBloodneeded in .then. If THAT doesn't work, you might want to create a Promise that you access from elsewhere. (That's beyond the scope of this question, and we'd need more detail to figure out best implementation).
Where does a returned function go if not stored somewhere? Shouldn't it get appended to the global object/current outer-context?
Here's an example:
var setup = function(){
console.log("xyz");
return function goBack(){
console.log("It's actually abc");
}
}
Now, on calling setup() in the global scope, "xyz" is being shown in the console, but the returning function, i.e goBack is not being appended in the global scope.
setup() //Outputs "xyz"
Now, on trying to call goBack, it's undefined in global scope:
goBack() //error: goBack not defined
Now I could access goBack using setUp()() or by storing the returned function from setup() into a global variable. But, shouldn't I be able to access goBack from the global scope once I execute setup() ? Because if I had stored setup() into a global variable, I would have access to goBack via that variable. But what happens if I don't use a variable to store the returned function from setup()? Where does goBack return to exactly? Thank you.
You're returning a function object, which is the same as any other kind of object, or any other sort of value. If you don't assign it to anything, it simply goes out of scope and will be garbage collected. Nothing happens with it.
I would say that you could not execute the goBackfunction because of the lexical scope : https://stackoverflow.com/a/1047491/1836175 not closures : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures.
If you want to execute your goBackfunction because it is returned by setup() you simply need to store the return of the setup function. Javascript has First-class functions : https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function
So the code to be able to execute the goBack function later would be :
var later = setup()
// do whatever you want and when needed
later() // -> will call the goBack function
Hope that helps to clarify what it is goind on :).
PS : and so yes, if not stored the function will be garbage collected (see deceze response).
If you don't store it in a variable it will be garbage collected when the setup function returns and you can't access it any more. On the other hand you can write your setup function like this:
var setup = function(){
console.log("xyz");
window.goBack = function(){
console.log("It's actually abc");
}
}
and have the goBack function available on the global scope.
then you would access it via window.goBack() or just goBack()
Actually, you are returning an object, which can be stored within a variable and then ran, or, you can also run it directly.
function a(){
console.log("a");
return function b(){
console.log("b");
};
}
console.log("this is calling just a");
a();
console.log("this is calling the a and the returned object");
a()();
Just to add to deceze's answer - adding to global scope is generally a Bad Thing, so the language doesn't do it unless you really want it to.
An example - suppose you have a large application with lots of component bits, and many of those component bits return a function when called. Now you have to make sure every single component uses a different name for their function, otherwise you could end up overwriting someone else's global, which would be bad. And if you're using a javascript library, you need to make sure that you're not using any of the same names as the library, because then you could break their code.
Keeping stuff in scope is super important, and storing stuff in global is a good way to introduce bugs that are really really hard to fix.
I will show the code directly:
disable: function(e){
that = this;
var haha = this;
$.post(url, function(){
console.log(this);// (why ajax object here?
console.log(that);// (I understand this one works
console.log(haha);// ReferenceError
})
}
What I get confused here is:
Why this in callback does not refer to the outside one? I think this in callback follow the default binding role.
Why haha does not refer as that do? I think when haha is not found in local scope, it will go to outer scope.
I know using that is not a good way. That's why I tried haha, but it failed.
I think you are trying to access those values from console... in that case haha will not work as it is local to the function, where as you have created that as a global variable(as there is no var used).
But that is a wrong pattern because some other script could modify the value of that before the ajax request is completed.
The answer to question 1 is: Because you can rebind it willy-nilly in Javascript, and jQuery happens to for jQuery.post(), as the documentation for jQuery.ajax() states:
The this reference within all callbacks is the object in the context option passed to $.ajax in the settings; if context is not specified, this is a reference to the Ajax settings themselves.
Generally: you should probably never rely on a Javascript library to not rebind this. If you need its value in a nested callback, just save it. Either in a different-named variable, or using Function.bind():
$(function() {
var self = this;
$.post("/echo/json/", (function() {
console.log("self", self); // this will be the document itself
console.log("this", this); // as will self
console.log("self === this", self === this); // should output true
}).bind(this));
});
Example on jsFiddle: https://jsfiddle.net/millimoose/Lx2oxobg/. For what it's worth, I strongly prefer using a separate variable for readability, because you can give it a descriptive name, and the fact that this isn't rebound, and that you've effectively reassigned one of the parameters of the callback, isn't hidden all the way after the block for which this holds true.
As for your question 2, I can't reproduce it, see my second fiddle: https://jsfiddle.net/millimoose/zL352rzf/. As others have stated, you're probably not actually getting the ReferenceError from the console.log() itself, given your screenshot.
Try using context option of $.ajax() to set this of success , error callbacks
disable: function(e) {
$.ajax({
context: this
, type:"POST"
, url:url
, success: function() {
console.log(this);
}
, error: function() {
console.log(this)
}
})
}
The callback function runs in a different its own scope hence this refers to it, not where it was defined. you can use bind or apply or call functions to bind it.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
so this refers to something else, but since that is declared in the scope that the function was declared in it still exists there.
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.
I have an object in a javascript. A method in the object is called from outside the object. I want this method to call itself (kind of recursion but not quite) after 200ms untill a condition is fullfilled.
this.setSearchResult = function(data){
if(initiated){
doSetSearchResult(data);
}else{
console.log("Map is not initiated yet. Waiting 200 ms");
setTimeout(function(){setSearchResult(data);}, 200); // <- Error
}
}
Calling setSearchResult is done this way:
mapView = new MapView(imageData);
mapView.setSearchResult(data);
The error I get is ReferenceError: setSearchResult is not defined.
One way to overcome the error is by changing the setTimeout call to this:
setTimeout(function(){mapView.setSearchResult(data);}, 200);
But I find that rather ugly (even though it would probably work in my application).
Is there a proper way of doing it? Do I have to skip using setTimeout in setSearchResult?
I think this should work:
this.setSearchResult = function(data){
if(initiated){
doSetSearchResult(data);
}else{
var _this = this;
console.log("Map is not initiated yet. Waiting 200 ms");
setTimeout(function(){_this.setSearchResult(data);}, 200); // <- Error
}
}
It is because you are in a callback function so you do not have access to the setSearchResult function.
setSearchResult is a method of your MapView object. You therefore have to call it as such. Inside the method itself, you can use the keyword this to reference the object the method belongs to.
Using this.setSearchResult would work if you would use it directly inside your method. But using it inside your setTimeout callback function, it would reference the window object, because setTimeout is a method of window. To work around this, store this in another variable and use it to point to the right object.
// Store this in a variable called self
var self = this;
setTimeout(function() {
// Inside this function "this" points to window, because setTimeout
// is a method of window. Use the previously declared self instead.
self.setSearchResult(data);
}, 200);