Maintaining the jquery object in ajax post - javascript

I want to maintain the datatable object in ajax call. Please refer below code
$(function(){
function applyDataTables(options) {
//datatable object
var $datatable = $("#table1").dataTable(options);
if (some condition) {
this.dataTableObj = [];
this.dataTableObj.push($datatable);
} else {
$datatable = dataTableObj[0];
}
...............................................
}
})();
first time page load, it will call this function and find some datatable object after that am making some ajax post that time also it will trigger the same function and finding the datatable object.
so, i want to maintain the $datatable object when the page loaded first time, during some ajax posts i want to use this same object for other purpose how can i maintain the $datatable object in ajax post.
if i add that object to "this.dataTableObj" i can able to get the value of old object in ajax post.whether it is correct way of maintaining existing object in javascript.
Thanks,

Well "this" always refers to calling object.
but if you call
applyDataTables(options) //this will be window object;
and it can be overridden using call, apply or bind method
applyDataTables.call(someObj,options) //this will point to someObj
In your function this can be confusing.
Plus if you are passing it to some callback this can be overriden by call or apply method.
So instead of storing datatableObj in this you can store it on some global namespacing whose scope will be on all ajax call.
You may define
var globV={
dataTableObj:[]
};
//you can use different namespacing too instead of globV
$(function(){
function applyDataTables(options) {
//datatable object
var $datatable = $("#table1").dataTable(options);
if (some condition) {
globV.dataTableObj = [];
globV.dataTableObj.push($datatable);
} else {
$datatable = globV.dataTableObj[0];
}
...............................................
}
})();

Related

Is there a way to modify a jQuery object itself?

When using function like .add, .remove, etc. on a jquery object, the jQuery object itself isn't modified, the result get caught by the returned new jQuery object.
Is there a way to modify the object itself?
I'd need that so I can write a function with a jQuery passed by reference, something like this :
function DoThings(refJQuery) {
refJQuery.find(...).remove(...);
if (refJQuery.length > 0) {
DoThings(refJQuery);
}
}
IMPORTANT: this sample of code is just a reminder for purpose/usage of "value passed by reference".
No, jQuery collections are designed as immutable (you could change their properties but you're not supposed to, they're part of the implementation, not the API)
Composition is usually the way to go when you want to pass a immutable object to a function and have it modified (assuming taking a return value isn't feasible).
Normally, you should use a custom object. But you can also devise a generic decorator if you want:
function MutableJQueryObject(jqo){
this.jqo = jqo;
}
['add','find','filter',].forEach(function(k){
MutableJQueryObject.prototype[k] = function(){
this.jqo = $.fn[k].apply(this.jqo, arguments);
}
});
['html','remove'].forEach(function(k){
MutableJQueryObject.prototype[k] = function(){
return this.jqo[k].apply(this.jqo, arguments);
}
});
$.fn.mutable = function(){
return new MutableJQueryObject(this);
}
So you would build a mutable object :
var $e = $('body').mutable();
console.log($e.html()); // html of the body
(function($c){
$c.find('div'); // change the object
})($e);
console.log($e.html()); // html of the div

Why in Javascript the this context changes based on way of calling?

While this issue occurred to me specifically with KnockoutJS, my question is more like a general javascript question.
It is good to understand however that ko.observable() and ko.observableArray() return a method so when assigning a value to them, you need to call the target as method instead of simply assigning a value to them. The code that I'm working with should also support plain objects and arrays, which I why I need to resolve to a method to call to assign a value to the target.
Think of these 2 examples:
Non-working one (this context changed in called method):
// Assigning value to the target object
var target;
// target can be of any of thr following types
target = ko.observableArray(); // knockout observable array (function)
// target = ko.observable(); // knockout observable (function)
// target = {}; // generic object
// target = []; // generic array
//#region resolve method to call
var method;
if (isObservable(target)) {
// if it is a knockout observable array, we need to call the target's push method
// if it is a konckout observable, we need to call the target as a method
method = target.push || target;
} else {
// if target is a generic array, we need to use the array's push prototype
// if target is a generic object, we need to wrap a function to assign the value
method = target.push || function(item){ target = item; };
}
//#endregion
// call resolved method
method(entity);
Working one (this context is fine):
if (isObservable(target)) {
if (target.push) {
target.push(entity);
} else {
target(entity);
};
} else {
if (target.push) {
target.push(entity);
} else {
target = entity;
};
}
Now, to the actual question:
In the first approach, later in the execution chain when using a knockout observable knockout refers to this context within itself, trying to access the observable itself (namely this.t() in case someone is wondering). In this particular case due to the way of callin, this has changed to window object instead of pointing to the original observable.
In the latter case, knockout's this context is just normal.
Can any of you javascript gurus tell me how on earth my way of calling can change the 'this' context of the function being called?
Ok, I know someone wants a fiddle so here goes :)
Method 1 (Uncaught TypeError: Object [object global] has no method 'peek')
Method 2 (Works fine)
P.S. I'm not trying to fix the code, I'm trying to understand why my code changes the this context.
UPDATE:
Thanks for the quick answers! I must say I hate it when I don't know why (and especially how) something is happening. From your answers I fiddled up this quick fiddle to repro the situation and I think I got it now :)
// So having an object like Foo
function Foo() {
this.dirThis = function () {
console.dir(this);
};
};
// Instantiating a new Foo
var foo = new Foo();
// Foo.dirThis() has it's original context
foo.dirThis(); // First log in console (Foo)
// The calling code is in Window context
console.dir(this); // Second log in console (Window)
// Passing a reference to the target function from another context
// changes the target function's context
var anotherFoo = foo.dirThis;
// So, when being called through anotherFoo,
// Window object gets logged
// instead of Foo's original context
anotherFoo(); // 3rd log
// So, to elaborate, if I create a type AnotherFoo
function AnotherFoo(dirThis){
this.dirThis = dirThis;
}
// And and instantiate it
var newFoo = new AnotherFoo(foo.dirThis);
newFoo.dirThis(); // Should dir AnotherFoo (4th in log)
If you're after a way to choose the 'this' that will get used at the time of call,
you should use bind, that's exactly done for that.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
So if SomeObject has a push method, then storing it like this won't work :
var thePushMethod = someObject.push;
since you loose the context of the function when writing this.
Now if you do :
var thePushMethod = someObject.push.bind(someObject);
the context is now stored inside thePushMethod, that you just call with
thePushMethod();
Notice that you can bind also the arguments, so for instance you might write :
var pushOneLater = someObject.push.bind(someObject, 1 );
// then, later :
pushOneLater(); // will push one into someObject
Consider this example,
function Person () {
this.fname = "Welcome";
this.myFunc = function() {
return this.fname;
}
};
var a = new Person();
console.log(a.myFunc());
var b = a.myFunc;
console.log(b());
Output
Welcome
undefined
When you make a call to a.myFunc(), the current object (this) is set as a. So, the first example works fine.
But in the second case, var b = a.myFunc; you are getting only the reference to the function and when you are calling it, you are not invoking on any specific object, so the window object is assigned. Thats why it prints undefined.
To fix this problem, you can explicitly pass the this argument with call function, like this
console.log(b.call(a));
So, for your case, you might have to do this
method.call(target, entity);
Check the fixed fiddle

Referencing Ajax-Loaded Element in JS Object Instance

How do you reference an element that doesn't exist yet from within a JavaScript object instance?
var Dynamic = function(el) {
this.$instance = $(el);
}
var dynamicInstance = new Dynamic('#dynamic');
Since the #dynamic element is loaded via Ajax, the script doesn't see it when dynamicInstance is created and can't reference it.
If it helps solve the issue, I could also reference the element from inside the object without passing it in when it's created -- but am still unclear on how to make the object aware of the element.
If you want to keep things decoupled you can accept a callback function as a parameter and call it once the new element is loaded and appended to the dom
function doAjaxCall(callback) {
$.ajax({
success : function(response) {
//Logic to create the new element based on response
callback();
}
});
}
doAjaxCall(function() {
var dynamic = new Dynamic('#dynamic');
});
In that way you keep everything decoupled while avoiding the race condition created by ajax calls.

call vs passing object in javascript

ive been using call a bit recently in some tutorials I've been following but am more used to passing the object. I was wondering is it best to use call. What's the most efficient way?
var editor = function(someParam){
//do something with this
}
var testFunction function(someParam){
editor.call(this, someParam);
}
or
var editor = function(obj, someParam){
var self = obj;
}
var testFunction function(someParam){
editor(this, someParam);
}
I would stick with passing the object to the function as long as you can structure the function that way.
I see call more like a utility if the function cannot be changed anymore and you really have to inject a different this context.
Also, consider using the prototype approach if your function is bound very close to some object that you want to call the function on.
Also, call will be less performant than passing the object to the function, as the injection of a different this has some overhead.
In some cases call is very useful, for example when adding event handler:
window.addEventListener('load', function(){
var cb = document.getElementById('myCheckBox');
cb.addEventListener('change', onchange);
onchange.call(cb); // sets `cb` as `this` in `onchange` function
});
function onchange(){
// I'm using 'this' for current element
if(this.checked)
alert('checked');
}
In this case onchange will be called on window load and every time checkbox checked state changes

Unable to use "class" methods for callbacks in JavaScript

I'm having a really rough time wrapping my head around prototypes in JavaScript.
Previously I had trouble calling something like this:
o = new MyClass();
setTimeout(o.method, 500);
and I was told I could fix it by using:
setTimeout(function() { o.method(); }, 500);
And this works. I'm now having a different problem, and I thought I could solve it the same way, by just dropping in an anonymous function. My new problem is this:
MyClass.prototype.open = function() {
$.ajax({
/*...*/
success: this.some_callback,
});
}
MyClass.prototype.some_callback(data) {
console.log("received data! " + data);
this.open();
}
I'm finding that within the body of MyClass.prototype.some_callback the this keyword doesn't refer to the instance of MyClass which the method was called on, but rather what appears to be the jQuery ajax request (it's an object that contains an xhr object and all the parameters of my ajax call, among other things).
I have tried doing this:
$.ajax({
/* ... */
success: function() { this.some_callback(); },
});
but I get the error:
Uncaught TypeError: Object #<an Object> has no method 'handle_response'
I'm not sure how to properly do this. I'm new to JavaScript and the concept of prototypes-that-sometimes-sort-of-behave-like-classes-but-usually-don't is really confusing me.
So what is the right way to do this? Am I trying to force JavaScript into a paradigm which it doesn't belong?
Am I trying to force JavaScript into a paradigm which it doesn't belong?
When you're talking about Classes yes.
So what is the right way to do this?
First off, you should learn how what kind of values the this keyword can contain.
Simple function call
myFunc(); - this will refer to the global object (aka window) [1]
Function call as a property of an object (aka method)
obj.method(); - this will refer to obj
Function call along wit the new operator
new MyFunc(); - this will refer to the new instance being created
Now let's see how it applies to your case:
MyClass.prototype.open = function() {
$.ajax({ // <-- an object literal starts here
//...
success: this.some_callback, // <- this will refer to that object
}); // <- object ends here
}
If you want to call some_callback method of the current instance you should save the reference to that instance (to a simple variable).
MyClass.prototype.open = function() {
var self = this; // <- save reference to the current instance of MyClass
$.ajax({
//...
success: function () {
self.some_callback(); // <- use the saved reference
} // to access instance.some_callback
});
}
[1] please note that in the new version (ES 5 Str.) Case 1 will cause this to be the value undefined
[2] There is yet another case where you use call or apply to invoke a function with a given this
Building on #gblazex's response, I use the following variation for methods that serve as both the origin and target of callbacks:
className.prototype.methodName = function(_callback, ...) {
var self = (this.hasOwnProperty('instance_name'))?this.instance_name:this;
if (_callback === true) {
// code to be executed on callback
} else {
// code to set up callback
}
};
on the initial call, "this" refers to the object instance. On the callback, "this" refers to your root document, requiring you to refer to the instance property (instance_name) of the root document.

Categories

Resources