JavaScript / jQuery scope - javascript

Hi I'm extending an existing plugin to use static JSON rather than load it from the server. This is a trimmed down version of the extension:
(function ($) {
$.fn.MyExtension = function (options) {
return this.each(function () {
if (opts.load_Json) {
$.get("", function (result) {
fromJson(opts.load_Json)
});
}
var fromJson = function (json) {
// json stuff..
}
});
});
If I remove the $.Get and call fromJson directly without the call back I get an error saying that fromJson is not defined. This must be some form of scope issue but I cant work it out?

This isn't scope. This is timing.
A function isn't assigned to fromJson until the end of the anonymous function you pass to each.
If you call it from your get callback, then that assignment will happen before the HTTP response comes back and the function fires.
If you call it directly, then it just doesn't exist yet.
Either reorder:
return this.each(function () {
var fromJson = function (json) {
// json stuff..
}
if (opts.load_Json) {
$.get("", function (result) {
fromJson(opts.load_Json)
});
}
});
Or use a function declaration (which will be subject to hoisting):
return this.each(function () {
if (opts.load_Json) {
$.get("", function (result) {
fromJson(opts.load_Json)
});
}
function fromJson (json) {
// json stuff..
}
});

Related

$.when().done() is not working

I am facing the some issue with $.when().done() functions with jQuery. Can anyone help please? When I have ajax calls and non-ajax call methods, non-ajax call is calling even I use $.when().done(). See below snippet. Method/function three is running before.
$(document).ready(function () {
Initial();
});
function Initial() {
debugger;
var emp = { Name: "Ram", Age: 10 };
Main(emp);
}
function Main(em) {
$.when(One(em)).done(Two(em)).done(Three(em.Name));
}
function One(et) {
//some ajax call
console.log("One");
}
function Two(et) {
//some ajax call
console.log("Two");
}
function Three(et) {
console.log(et);//not an ajax call
console.log("Three");
}
Edit:
Below is the code snippet after the modifications by Vohuman, which is working like a charm
$(document).ready(function () {
Initial();
});
function Initial() {
debugger;
var emp = { Name: "Ram", Age: 10 };
Main(emp);
}
function Main(em) {
var def1 = $.Deferred();
var def2 = $.Deferred();
One(em, def1);
Two(em, def2);
$.when(def1, def2).done(function () {
Three(em.Name)
});
}
function One(et, defObj) {
//some ajax call
if (defObj) {
defObj.resolve();
}
console.log("One");
}
function Two(et, defObj) {
//some ajax call
if (defObj) {
defObj.resolve();
}
console.log("Two");
}
function Three(et) {
console.log(et);//not an ajax call
console.log("Three");
}
The () is called Invocation Operator. It invokes a function. This means you are calling the function yourself and the returned value of the function is set as the callback and not the function itself.
$.when(One(em)).done(Two).done(Three);
And if you want to have the callback called with parameters you should use a middleware, i.e. another function.
function Main(em) {
$.when(One(em)).done(function() {
Two(em);
}).done(function() {
Three(em.Name);
});
}
Also note that if you want send several ajax requests and have a callback executed when all of them are complete, you can pass several deferred objects to $.when:
$.when(deferredOne, deferredTwo).then(function(resolvedValueOne, resolvedValueTwo) {
});
And as a suggestion, do not use PascalCase names for regular functions. By convention, in JavaScript PascalCase names are used for naming constructors and classes.
another way of doing same is
$.when(One(em), Two(em)).done(function( a1, a2 ) {
Three(em.Name)
});
but One and Two method must return promise object.

Calling a function in another function with AngularJS factory

I have an AngularJS factory that has multiple functions.
I want to call one of the functions inside the other function as shown below:
.factory("AppStart", function($cordovaSQLite) {
return {
init: function() {
var res = "hello";
console.log("in load start up page");
},
create_table: function() {
AppStart.init();
}
}
});
But I get the following error:
AppStart is not defined.
So how do I call the init() function in the create_table() function? I have tried just calling init(), but it doesn't work either.
To accomplish this, I recommend defining your functions with names, and then creating a service object with properties that refer to them, as I did below:
.factory("AppStart", function($cordovaSQLite) {
function init() {
var res = "hello";
console.log("in load start up page");
}
function create_table() {
init();
}
return {
init: init,
create_table: create_table
};
});

Object's function getting called while sending data via AJAX

Sending a plain javascript object with function via AJAX request results in invoking this function.
Why is that happening?
The problem does not occur when sending JSON data.
What is the best way to convert that object to JSON?
I enclose sample code that presents this behaviour.
var A = (function () {
function A(value) {
this.value = value;
}
A.prototype.getValue = function () {
console.log('getValue');
return this.value;
};
return A;
})();
$(document).ready(function () {
var a = new A(10);
var xhr = $.ajax("http://example.com/", {
data: a,
type: 'post',
error: function (data) {
console.log('error');
},
success: function (data) {
console.log('success');
},
crossDomain: true
});
}
Output of the code is:
getValue
success
This is because jQuery.param (used internally by jQuery.ajax) uses the return value of a function when serializing the request parameters. From the docs:
As of jQuery 1.3, the return value of a function is used instead of the function as a String.
Thus, when jQuery.param encounters your a object and sees the getValue property being a function, it calls the function and uses the (serialized) the return value.
Either way, why would you want to pass such a complex object as request data? If you don't want to pass that function along with the request data, you're better off creating a custom serialization function for your A class, such as:
A.prototype.serialize = function() {
return { value: this.value };
}
and use that instead:
var xhr = $.ajax("http://example.com/", {
data: a.serialize(),
// ...
});

How create wrapper for callback?

I use ajaxSubmit.
form.ajaxSubmit(successCallback);
I need create wrapper for successCallback.
How to do this?
I tried
form.ajaxSubmit(wrapperCallBack(successCallback));
var wrapperCallBack = function (successCallback) {
debugger;
changeState(false);
successCallback(this);
};
You're pretty close:
form.ajaxSubmit(wrapperCallBack(successCallback));
var wrapperCallBack = function (successCallback) {
return function() {
changeState(false);
return successCallback(this);
};
};
Or as I would prefer to write it:
form.ajaxSubmit(wrapperCallBack(successCallback));
function wrapperCallBack(successCallback) {
return function() {
changeState(false);
return successCallback(this);
};
}
There, wrapperCallback creates a function to wrap around its argument (the successCallback argument) and returns that function.
Both of those assume you're going to use wrapperCallBack to create wrappers more than once. If you only need a one-off, then you can just use an inline anonymous function:
form.ajaxSubmit(function() {
changeState(false);
return successCallback(this);
});

How do you call other internal methods from inside a javascript closure with backbone.js?

Here is my example object to demonstrate the issue.
Dog = Backbone.Model.extend({
initialize: function () {
},
Speak: function (sayThis) {
console.log(sayThis);
},
CallInternalSpeak: function () {
this.Speak("arf! from internal function.");
},
CallSpeakFromClosure: function () {
this.Speak("arf! fron outside closure.");
var callClosure = function () { // think of this closure like calling jquery .ajax and trying to call .Speak in your success: closure
console.log("we get inside here fine");
this.Speak("say hi fron inside closure."); // THIS DOES NOT WORK
}
callClosure();
}
});
var rover = new Dog;
rover.Speak("arf! from externally called function");
rover.CallInternalSpeak();
rover.CallSpeakFromClosure();
Since you are in Backbone, you can always use Underscore's bind function as well. After you define callClosure, you can wrap it with a proper binding:
callClosure = _.bind(callClosure, this);
The old "self" trick... make a reference to this, call it self, and reference it in the function.
CallSpeakFromClosure: function () {
this.Speak("arf! fron outside closure.");
var self = this;
var callClosure = function () {
console.log("we get inside here fine");
self.Speak("say hi fron inside closure."); // THIS DOES NOT WORK
}
callClosure();
}

Categories