How to use q.js to chain backbone model? - javascript

I have the following:
var q = new app.models.OverwriteLineItemsProcess();
q.set('id', $("#process_id").val());
q.saveSource($("#source_quote").val());
q.lockSource();
saveSource is sending data to the backend using ajax. So is lockSource.
I want to execute in this SEQUENTIAL manner: saveSource >> lockSource.
How do I write the q.js to make it work?
By q.js, I mean https://github.com/kriskowal/q
UPDATE: added saveSource and lockSource
saveSource: function (quotation_id) {;
var type = "PUT";
var verb = "Updated";
var headers = {
'X-HTTP-Method-Override': type
};
var url = app.base_url + "/overwrite_line_items/" + this.id;
this.set('source_quote', quotation_id);
var data = this.toFormData();
var result = false;
var currentModel = this;
var settings = {
headers: headers,
type: type,
url: url,
data: data,
success: function(json) {
response = JSON && JSON.parse(json) || $.parseJSON(json);
console.log(response);
currentModel.lockSource();
$("#facebox-source-quote-status").html('<font color="green">SELECTED</font>');
},
error: function(response) {
$("#facebox-source-quote-status").html('<font color="red">UNABLE TO SELECT</font>');
},
dataType: 'json'
};
$.ajax(settings).done(function() {
});
},
lockSource: function () {
var type = "PUT";
var verb = "Updated";
var headers = {
'X-HTTP-Method-Override': type
};
var url = app.base_url + "/quotations/is_editable/" + this.attributes.source_quote;
var data = this.toFormData();
var result = false;
var currentModel = this;
var settings = {
headers: headers,
type: type,
url: url,
data: data,
success: function(response) {
console.log(response);
},
error: function(response) {
$("#facebox-source-quote-status").html('<font color="red">UNABLE TO SELECT</font>');
},
dataType: 'json'
};
$.ajax(settings).done(function() {
});
},

The jQuery.ajax function which you're using already returns a promise for its result. You just need to return that from your functions:
saveSource: function (quotation_id) {;
…
var settings = {
headers: headers,
type: type,
dataType: 'json', // jQuery will automatically parse it for you
url: url,
data: data
};
return $.ajax(settings).done(function() {
// ^^^^^^
$("#facebox-source-quote-status").html('<font color="green">SELECTED</font>');
// notice I did remove the currentModel.lockSource(); call from the callback
}, function() {
$("#facebox-source-quote-status").html('<font color="red">UNABLE TO SELECT</font>');
});
},
lockSource: function () {
…
var settings = // analoguous, no callbacks here
return $.ajax(settings).fail(function(response) {
$("#facebox-source-quote-status").html('<font color="red">UNABLE TO SELECT</font>');
});
}
Now you can easily chain them:
var q = new app.models.OverwriteLineItemsProcess();
q.set('id', $("#process_id").val());
q.saveSource($("#source_quote").val()).then(function(saveResponse) {
console.log(saveResponse);
return q.lockSource();
}).done(function(lockResponse) {
console.log(lockResponse);
});
You don't even need Q for that. If you want to use it, wrap the $.ajax() calls in a Q() invocation, as explained in the Converting JQuery Promises to Q section of the docs.

Related

Returning the correct promise in angular

I'm having trouble returning the correct promise for a service in angular.
this is my function:
postToSP.post($scope.sharePointURL, data).then(function() {
$scope.gettingData = false;
$scope.yammerListName = "Successfully posted to SP";
}).catch(function(e){
//console.log("Error: ", e);
$scope.yammerListName = "Sorry we couldn't post to that page, please make sure your column names are EXACTLY the same!"
$scope.gettingData = false;
throw e;
});
And this is my service, i get the error: "Unable to get property 'then' of undefined or null reference". I know it's because i'm not returning the promise properly but I can't figure out how to do it correctly. Please help, thanks in advance.
app.service("postToSP", function($http) {
//Submit to SP function
this.post = function(originalurl,data){
console.log(data);
var url = originalurl.split("Lists/")[0];
var listname = originalurl.split("Lists/")[1].split("/")[0];
//if the row is checked send it, if not jump to the next row
//run the function, continue until the end and break
var i = 0;
return letsPost(i);
function letsPost (i) { //i<data.length; i++
if (data[i].checked == false) {
i++;
return letsPost(i);
} else {
var formattedText = document.getElementById("text"+i).innerHTML.toString() ;
var formattedCreated = document.getElementById("created"+i).innerHTML.toString();
var formattedLikes = document.getElementById("likes"+i).innerHTML.toString();
var formattedLinks = document.getElementById("links"+i).innerHTML.toString();
var uploadData = { //change this for input data
'__metadata': { 'type': 'SP.Data.' + listname + 'ListItem' },
'Title': i + "",
'Likes': formattedLikes,
'Post_x0020_Date': formattedCreated,
'Post_x0020_Links' : formattedLinks,
'Post_x0020_Text': formattedText
};
console.log(uploadData);
createListItem(url, listname, uploadData)
.done(function (columnData) {
console.log('Added row' + i);
// if there is more data
if (i < data.length) {
i++;
return letsPost(i);
//add new data and continue the function
} else {
return;
}
})
.fail(function (error) {
console.log(JSON.stringify(error));
alert("Error:" + JSON.stringify(error));
throw error;
});
//Function to get form digest token
function getFormDigest(webUrl) {
return $.ajax({
url: webUrl + "/_api/contextinfo",
method: "POST",
headers: { "Accept": "application/json; odata=verbose" }
});
};
//Function to create the list item
function createListItem(webUrl, listName, itemProperties) {
$.ajax({
url: url + "/_api/web/lists/getbytitle('" + listName + "')/items",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
console.log(data.d.results);
},
error: function (data) {
console.log(data);
}
});
return getFormDigest(webUrl).then(function (data) {
return $.ajax({
url: webUrl + "/_api/web/lists/getbytitle('" + listName + "')/items",
type: "POST",
processData: false,
contentType: "application/json;odata=verbose",
data: JSON.stringify(itemProperties),
headers: {
"Accept": "application/json;odata=verbose",
"X-RequestDigest": data.d.GetContextWebInformation.FormDigestValue
}
});
});
};
};
};
};
});
in your function declare the promise first
this.post = function(originalurl,data){
var deferred = $q.defer();
the data that you want to return use
deferred.resolve(dataToReturn)
and at the end of your function add
return deferred.promise;
From what I understand your code, mistake you are doing is you are returning the promise returned from getFormDigest but also applying then function on it and returning another promise. If you dont return getFormDigest nothing will be returned since its async.
To solve it you can use angular $q library and return and independent promise. Resolve that promise in your then function where you are returning a promise and no need to return getFormDigest so only one promise will be returned and hopefully your problem will be resolved.
In simple way you can achieve it..i hope it make sense
//in your controller
yourService.addData(yourPayload);
.then(function (cou) {
$scope.data = cou.data;
});
//in your service
this.addData = function (data) {
var response = $http({
method: "POST",
url: 'your url',
data: data,
dataType: "json"
});
return response;
}

Working with two URLs in ajax

I have to get values from two different URLs and then to merge it. I know it would much better if i'll get all of the data in one URL, but that's how i've got and i need to work with it.
I want to print out the value of a_value, but it's been printed out while b hasn't returned his value. I've read some articles of how to make the functions synchronous but still don't know how to implement it into my code, and don't know what is the best solution for my case. I'm pretty new with JavaScript and still need some help and guiding.
function any_function() {
$.ajax(
{
url : '/url1',
type: "GET",
success:function(data, textStatus, jqXHR)
{
$("#print").html(a(data));
}
});
}
function a(data){
x = 'any value' //`do something with data and insert to this variable`
a_value = x + b(`some id that extracted from data`)
return a_value
}
function b(id){
$.ajax({
url: '/url2',
type: 'GET',
success: function (data, textStatus, jqXHR) {
b_value = c(data, id)
}
});
return b_value
}
function c(data, id){
//do something with `data` and return the value
return c_value
}
function f() {
var request1 = $.ajax({
url : '/url1',
type: 'GET'
});
var request2 = $.ajax({
url: '/url2',
type: 'GET'
});
$.when(request1, request2).done(function(result1, result2){
data1 = result1[0]
data2 = result2[0]
// r1 and r2 are arrays [ data, statusText, jqXHR ]
// Do stuff here with data1 and data2
// If you want to return use a callback or a promise
})
}
This can be done in a synchronous-looking fashion with promises:
$.get(url1)
.then(function(data1){
return $.get(url2)
})
.then(function(data2){
return $.get(url3);
})
.then(function(data3){
// All done
});
You just need to make the second call in the success handler of the first one:
function any_function() {
$.ajax({
url : '/url1',
type: "GET",
success:function(data, textStatus, jqXHR) {
$("#print").html(a(data));
b("someId");
}
});
}
function a(data){
x = 'any value' //`do something with data and insert to this variable`
a_value = x + b(`some id that extracted from data`)
return a_value;
}
function b(id){
$.ajax({
url: '/url2',
type: 'GET',
success: function (data, textStatus, jqXHR) {
b_value = c(data, id);
return b_value;
}
});
}
function c(data, id){
//do something with `data` and return the value
return c_value
}

How can I make many jQuery ajax calls look pretty?

I'm making many ajax call based web service.
I attached event listeners every dom elements. And every event handlers request ajax call in it.
By the way, my source code getting more dirty and complexity.
I want to reduce boilerplate code and look more simple with ajax calls.
How can I do that effectively?
The sample code looks like this:
button1
button2
button3
button4
$('.button1').on('click', function() {
$.ajax({
url: '/api/1/resource1',
data: {
value1: 'value1',
value2: 'value2'
},
success: function (response) {
$('.some_dom1').html(Handlebars.resource({items:response.items}));
}
});
});
$('.button2').on('click', function() {
$.ajax({
url: '/api/1/resource2',
data: {
value1: 'value1',
value2: 'value2'
},
success: function (response) {
$('.some_dom2').html(Handlebars.resource({items:response.items}));
}
});
});
$('.button3').on('click', function() {
$.ajax({
url: '/api/1/resource3',
data: {
value1: 'value1',
value2: 'value2'
},
success: function (response) {
$('.some_dom3').html(Handlebars.resource({items:response.items}));
}
});
});
$('.button4').on('click', function() {
$.ajax({
url: '/api/1/resource4',
data: {
value1: 'value1',
value2: 'value2'
},
success: function (response) {
$('.some_dom4').html(Handlebars.resource({items:response.items}));
}
});
});
Updated:
Every class name and ajax response handler is not same each other. Example code just shows boilerplate code and complexity. This is not the problem of class name or if else statements.
Make common function like this:
String.prototype.endsWith = function(suffix) {
return this.indexOf(suffix, this.length - suffix.length) !== -1;
};
var doAjax_params_default = {
'url': null,
'requestType': "GET",
'contentType': 'application/x-www-form-urlencoded; charset=UTF-8',
'dataType': 'json',
'data': {},
'beforeSendCallbackFunction': null,
'successCallbackFunction': null,
'completeCallbackFunction': null,
'errorCallBackFunction': null,
};
function doAjax(doAjax_params) {
var url = doAjax_params['url'];
var requestType = doAjax_params['requestType'];
var contentType = doAjax_params['contentType'];
var dataType = doAjax_params['dataType'];
var data = doAjax_params['data'];
var beforeSendCallbackFunction = doAjax_params['beforeSendCallbackFunction'];
var successCallbackFunction = doAjax_params['successCallbackFunction'];
var completeCallbackFunction = doAjax_params['completeCallbackFunction'];
var errorCallBackFunction = doAjax_params['errorCallBackFunction'];
//make sure that url ends with '/'
/*if(!url.endsWith("/")){
url = url + "/";
}*/
$.ajax({
url: url,
crossDomain: true,
type: requestType,
contentType: contentType,
dataType: dataType,
data: data,
beforeSend: function(jqXHR, settings) {
if (typeof beforeSendCallbackFunction === "function") {
beforeSendCallbackFunction();
}
},
success: function(data, textStatus, jqXHR) {
if (typeof successCallbackFunction === "function") {
successCallbackFunction(data);
}
},
error: function(jqXHR, textStatus, errorThrown) {
if (typeof errorCallBackFunction === "function") {
errorCallBackFunction(errorThrown);
}
},
complete: function(jqXHR, textStatus) {
if (typeof completeCallbackFunction === "function") {
completeCallbackFunction();
}
}
});
}
then in your code:
$('.button').on('click', function() {
var params = $.extend({}, doAjax_params_default);
params['url'] = `your url`;
params['data'] = `your data`;
params['successCallbackFunction'] = `your success callback function`
doAjax(params);
});
Use a common class:
button1
button2
button3
button4
add listener to this class:
$('.button').on('click', function() {
//find the index of the element and use it
var btnNumber= $( ".button" ).index(this)+1;
$.ajax({
url: '/api/1/resource'+btnNumber,
data: {
value1: 'value1',
value2: 'value2'
},
success: function (response) {
$('.some_dom'+btnNumber).html(Handlebars.resource({items:response.items}));
}
});
});
You can also use any kind of attribute and use it later for any data or parameter
like :
button1
button2
button3
button4
and then use it for any purpose
$('.button').on('click', function() {
var dVal=$(this).attr('abc');
//use dVal any where you want.
alert(dVal);
});
You can follow this change:
button1
button2
button3
button4
Make use of data-* attribute to hold the specific url for each link which is going to be clicked. Now just one change and you would have a common click event for all ajax calls:
$('.button').on('click', function() {
var url = $(this).data('url');
var index = $(this).index();
$.ajax({
url: url,
data: {
value1: 'value1',
value2: 'value2'
},
success: function(response) {
$('.some_dom'+index).html(Handlebars.resource({items: response.items}));
}
});
});
As per your update in your question you can try doing this:
success: function(response) {
if(url.indexOf('1') != -1){
$('.some_dom1').html(Handlebars.resource({items: response.items}));
}else if(url.indexOf('2') != -1){
$('.some_dom2').html(Handlebars.resource({items: response.items}));
}else if(url.indexOf('3') != -1){
$('.some_dom3').html(Handlebars.resource({items: response.items}));
}
}
In success you have to check if the current url of ajax call is having something different to other calls, so if that matches then you can differentiate it within the if/else if conditions.
You can give a common button class to all tags and you can have a single event handler. Then on the basis of other class name you can make calls using different url and data.
button1
button2
button3
button4
var ajaxFunc = function(url, data, successFun){
$.ajax({
url: url,
data:data,
success: successFun
});
}
$('button').on('click', buttonClick);
function buttonClick (){
var elem = $(event.target),
url='', data;
if(elem.hasClass('button1')){
url = '/api/1/resource1';
data = {
value1: 'value1',
value2: 'value2'
}
ajaxFunc(url, data, successFun1);
} else if(elem.hasClass('button2')){
url = '/api/1/resource2';
data = {
value1: 'value1',
value2: 'value2'
}
ajaxFunc(url, data, successFun2)
} else if(elem.hasClass('button3')){
url = '/api/1/resource3';
data = {
value1: 'value1',
value2: 'value2'
}
ajaxFunc(url, data, successFun3)
}
else if(elem.hasClass('button4')){
url = '/api/1/resource4';
data = {
value1: 'value1',
value2: 'value2'
}
ajaxFunc(url, data, successFun4)
}
}
function successFun1(evt){
}
function successFun2(evt){
}
If you are not doing anything different then you can go for only one success function.
The template for anchor tag can be like this
<a data-url="url" data-dataId="dataKey" data-success="functionName" onclick="ajax_call(this);">button</a>
or
button
Then the javascript and jQuery part.
Store all the parameters needed to pass for each request with a key, this key must match the html data attribute.
var myBigJsonObj = {
data1 : { "foo": "bar" },
data2 : { "foo": "bar", "foo1": "bar1"}
};
A user defined success function. Similarly can have error function.
function success() {
// Do some stuff here
alert('Success');
}
Finally the ajax request call.
function ajax_call(obj) {
var url = obj.getAttribute('data-url');
var data = myBigJsonObj[obj.getAttribute('data-dataID')];
var success = obj.getAttribute('data-success');
$.ajax({
url: url,
data: data,
success: window[success].call();
});
}
You can make an async function that contains the ajax API call. Then from everywhere, you can simply call and use the 'then' method for success and error response implementation.
Like here I will give you a very basic example:
// req is JSON type
// SERVICE_URL is global declared service URL or you can pass it as an argument
async function apiCall(req) {
var form_data = new FormData;
for (var key in req) form_data.append(key, req[key]);
let myPromise = new Promise(function (myResolve, myReject) {
$.ajax({
url: SERVICE_URL,
type: 'POST',
data: form_data,
processData: false,
contentType: false,
success: function (result) {
myResolve(result);
},
error: function (error) {
myReject(error);
}
});
});
return await myPromise;
}
Then from everywhere where you are required to use this ajax call use in asynchronous way, like:
// form is the form reference passed from onsubmit method from HTML
// username & password are input fields with 'name' attribute as 'username' & 'password'
function saveForm(form) {
event.preventDefault();
const req = {
username: form.username.value,
password: form.password.value
}
apiCall(req,).then(
function (value) { console.log('async success:', value) },
function (error) { console.log('async error:', error) }
)
}
This is a completely asynchronous implementation and since it's a common function hence is a most cleaner way to do it.

How to send multiple values using ajax to PHP

I'm trying to collect a Facebook user info and then sign them up. How do i include more than one value in ajax?
$.signuser = function () {
FB.api('/me', function (response) {
var str = "";
alert(response.name);
var fbfname = response.first_name;
var fblname = response.last_name;
var fblname = response.id;
var fblink = response.link;
var fbusername = response.username;
var fblink = response.email;
$.ajax({
type: "POST",
data: {
data: fbfname,
fblname
},
complete: function () {
//$('#booksloadjif').css('display','none')
},
url: "fbpost.php"
}).done(function (feedback) {
$('#fg').html(feedback)
});
});
}
You can pass multiple key / value pairs to PHP as an object in $.ajax
$.signuser = function () {
FB.api('/me', function (response) {
var data = { // create object
fbfname : response.first_name,
fblname : response.last_name,
fblname : response.id,
fblink : response.link,
fbusername : response.username,
fblink : response.email
}
$.ajax({
type: "POST",
data: data, // pass as data
url: "fbpost.php"
}).done(function (feedback) {
$('#fg').html(feedback)
}).always(function() {
$('#booksloadjif').css('display','none')
});
});
}
and you'd access them in PHP with
$_POST['fbfname']
$_POST['fblname']
etc, i.e. the keynames in javascript are also the key names for the $_POST array

Want to get an access_token from Twitter Oauth api using oauth.js plugin

I am trying to get a Twitter access token from their oauth api. The plugin I am using is this https://code.google.com/p/oauth/source/browse/#svn%2Fcode%2Fjavascript. So far I only get "401 failed to validate signature and token".
Strange thing is that my ajax call becomes 'GET' request even though I set type:'POST'. Seems like jquery is changing the type from POST to GET. I don't know why it does that. I am running it on my Mac. I appreciate your help/hints/suggestions/advises. Thanks!
$(function() {
function myCallback(resp) {
console.log(resp);
}
var TwitterAPI;
TwitterAPI = (function() {
var consumer_key = null;
var consumer_secret = null;
function TwitterAPI(cons_key, cons_secret) {
this.consumer_key = cons_key;
this.consumer_secret = cons_secret;
}
TwitterAPI.prototype._url = function (data) {
if (typeof data == 'array') {
return array_map([ // TODO
this, '_url'], data);
} else if ((/boolean|number|string/).test(typeof data)) {
return encodeURIComponent(data).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A');
} else {
return '';
}
}
TwitterAPI.prototype.myCallback = function(resp) {
console.log(resp);
}
TwitterAPI.prototype.getRequestToken = function() {
var accessor = {
consumerSecret: this.consumer_secret, //this.consumer.consumerSecret,
tokenSecret: ''
};
var message = {
method: "POST",
action: "https://api.twitter.com/oauth/request_token",
parameters: {
oauth_signature_method: "HMAC-SHA1",
oauth_consumer_key: this.consumer_key, //this.consumer.consumerKey
oauth_callback: this._url("http://127.0.0.1/foobar/libs/oauth/wtf.html"),
}
};
OAuth.setTimestampAndNonce(message);
OAuth.SignatureMethod.sign(message, accessor);
var target = OAuth.addToURL(message.action, message.parameters);
message.parameters.oauth_signature = this._url(message.parameters.oauth_signature);
console.log(message.parameters);
$.ajax("https://api.twitter.com/oauth/request_token",
{ url: "https://api.twitter.com/oauth/request_token",
type: 'POST',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: "myCallback",
data: message.parameters,
success: function(data, textResp, xhr) {
console.log(data);
},
error: function(xhr, text, err) {
console.log(text);
}
});
};
return TwitterAPI;
})();
api = new TwitterAPI(key, secret);
$('button#request').on('click', function(e) {
e.stopPropagation();
api.getRequestToken();
});

Categories