I have a model which is doing a fetch:
fetch: function (options) {
var self = this;
var def = $.Deferred();
P1Comm.get({
'dataType': 'json',
'processAjaxResponse': self.processAjaxResponse,
'onStatusInvalid': function (e) {
P1.log(e, 'status');
},
'onSuccess': function () {
options.success;
def.resolve();
},
'onError': function (e) {
P1.log(e);
def.reject();
},
'sourceURL': P1.API_APPS_ROOT + 'v1.0/accepted-terms'
});
return def.promise();
},
I have recently updated this to have the deferred functionality. However this has now broken my function in the view which sets the fetched data and puts it into the model.
fetchAcceptedTerms: function () {
var self = this;
this.appAcceptedTerms = new T1AppAcceptedTerms();
this.acceptedTerms = new AppAcceptedTerms();
this.acceptedTerms.fetch({
success: function (data) {
if (data.meta.status === 'success') {
self.appAcceptedTerms.set(data.data);
}
}
});
},
Before I changed the structure of the fetch to include deferred this function worked fine.
Can anyone point me in the direction of what I am doing wrong?
Thanks
UPDATE:
The fetch function when it was working (before the deferred) was this:
fetch: function (options) {
var self = this;
return P1Comm.get({
'dataType': 'json',
'processAjaxResponse': self.processAjaxResponse,
'onStatusInvalid': function (e) {
P1.log(e, 'status');
},
'onSuccess': options.success,
'onError': function (e) {
P1.log(e);
},
'sourceURL': P1.API_APPS_ROOT + 'v1.0/accepted-terms'
});
},
It's not clear why you need the extra Deferred here since get and fetch already return Promise objects, but as commenters have already indicated, you're not actually calling the options.success function:
'onSuccess': function () {
options.success;
def.resolve();
}
should be
'onSuccess': function(data) {
options.success(data);
def.resolve();
}
Related
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));
};
I have these ajax calls that need to get called when the previous one is success, meaning once the first ajax is OK, call the 2nd ajax, once the 2nd ajax is OK call the 3rd one, etc so on. I started with a few ajax calls so it was fine to chain them up like this below but now I have about 20 of them and it'd be a mess to chain them up like this.
$.ajax({
url: 'urlThatWorks1',
success: function (data) {
//call someMethod1 with data;
$.ajax({
url: 'urlThatWorks2',
success: function (data) {
//call method2 with data;
//another ajax call ... so on
}
}.... 19 level deep
So I need to make it bit easier to read and maintain so I'm thinking something like
var ajaxArray = [];
var function1 = $.ajax('urlThatWorks1', data I get back from the 'urlThatWorks1' call);
myArray.push(function1);
var function2 = $.ajax('urlThatWorks2', data I get back from the 'urlThatWorks2' call);
myArray.push(function2);
//etc 19 others
myArray.each(index, func){
//Something like $.when(myArray[index].call()).done(... now what?
}
Hope this makes sense, I'm looking for a way of ajax call array from which I can call an ajax call on whose success I call the next ajax in the array. Thanks.
Create a recursive function to be called in sequence as the ajax requests return data.
var urls = [ "url.1", "url.2", ... ];
var funcs = [];
function BeginAjaxCalls()
{
RecursiveAjaxCall(0, {});
}
function RecursiveAjaxCall(url_index)
{
if (url_index >= urls.length)
return;
$.ajax(
{
url: urls[url_index],
success: function(data)
{
funcs[url_index](data);
// or funcs[urls[url_index]](data);
RecursiveAjaxCall(url_index + 1);
}
});
}
funcs[0] = function(data)
// or funcs["url.1"] = function(data)
{
// Do something with data
}
funcs[1] = function(data)
// or funcs["url.2"] = function(data)
{
// Do something else with data
}
Try
$(function () {
// requests settings , `url` , `data` (if any)
var _requests = [{
"url": "/echo/json/",
"data": JSON.stringify([1])
}, {
"url": "/echo/json/",
"data": JSON.stringify([2])
}, {
"url": "/echo/json/",
"data": JSON.stringify([3])
}];
// collect responses
var responses = [];
// requests object ,
// `deferred` object , `queue` object
var requests = new $.Deferred() || $(requests);
// do stuff when all requests "done" , completed
requests.done(function (data) {
console.log(data);
alert(data.length + " requests completed");
$.each(data, function (k, v) {
$("#results").append(v + "\n")
})
});
// make request
var request = function (url, data) {
return $.post(url, {
json: data
}, "json")
};
// handle responses
var response = function (data, textStatus, jqxhr) {
// if request `textStatus` === `success` ,
// do stuff
if (textStatus === "success") {
// do stuff
// at each completed request , response
console.log(data, textStatus);
responses.push([textStatus, data, $.now()]);
// if more requests in queue , dequeue requests
if ($.queue(requests, "ajax").length) {
$.dequeue(requests, "ajax")
} else {
// if no requests in queue , resolve responses array
requests.resolve(responses)
}
};
};
// create queue of request functions
$.each(_requests, function (k, v) {
$.queue(requests, "ajax", function () {
return request(v.url, v.data)
.then(response /* , error */ )
})
})
$.dequeue(requests, "ajax")
});
jsfiddle http://jsfiddle.net/guest271314/6knraLyn/
See jQuery.queue() , jQuery.dequeue()
How about using the Deferred approach. Something like:
var arrayOfAjaxCalls = [ { url: 'https://api.github.com/', success: function() { $("#results").append("<p>1 done</p>"); } },
{ url: 'https://api.github.com/', success: function() { $("#results").append("<p>2 done</p>"); } },
{ url: 'https://api.github.com/', success: function() { $("#results").append("<p>3 done</p>"); } },
{ url: 'https://api.github.com/', success: function() { $("#results").append("<p>4 done</p>"); } },
{ url: 'https://api.github.com/', success: function() { $("#results").append("<p>5 done</p>"); } },
{ url: 'https://api.github.com/', success: function() { $("#results").append("<p>6 done</p>"); } },
{ url: 'https://api.github.com/', success: function() { $("#results").append("<p>7 done</p>"); } },
{ url: 'https://api.github.com/', success: function() { $("#results").append("<p>8 done</p>"); } },
{ url: 'https://api.github.com/', success: function() { $("#results").append("<p>9 done</p>"); } }
];
loopThrough = $.Deferred().resolve();
$.each(arrayOfAjaxCalls, function(i, ajaxParameters) {
loopThrough = loopThrough.then(function() {
return $.ajax(ajaxParameters);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="results"></div>
You could use the async library, which has a bunch of functions like waterfall or series which could solve your problem.
https://github.com/caolan/async#series
https://github.com/caolan/async#waterfall
I have a dojo class like this.
var widget = declare("app.util",null, {
createSecuredLayers: function () {
$.ajax.get({
url: "/Api/GetLayer",
success: function (e) {
},
error: function () {
}
});
}
});
I want to use this object with callback parameters. I mean I want to pass success and error callbacks as parameter.
var util = new app.util();
util.createSecuredLayers({
success:function(){ },
error:function(){ }
});
createSecuredLayers: function(item) {
$.ajax.get({
url: "/Api/GetLayer",
success: item.successCallback,
error: item.errorCallback
});
}
When you call the method, don't forget to pass the response in the success callback.
util.createSecuredLayers({
successCallback: function(resp) {},
errorCallback: function(err) {}
});
You can do it like this:
var widget = declare("app.util",null, {
createSecuredLayers: function (args) {
$.ajax.get({
url: "/Api/GetLayer",
success: args.success,
error: args.error
});
}
});
var util = new app.util();
util.createSecuredLayers({
success:function(){ },
error:function(){ }
});
You should also consider using Dojo's deferred
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.
I have following code:
App.Views.UseCategory = Backbone.View.extend({
template: HandlebarsTemplates['uses/useCategory'],
initialize: function() {
_.bindAll(this, 'render', 'addCategory');
this.render();
},
events: {
'submit #addCategoryForm': 'addCategory'
},
render: function() {
$(this.el).append(this.template(this.options));
return this;
},
addCategory: function(event) {
event.preventDefault();
var self = this;
var useCategoryId = $('select[id=use_category_id]').val();
this.model.set('category_id', parseInt(useCategoryId,10));
this.model.save({ success: console.log('success') });
}
});
Code above works and trigger success callback, so I receive in console "success".
But why when I change that addCategory function to:
addCategory: function(event) {
event.preventDefault();
var self = this;
var useCategoryId = $('select[id=use_category_id]').val();
this.model.set('category_id', parseInt(useCategoryId,10));
console.log('save?');
this.model.save({ success: this.addedCategory, error: function() { console.error(arguments) } });
},
addedCategory: function() {
console.log('success');
}
success callback is not triggered anymore, why?
Edit:
When you do:
this.model.save({ success: console.log('success') });
You already call your console log. What you should do is (not the same):
this.model.save({ success: function() {
console.log('success')
} });
Do you understand the difference or do you need clarifications?
In fact i suspect your success callback is never called.
EDIT:
model.save(data, opts) takes two arguments. You should do:
this.model.save({}, { success: function() {
console.log('success')
} });