jquery function inside class confusing this keyword - javascript

function chat() {
this.waittime = 6000;
this.intUpdate = null;
this.sendChatUpdate = function (msg) {
var Chatmsg = '0';
if (msg > 0) {
Chatmsg = $('#chatmsg');
var m = Chatmsg.val();
Chatmsg.val('');
}
var s = $("#chatnick").val();
var r = $("#chatto").val();
$.ajax({
type: 'POST',
url: 'Chat/ajax/Chat.php',
data: {
S: s,
R: r,
M: m
},
success: function (data) {
this.ProcessChatReturn(data);
},
error: function (data) {
this.ProcessChatReturn(data);
}
});
}
this.getUnreadChat = function (mr) {
var s = $("#chatnick").val();
$.ajax({
type: 'POST',
url: 'Chat/ajax/Chat.php',
data: {
S: s,
UR: 1,
MR: mr
},
success: function (data) {
this.ProcessChatReturn(data);
},
error: function (data) {
this.ProcessChatReturn(data);
}
});
//clearTimeout(intUpdate);
$('#chatbox').show();
}
}
var chat = new chat();
chat.getUnreadChat();
I am getting error "Uncaught TypeError: Object # has no method 'ProcessChatReturn' "
I think it is because if the use of "this" inside of the jquery ajax call. I want to reference my "chat" object but I think due to including it inside the jquery ajax function it is not.
Any suggestions how to reference my chat object in that location?

You cannot do that because this inside the ajax succes callback points to jqXHR object and not to your object context. You can instead cache the object to another variable and use it. There are numerous other ways too.
this.sendChatUpdate = function (msg) {
var Chatmsg = '0';
if (msg > 0) {
Chatmsg = $('#chatmsg');
var m = Chatmsg.val();
Chatmsg.val('');
}
var s = $("#chatnick").val();
var r = $("#chatto").val(), self = this; //Cache this to self.
$.ajax({
type: 'POST',
url: 'Chat/ajax/Chat.php',
data: {
S: s,
R: r,
M: m
},
success: function (data) {
self.ProcessChatReturn(data); //Invoke it with self
},
error: function (data) {
self.ProcessChatReturn(data); //Invoke it with self
}
});
}
You can also make use of context property of ajax settings.
Ex:
$.ajax({
type: 'POST',
url: 'Chat/ajax/Chat.php',
data: {
S: s,
R: r,
M: m
},
context:this, //set the context here
success: function (data) {
this.ProcessChatReturn(data); //Invoke it with this
},
error: function (data) {
this.ProcessChatReturn(data); //Invoke it with this
}
});
There are other ways as well like binding the callback function reference using Ecmascript5 function.bind or $.proxy , but in your case you can avoid those.
Note that a context inside a function refers to the context of the caller, or in other words where the function was invoked from (Except for bound function as mentioned in the last statements). In your case you gave a callback to ajax as your anonymous func reference and it gets invoked from jquery ajax object so by default the context points to that

Related

Bind observable array using AJAX inside function

I'am using Knockout.js. I have a function like this:
function deviceGroupItem(item) {
this.DeviceGroupName = item.DeviceGroupName;
this.groupDevicesVisible = ko.observable(false)
this.groupDevicesArray = ko.observableArray();
this.deviceGroupClick = function () {
if (this.groupDevicesVisible() == false) {
this.groupDevicesVisible(true)
$.ajax({
url: returnServer() + '/api/Mobile/getRoomDevices?accessToken=' + localStorage.getItem('Token'),
type: "GET",
dataType: "json",
success: function (data) {
this.groupDevicesArray()($.map(data, function (item) {
return new roomDeviceItem(item);
}))
},
error: function () {
}
})
} else {
this.groupDevicesVisible(false)
}
}
return this;
}
Problem is, when I'am trying bind:
this.groupDevicesArray = ko.observableArray();
Using:
this.groupDevicesArray()($.map(data, function (item) {
return new roomDeviceItem(item);
}))
I'am receiving error "this.groupDevicesArray is not a function". Honestly, I dont know how to do this in correct way. Do You know how can I achieve that?
The issue is because of you referring observable Array with this inside the function deviceGroupClick which does not exist because this refers to current context .
This technique depends on current closure which is a pseudo variable
that may differ from scope to scope dynamically .
viewModel:
function roomDeviceItem(data) {
this.room = ko.observable(data.room)
}
function deviceGroupItem() {
var self=this; //Assign this to self & use self everywhere
self.groupDevicesArray = ko.observableArray();
self.deviceGroupClick = function () {
$.ajax({
url: '/echo/json/',
type: "GET",
dataType: "json",
success: function (data) {
data = [{
'room': 'One'
}, {
'room': 'Two'
}]
self.groupDevicesArray($.map(data, function (item) {
return new roomDeviceItem(item);
}))
}
});
};
};
ko.applyBindings(new deviceGroupItem());
working sample here
Just in-case if you are looking for solution with this you need to use bind(this) to get reference of outer closure check here
Try
this.groupDevicesArray($.map(data, function (item) {
return new roomDeviceItem(item);
}));
groupDevicesArray is observableArray and $.map returns an array.

Accessing JavaScript variable outside of $.each() function

I'm having trouble passing a variable declared in an $.each() function to Prototype function. I'm receiving the error Uncaught ReferenceError: prices is not defined
Compare.prototype.results = function (answers) {
$.ajax({
type: 'POST',
dataType: 'json',
data: {
answers: answers
},
success: function (data) {
$.each(data, function (index, dataItem) {
var prices = [],
priceData = dataItem.pricing_term,
priceObj = JSON.parse(priceData);
$.each(priceObj, function (term, pricing) {
prices.push(term, pricing);
});
});
Compare.prototype.show(data, prices);
}
});
}
I want to be able to populate the prices variable and pass it to be used with the data that is originally returned from the ajax call. I am new to javascript, if there is a cleaner way to go about writing this please let me know.
It's out of scope
Compare.prototype.results = function (answers) {
$.ajax({
type: 'POST',
dataType: 'json',
data: {
answers: answers
},
success: function (data) {
var prices = [];
$.each(data, function (index, dataItem) {
var priceData = dataItem.pricing_term,
priceObj = JSON.parse(priceData);
$.each(priceObj, function (term, pricing) {
prices.push(term, pricing);
});
});
// same scope
Compare.prototype.show(data, prices);
}
});
}
You have declared your prices array within the scope of the first &.each function. This means you can only access the prices array in that function. You need to declare prices outside of the function, like so:
Compare.prototype.results = function (answers) {
$.ajax({
type: 'POST',
dataType: 'json',
data: {
answers: answers
},
success: function (data) {
var prices = [];
$.each(data, function (index, dataItem) {
var priceData = dataItem.pricing_term;
var priceObj = JSON.parse(priceData);
$.each(priceObj, function (term, pricing) {
prices.push(term, pricing);
});
});
Compare.prototype.show(data, prices);
}
});
}
This way, prices is available in any of the functions that are within the scope of the success function of the AJAX request.

Getting Object does not support this action error on $.post

Here's my javascript method:
function AssignDebtor(e) {
var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
var debtorId = dataItem.Id;
$.post({
url: '#Url.Action("AssignDebtorToUnallocatedReceipt", "Debtor")',
data: new { unallocatedReceiptId : cdcUnallocatedReceiptId, debtorId : debtorId },
success: function (result, textStatus, jqXHR) {
if (result.success) {
var window = $("#LookupDebtorWindow").data("kendoWindow");
window.close();
var grid = $("#UnallocatedReceiptsGrid").data("kendoGrid");
grid.dataSource.read();
}
else {
alert(result.error);
}
},
dataType: 'json'
});
}
At runtime, the debugger stops on the $.post line, and returns this error:
0x800a01bd - JavaScript runtime error: Object doesn't support this
action
debtorId successfully gets its value. Is there perhaps a problem in the way I have constructed the method?
new { unallocatedReceiptId : cdcUnallocatedReceiptId, debtorId : debtorId }
looks like a syntax error, but is none unfortunately. Instead, it throws that exception you get when you try to use an object (which is not even a function at all) as a constructor.
Just omit the new operator.
Also, as #danludwig mentioned, the $.post function has a different signature, you cannot pass in an object as a parameter. Rather switch to $.ajax.
$.post does not allow you to pass in a javascript object, it expects more strongly-typed method parameters. See the jQuery docs and try this instead:
function AssignDebtor(e) {
var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
var debtorId = dataItem.Id;
$.ajax({
type: 'POST',
url: '#Url.Action("AssignDebtorToUnallocatedReceipt", "Debtor")',
data: { unallocatedReceiptId : cdcUnallocatedReceiptId, debtorId : debtorId },
success: function (result, textStatus, jqXHR) {
if (result.success) {
var window = $("#LookupDebtorWindow").data("kendoWindow");
window.close();
var grid = $("#UnallocatedReceiptsGrid").data("kendoGrid");
grid.dataSource.read();
}
else {
alert(result.error);
}
},
dataType: 'json'
});
}
... or if you are partial to $.post, you could do this instead:
function AssignDebtor(e) {
var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
var debtorId = dataItem.Id;
$.post('#Url.Action("AssignDebtorToUnallocatedReceipt", "Debtor")',
{ unallocatedReceiptId : cdcUnallocatedReceiptId, debtorId : debtorId },
function (result, textStatus, jqXHR) {
if (result.success) {
var window = $("#LookupDebtorWindow").data("kendoWindow");
window.close();
var grid = $("#UnallocatedReceiptsGrid").data("kendoGrid");
grid.dataSource.read();
}
else {
alert(result.error);
}
},
'json'
);
}
Note I also took out the new keyword from your parameters object.

JavaScript Scoping - Passing callback to already defined function

The title is a bit weird, don't quite know the best way to explain it in a sentence...
At present there is an object with 3 functions; func, funcSuccess, and funcFailure. func contains a jQuery ajax request, with this.funcSuccess as the success callback, and funcError as the error callback. func is passed a callback for any success values to be passed back to, however this callback needs to be executed in the funcSuccess code.
Here's the code:
var Obj =
{ func: function (callback) {
$.ajax(
{ type: 'POST'
, url: '/func'
, success: this.funcSuccess
, error: this.funcError
}
)
}
, funcSuccess: function (res) {
// THIS IS WHERE CALLBACK IS NEEDED
callback(res.thing)
}
, funcError: function (res) {
debug(res)
}
}
I'm wondering if there's a tidier way to do it rather than having:
var that = this
$.ajax(
{ type: 'POST'
, url: '/func'
, success: function (res) {
that.funcSuccess(res)
}
, error: this.funcError
}
)
Pretty sure I'm missing something obvious, just not quite with it today...
What about storing the callback explicitly in your object, so you don't have to worry about closure scopes:
var Obj =
{ func: function (callback) {
//this.callback = callback;
$.ajax(
{ type: 'POST'
, url: '/func'
, success: $.proxy(this.funcSuccess, this, callback)
, error: $.proxy(this.funcError, this)
}
)
}
, funcSuccess: function (callback, res) {
callback(res.thing)
}
, funcError: function (res) {
debug(res)
}
}
Edit: I forgot to bind the callbacks to this. In JQuery you can do it with $.proxy, see changes above.
Edit: A further tidy (jQuery 1.6 allows for this) with passing the callback as an argument to $.proxy, so no need to attach it to the current object.
You need to pass the callback into the funcSucess, else it won't have access to it. Here by using a closure:
var Obj = {
func: function (callback) {
return $.ajax({
type: 'POST',
url: '/func',
success: this.makeFuncSuccess(callback),
error: this.funcError
});
}, makeFuncSuccess(callback) {
return function funcSuccess (res) {
callback(res.thing);
};
},
funcError: function (res) {
debug(res)
}
};

jQuery's AJAX call to a javascript class method

I'm a newbee about jQuery's workflow and I would like to setup a javascript class that uses an internal method to make an AJAX request. When the request returns with success, the jQuery AJAX callback should invoke a method owned by the class itself. That's the code:
function IXClock()
{
this.m_intervalID = 0;
this.startClock = function ()
{
this.m_intervalID = setInterval(this.tictac, 500);
}
this.stopClock = function ()
{
clearInterval(this.m_intervalID);
}
this.setClockTime = function(p_strTime)
{
$('#clock').html(p_strTime);
}
this.tictac = function ()
{
$.ajax
({
type: 'POST',
url: '/rap/rapClock.php',
complete: function (data)
{
this.setClockTime(data);
}
});
}
}
The class represents a clock, with an internal method (tictac) that requests "what's the time" on the server side.
After the server says the time, the jQuery's AJAX method should invoke the setClockTime method of the IXClock class. The invoke method will update the #clock div item in the html page.
The problem is that the method this.setClockTime() results unknown and the javascript return the "this.setClockTime is not a function" error.
The question is: is there a way to invoka a class method from the jQuery's AJAX callback ?
I think that the problem is that the this in your callback function is different from the this referring to IXClock. Try:
var thisClass = this ;
this.tictac = function ()
{
$.ajax
({
type: 'POST',
url: '/rap/rapClock.php',
complete: function (data)
{
thisClass.setClockTime(data);
}
});
}
Test Case (added to site which already has jQuery loaded):
function uClass () {
this.testFunction = function(input) {
alert(input) ;
}
this.ajaxFunction = function() {
var myClass = this ;
$.ajax({
type: 'POST',
url: '/',
complete: function(data) {
alert(myClass.testFunction) ;
myClass.testFunction(data) ;
this.testFunction(data) ;
}
}) ;
}
}
var k = new uClass() ;
k.ajaxFunction() ;
It happens bacause your callback function leave in global context.
You can choose 2 ways
Use .bind function to bind context to callback function http://www.robertsosinski.com/2009/04/28/binding-scope-in-javascript/
jQuery's AJAX supports transfer some data to callback function. You can write smth like this:
:
this.tictac = function () { $.ajax ({ type: 'POST', context:this, url: '/rap/rapClock.php', complete: function (data) { this.setClockTime(data); } }); }
}
this does not refer to IXClock in your ajax callback. this allways points to the current scope (have a look at this document). You need to do something like this:
this.prototype.tictac = function ()
{
var self = this;
$.ajax
({
type: 'POST',
url: '/rap/rapClock.php',
complete: function (data)
{
self.setClockTime(data);
}
});
}
You can also use jQuery's .proxy()-function for this purpose:
this.prototype.tictac = function ()
{
$.ajax
({
type: 'POST',
url: '/rap/rapClock.php',
complete: $.proxy(function (data) {
this.setClockTime(data);
}, this)
});
}
The this in the result handler is not what you expect it is. (It is not the IXClock instance)
function IXClock()
{
this.m_intervalID = 0;
}
IXClock.prototype = {
startClock: function ()
{
this.m_intervalID = setInterval(this.tictac, 500);
},
stopClock: function ()
{
clearInterval(this.m_intervalID);
},
setClockTime: function(p_strTime)
{
$('#clock').html(p_strTime);
},
tictac: function ()
{
var that = this;
$.ajax({
type: 'POST',
url: '/rap/rapClock.php',
success: function (data) { // You want success here, not complete, IMO
that.setClockTime(data);
}
});
}
}
If you ask me, that ajax call is doing evil. It does not seem to send any data, nor modify any
state on the server, but is expecting/getting/using data from the php, yet is using the POST method.
Should've been
$.get('/rap/rapClock.php', function (data) {
that.setClockTime(data);
});
One simple solution is, to keep your callback function as self = this. This will support inheritance also.
class Record{
get_data(){
self = this;
$.ajax({
type : "GET",
url : "/get_url",
dataType : "json",
contentType: "application/json; charset=utf-8",
data : {},
success : function(data){
console.log(data);
self.load_table(data);
},
});
}
static load_table(data){
console.log(data);
}

Categories