Bind observable array using AJAX inside function - javascript

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.

Related

How to call the callback function with class name defined in another javascript file

I was trying to call the callback function with classname, defined in another javascript file, but I was failed to call. I didn't get the mistake I did. Please let me know the mistake I did in below code and Thank you show much for your help.
I have created one central javascript file like below
CentralScript.js
function CentralScript() {
}
CentralScript.prototype.makeRequest = function (className, cbf, dataToSend) {
$.ajax({
url: 'apiurl',
type: 'POST',
dataType: 'json',
data: {
parameters : dataToSend
},
success: function (responseData) {
this.showResponse(className, cbf, responseData);
},
complete: function() {
},
error: function () {
console.log("Error occurred...");
}
});
};
CentralScript.prototype.showResponse = function (className, cbf, data) {
className.cbf(data);
};
and I have created another file like below
SomeFile.js
function SomeFile() {
}
SomeFile.prototype.sayHi = function() {
var obj = new CentralScript();
var dataToSend = {
method: 'someMethod'
};
obj.makeRequest('SomeFile', 'resultToShow', dataToSend);
};
SomeFile.resultToShow = function (data) {
console.log(data);
};
and I have created main.js file like below
main.js
var ProjectName= (function() {
var sfObj;
function init() {
createObjects();
initiateProject();
}
function createObjects() {
sfObj = new SomeFile();
}
function initiateProject() {
sfObj.sayHi();
}
return {
init : init
};
})();
$(ProjectName.init);
I was getting the response when I was making ajax request from SomeFile.js file, but the response was not logging in console.
I am getting 'cbf' as undefined in 'showResponse' function present in CentralScript.js file
CentralScript.prototype.showResponse = function (className, cbf, data) {
className.cbf(data);
};
May I call the callback function like this "className.cbf(data);" present in SomeFile.js
Please let me know the mistake I did and Thank you show much for your help.
The problem has nothing to several files.
This is corrected script:
//CentralScript.js
function CentralScript() {
}
CentralScript.prototype.makeRequest = function (className, cbf, dataToSend) {
var $this = this;//save for further use
$.ajax({
url: 'apiurl',
type: 'POST',
dataType: 'json',
data: {
parameters: dataToSend
},
success: function (responseData) {
//cbf(responseData);//cbf is SomeFile.resultToShow
$this.showResponse(className, cbf, responseData);//this is $.ajax here
},
complete: function () {
},
error: function () {
console.log("Error occurred...");
}
});
};
CentralScript.prototype.showResponse = function (className, cbf, data) {
//className.cbf(data);//undefined
cbf(data);//cbf is SomeFile.resultToShow
};
//SomeFile.js
function SomeFile() {
}
SomeFile.prototype.sayHi = function () {
var obj = new CentralScript();
var dataToSend = {
method: 'someMethod'
};
//obj.makeRequest('SomeFile', 'resultToShow', dataToSend);
obj.makeRequest(this, this.resultToShow, dataToSend);//this is SomeFile
};
SomeFile.prototype.resultToShow = function (data) {//need .prototype to add function to SomeFile
console.log(JSON.stringify(data));
};

How to combine multiple call to Ajax Data base from different JS files

I have some code on a file that makes Ajax calls. This file is being called as a function by multiple other files that creates a new instance each time.
This is the JS code that is being called:
define(["underscore", "homeop", "domReady!"],
function (_, homeop, domready) {
var timeout = 500;
return function (opUrl, opList, onCallback) {
// IRRELEVANT CODE
var getFetch = function (optionName) {
$.ajax({
url: optionsUrl,
data: { optionNames: [optionName] },
type: "POST",
dataType: "json",
async: false,
traditional: true,
success: function (data) {
_.each(data, function (optionData, optionName) {
if (homeop.globalCache[optionName] === null) {
homeop.globalCache[optionName] = optionData;
}
});
},
error: function (message) {
console.error(message.responseText);
}
});
};
self.getInfo = function (optionName) {
if (homeop.globalCache[optionName] === undefined) {
if (!_.contains(homeop.getOption(), optionName)) {
getFetch(optionName);
}
// MORE IRRELEVANT CODE GOES HERE
In other JS files, I call the get function; for example
var these = new getOptions(optionsUrl, optionsList, onLoadCallback);
var getOpt = these.get(OptionsUrl);
The problem is I am making multiple calls to the get information from the database causing multiple call to my JS file. Each new instance of the JS file will create a ajax call.
Is there a way to wait for all the calls to be done and then get data from the database? In other words how can I somehow combine all the call to my 'getOption.js'?
Thanks
Try this.. You can also implement queue in place of stack
var optionStack = [];
var isAvailable = true;
var getFetch = function (optionName) {
if(isAvailable){
isAvilable = false; // function not available now
}
else {
optionStack.push(optionName)
return;
}
$.ajax({
url: optionsUrl,
data: { optionNames: [optionName] },
type: "POST",
dataType: "json",
async: false,
traditional: true,
success: function (data) {
_.each(data, function (optionData, optionName) {
if (homeop.globalCache[optionName] === null) {
homeop.globalCache[optionName] = optionData;
}
});
},
error: function (message) {
console.error(message.responseText);
},
done: function (){
isAvailable = true;
if(optionStack.length > 0){
getFetch(optionStack.pop());
}
}
});
};

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.

knockout.js observableArray is not recognized as a function

I have been using knockout.js for a while now, and haven't encountered this problem before. Usually, when I try to push a new js object to an observableArray, it works without an issue, but for some reason, this time around I'm getting this error:
TypeError: self.Students.push is not a function
Here is a snippet of my code:
window.ApiClient = {
ServiceUrl: "/api/students",
Start: function () {
var viewModel = ApiClient.ViewModel(ngon.ClientViewModel);
ko.applyBindings(viewModel);
viewModel.get();
}
};
ApiClient.ViewModel = function(data) {
var self = this;
ko.mapping.fromJS(data, {}, this);
this.get = function (id) {
if (id == undefined) {
return ApiClient.Service.get(self.PageSize(), self.PageNumber(), function (data) {
self.Students(data);
});
}
}
this.post = function () {
return ApiClient.Service.post(self.DetailedStudent, function (data) {
self.Students.push(data);
});
}
return this;
}
ApiClient.Service = function () {
var _get = function (pageSize, pageNumber, callback) {
sv.shouldShowLoading = false;
var queryParams = String.format("?pageSize={0}&pageNumber={1}", pageSize, pageNumber);
$.ajax(ApiClient.ServiceUrl + queryParams, {
dataType: "json",
type: "get",
success: callback
});
}
var _post = function (student, callback) {
$.ajax(ApiClient.ServiceUrl, {
data: ko.mapping.toJSON(student),
type: "post",
contentType: "application/json; charset-utf-8",
statusCode: {
201 /*Created*/: callback,
400 /*BadRequest*/: function (jqxhr) {
var validationResult = $.parseJSON(jqxhr.responseText);
alert(jqxhr.responseText);
}
}
});
}
return {
get: _get,
post: _post
};
}();
$(document).ready(function () {
ApiClient.Start();
});
My student object is a very simple C# object that has Id, FirstName, LastName. The get() function works without any issues, it's just the callback function from the post() that cannot push the resulting data. Also, the data being returned back from the server looks correct:
{"Id":"rea","FirstName":"asdf","MiddleName":null,"LastName":"rrr"}
I solved this! It's because the initial viewModel, when being instantiated by the page's view model object had 'null' for its Students property.
knockout.js requires non-null values for all fields that are to be auto mapped.

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