what is 'this' refers to in jquery's $.ajax success? - javascript

Sorry if I have made some mistakes of js terms in my question.
I'm trying to call a method in $.ajax success event which is within the same namespace, here is the demo:
"use strict";
var example = window.example || {};
example.Demo = {
doSomething: function(data) {
console.log(data);
},
main: function() {
$(document).ready(function() {
$.ajax({
url: 'url/to/some/place',
type: 'GET',
async: true,
dataType: "json",
success: function (data) {
this.doSomething(data);
}
});
});
},
};
example.Demo.main()
but it will fail with the following error:
Object # has no method 'doSomething',
seems this can works:
...
main: function() {
var that = this;
...
...
success: function (data) {
that.doSomething(data);
...
but I want to know whether there is any best practice for such case, or this is exactly the proper solution.

it refers the ajax settings by default, you can use the context to pass a custom object
context
This object will be made the context of all Ajax-related callbacks. By
default, the context is an object that represents the ajax settings
used in the call ($.ajaxSettings merged with the settings passed to
$.ajax).
example.Demo = {
doSomething: function (data) {
console.log(data);
},
main: function () {
//don't use dom ready handler here
$.ajax({
url: 'url/to/some/place',
type: 'GET',
//see the use of context
context: this,
async: true,
dataType: "json",
success: function (data) {
this.doSomething(data);
}
});
},
};

In JavaScript this always refers to the “owner” of the function we're executing, or rather, to the object that a function is a method of. When we define our faithful function doSomething() in a page, its owner is the page, or rather, the window object (or global object) of JavaScript. An onclick property, though, is owned by the HTML element it belongs to.
This "ownership" is the result of JavaScript's object oriented approach. See the Objects as associative arrays page for some more information.

Remove $(document).ready(function(){... inside the main , that will solve the problem

Related

TypeError: this.abc is not a function | javascript

Not a fronted or JavaScript so not able to understand why it's not able to find the defined function in the file. I am integrating Apple Pay and I am trying to call the back-end API based on certain event. Here is my code.
ACC.payDirect = {
_autoload: ['payDirect'],
session: null,
payDirect: function () {
let button = $('#mbutton');
if (button.length === 0) {
return;
}
$('#mbutton').on('click', this.onButtonClicked.bind());
},
onButtonClicked: function () {
if (!Session) {
return;
}
var request = getCartPaymentRequest();
this.requestSession("1234"); //getting error while calling this function
session.begin();
},
requestSession: function (validationURL) {
return new Promise(function (resolve, reject) {
$.ajax({
type: 'POST',
url: ACC.config.encodedContextPath + '/checkout/request_session',
data: JSON.stringify({ validationURL: validationURL }),
dataType: 'json',
contentType: 'application/json',
success: resolve,
error: reject
});
});
},
},
function getCartPaymentRequest() {
var result = "";
$.ajax({
type: 'GET',
url: ACC.config.encodedContextPath + '/checkout/payment-request',
dataType: 'json',
async: false,
success: function (response) {
result = response;
},
});
return result;
}
While calling the requestSession I am getting the following error
TypeError: this.requestSession is not a function. (In 'this.requestSession("1234")', 'this.abc' is undefined)
I am sure doing some basic mistake but not able to find out the root cause as why it's not able to find the second function while the first one seems to be working without any issue.
The problem is with the .bind method you called without any parameters.
Take the following example:
const obj2 = {
b: function (callback) {
callback()
}
};
const obj = {
a: function () {
obj2.b(this.c.bind())
},
c: function () {
console.log(this)
}
};
obj.a()
What will happen here is that the Window object will appear in the console.
This happens because the window is somewhat of the global context, and when running in the browser JavaScript's bind's parameter will default to the only context it can: the window.
What you need to do is call the .bind method using the ACC.payDirect as parameter as it will then bind it to the object and use the proper context, you could use a this but if the methodm was called with a different context would cause problems. An even better solution (provided you can use new ES features) is using arrow functions. They are much, much better to work with and won't give you headaches such as this.

this.$emit is not a function within ajax success request [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 1 year ago.
I have the code below:
remove Dog: function(dog) {
self = this;
const updated = this.pets.filter(o => o !== dog);
$.ajax({
type: "PATCH",
url: //irrelevant,
'data': //irrelevant,
'dataType': 'json',
success: function (result) {
self = this;
this.$emit('update:pets', updated);
},
error: function (result) {
}
});
}
I am trying to have an emit command after the success of the ajax request. The ajax works fine so don't worry about that. I am just unable to do the emitting because it says that this.$emit is not a function.
Can anyone help?
this property has access to your scope level properties because it's a function and not an arrow function. So when you access the properties or method which is not in the scope of that function, it returns undefined or not a function.
To fix it, Make your success function as an arrow function of Javascript.
success: (result) => {
this.$emit('update:pets', updated);
},
Another way is to remove the self inside the success method and use the outer self.
success: function (result) {
self.$emit('update:pets', updated);
},

JQuery prototyping functions

I am trying to create a prototype of the ajax object.
I have created these functions:
$.extend({
ajax_prototype : function(parammeters){
instance = this;
instance.cache = false;
instance.crossDomain = false;
instance.dataType = 'json';
instance.timeout = 30000;
instance.error = default_error_function;
$.each(parammeters,function(key,value){
instance[key] = value;
});
},
set_ajax_action : function(template,action,func,def){
template[action] = func;
}
});
ajax_prototype
Is a constructor for the object.
Sets some default settings and some defined based on every need.
set_ajax_action
Sets the function to be executed on each event.
When I create an object like this:
temp1 = new $.ajax_prototype({
'type' : 'post',
'url' : 'controller.php',
});
I get this object:
Object { cache: false, crossDomain: false, dataType: "json", timeout: 30000, error: default_error_function(), type: "post", url: "controller.php", success: function () }
But after I use this:
$.set_ajax_action(temp1,'error',function(){console.log();});
The object becomes like this:
Object { cache: false, crossDomain: false, dataType: "json", timeout: 30000, error: function (), type: "post", url: "controller.php", success: function () }
Basicly their difference is the way error function is set.
Both objects work prety good.
But I would like to make the prototype to create the object with the second form.
Can someone explain me why the difference on the two objects and how to resolve my problem?
Edit 1
I can also create the second object even if I remove the error property from my prototype and call $.set_ajax_action(...) .
My problem is why there is difference to the functions presentation to console.
I know my question is trivial and that either way the result would be the same, but I wan to know how it works.
By the way, even if I set the error property like this:
instance.error = function(){ ... };
The result will be:
Object { cache: false, ifModified: false, processData: true, crossDomain: false, dataType: "json", timeout: 30000, error: .ajax_prototype/instance.error(), url: "test" }
Console is able to trace if a function can be identified somehow. For example, if it has a name or it is assigned to variable, console will show its/variable's name. If it's created inside a function, console will show it. Example:
(function testt(){
$.set_ajax_action(temp1,'error',function(){console.log();});
})()
console.log(temp1)
this code will produce error: testt/<() (firefox).
You can hide name of function, not giving your default handler a name. For example, like this:
(function(default_error_function){
$.extend({
ajax_prototype : function(parammeters){
instance = this;
...
instance.error=default_error_function
...
},
set_ajax_action : ...
});
})(function() {/* default error handler */})
Here, scope of default_error_function symbol is not global, therefore console does not show it. At the same time, handler was created outside any other function, so console only has function () to show.

How can I pass an object in addition to json from my ajax function?

I have the following code:
function submitHandler(dialog) {
dialog.$submits.disableBt();
dialog.$message.addMessage("loading", "<li>Contacting Server, please wait ...</li>");
$.ajax({
url: href,
dataType: 'json',
type: 'POST',
data: dialog.$form.serializeArray()
})
.done(onSubmitDone())
.fail(onSubmitFail());
}
This function has a parameter of dialog which is an object looking like this:
{
$modal: $modal,
$form: $modal.find('.form'),
$message: $modal.find('.message'),
$submits: $modal.find('.submit-button'),
href: $form.attr('data-href')
};
I need to send the dialog object to the onSubmitDone and onSubmitFail functions. Previously I was not using an object
to hold $modal, $form etc and the variables were all available to all functions that were enclosed within an outer function
Two questions:
Is it sensible to pass things around as parts of an object or should I just declare these variables at the top of an outer function.
If I do pass around the object how can I pass it to the following:
function onSubmitDone(json) {
json = json || {};
if (json.Success) {
switch (action) {
I understand that my json object is passed but how can I pass the dialog object also?
One way of passing your dialog argument to the ajax callbacks is to enclose it in the callbacks definition, as showed bellow:
function submitHandler(dialog) {
dialog.$submits.disableBt();
dialog.$message.addMessage("loading", "<li>Contacting Server, please wait ...</li>");
$.ajax({
url: href,
dataType: 'json',
type: 'POST',
data: dialog.$form.serializeArray(),
success: function(data, textStatus, jqXHR) {
onSubmitDone(data, textStatus, jqXHR, dialog);
},
error: function(jqXHR, textStatus, errorThrown) {
onSubmitFail(jqXHR, textStatus, errorThrown, dialog);
}
});
}
I made explicit all callback arguments (data, textStatus, jqXHR, errorThrown), but you don't need to use all of them if you don't want to.
If you pass your object as the context option of $.ajax, it will be available as this inside onSubmitDone and onSubmitFail:
var jsonObj; // do you really need this global?
function submitHandler(dialog) {
jsonObj=dialog.$form.serializeArray();
dialog.$submits.disableBt();
dialog.$message.addMessage("loading", "<li>Contacting Server, please wait ...</li>");
$.ajax({
url: href,
dataType: 'json',
type: 'POST',
data: jsonObj ,
context: dialog
})
// Don't call the handlers from here, no ()!
.done(onSubmitDone)
.fail(onSubmitFail);
}
// Receives the data from the server
function onSubmitDone(response) {
// your object is available as 'this':
console.log(this.$modal);
}
// Different params here, but 'this' is the same
function onSubmitFail(jqXHR, textStatus) { /* ... */ }
Underscore js is a unique and really awesome library for object handling and manipulation
Since you want to pass your object is wise to declare it outside of the functions
Then you can access your object's parts and work with them in your functions' body.
Your code will look like this:
var jsonObj;
function submitHandler(dialog) {
jsonObj=dialog.$form.serializeArray();
dialog.$submits.disableBt();
dialog.$message.addMessage("loading", "<li>Contacting Server, please wait ...</li>");
$.ajax({
url: href,
dataType: 'json',
type: 'POST',
data:jsonObj
})
.done(onSubmitDone(jsonObj))
.fail(onSubmitFail(jsonObj));
}
Regarding your question if it is sensible to pass the object around, while you can, you might find it gets a little burdensome to do so, needing to lug the variable around whenever you need to use it. I would recommended encapsulating your dialog object in the parent scope of your submitHandler() function so it is available to submitHandler, onSubmitDone, etc.
Regarding your second question if you were to pass it around and how you'd get the dialog object to your onSubmitDone function as well, you can always pass the response and your dialog object to your onSubmitDone function like so:
.done(onSubmitDone(response, dialog))

Memory leak when performing setTimeout and Ajax every x seconds

I get new data every x seconds using jQuery Ajax and setTimeout() and it results in a memory leak. The browser memory goes up and up on each Ajax call until the browser crashes.
$(document).ready(wp.state.init);
wp.state = {
data: {},
init: function () {
$.PubSub('state:refresh').subscribe(function () {
window.setTimeout(function () {
wp.state.refresh();
}, 1000);
});
this.refresh();
},
refresh: function () {
$.ajax({
url: 'http://url_here/',
cache: false,
dataType: "json",
success: function (data) {
wp.state.data = data;
$.PubSub('state:refresh').publish();
}
});
}
}
UPDATE (based on #dez answer)
wp.state = {
data: {},
init: function () {
$.PubSub('state:refresh').subscribe(function () {
window.setTimeout(wp.state.refresh, 1000);
});
this.getState();
},
refresh: function () {
wp.state.getState();
},
onSuccess: function (data) {
wp.state.data = data;
$.PubSub('state:refresh').publish();
},
getState: function () {
$.ajax({
url: 'http://url_here/',
cache: false,
dataType: "json",
success: this.onSuccess
});
}
}
Notes:
Publisher/Subscriber ($.PubSub) implementation taken form here. Mem leak occured also before implementing PubSub so its apparently not related.
setTimeout is used instead of setInterval in order to perform the new Ajax call only after the old one was succesfull.
Of course there are other functions that listen to 'state:refresh' and use the data in wp.state.data
I can see a couple of issues here, some of them may be causing your memory leak.
For starters, the first line:
$(document).ready(wp.state.init);
This is not going to execute init in the correct scope and as a result the value of this will be undefined on the line:
this.refresh();
You should do something like this instead:
$(document).ready(function(){wp.state.init();});
or amend your this.refresh() to be explicitly wp.state.refresh().
The bits I think are likely to be causing a leak are...
Every time you make the $.ajax call in refresh you're create a new function to handle the success callback. You should define the callback as another function on your wp.state object instead and pass that in as success in the same manner as you pass wp.state.init to the ready() method currently.
Similarly every time you call window.setTimeout in the function subscribed to your PubSub you're creating a function to handle that callback too. You should do the same here and extract that out into a function on wp.state.

Categories

Resources