How to make an ajax call asynchronous? - ajax

I was trying to retrieve CRM records using Ajax calls.
function RetrieveCrmRecords(entName, fields, filter, callback, orderby, errcallback) {
///<summary>
/// function to Retrieve Multiple CRM records.
///</summary>
//debugger;
var async = !!callback;
var setEntityName = entName + 'Set';
var _callback = callback;
filter = (filter) ? "&$filter=" + filter : '';
var query1 = CrmServerUrl + ODATA + "/";
var query2 = setEntityName + "()" + "?";
var queryUrl = query1 + query2;
if (fields != null) queryUrl += "$select=" + fields.join(',');
if (orderby != null) {
if (fields != null) {
queryUrl += '&';
}
queryUrl += "$orderby=" + orderby;
}
queryUrl += filter;
var performRequest = function (queryUrl, fnCallback) {
var async = !!fnCallback;
var opts = { url: queryUrl }
return _makeRequest(opts, async, function (data) {
var nextData = data.__next || null;
var resultsData = data.results || data;
var responseData = { 'results': resultsData, 'next': nextData }
if (nextData) {
responseData.LoadNext = function (callback) {
return performRequest(nextData, callback);
};
}
if (async) {
fnCallback(responseData);
}
else {
return responseData;
}
}, errcallback);
};
return performRequest(queryUrl, callback);
}
As I don't have that much idea about ajax calls, its hard to make this function Asynchronous for me.
Experts please help me to understand that this function is synchronous because of var async = !!callback; this?
If in place of this line I write var async=true; can it make this function asynchronous?
Thanks in advance.

I think i got you exactly what you are asking for.
Please don't get look into this file from where you have copied and pasted this function.
This will make you confuse if you are new for this.
Just call the function from your .js File like this.
function RetrieveCrmRecords(entName, fields, filter, calledForAsync, orderby, errcallback) {
//Your Code
}
function calledForAsync()
{
//Your Code
}
When Operation in RetrieveCrmRecords() will completed rest code will execute finely and then it will come into the calledForAsync().
This is called Async Call.
I hope you were asking for this.
Thanks,
Anish.

Related

How to call script include from the client script servicenow?

Can anyone help me with how to call the script include from the client script?
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
//Current assignment group
var assignment_group = newValue;
if(assignment_group){
var coe = '';
var ga = new GlideAjax('sn_hr_core.scriptIncludeNameUtils'); //Script include
ga.addParam('sysparm_name','MethodName'); //Method/Function
ga.addParam('assignment_group',assignment_group); //Parameter
ga.getXMLAnswer(function(response){
coe = response;
if(coe){
g_form.setValue('u_hr_coe', coe);
}
});
}
}
Script Include:
MethodName: function (assignment_group) {
var sys_id = this.getParameter('assignment_group') ? this.getParameter('assignment_group') : assignment_group; //Params
var result = '';
if(sys_id){
var grSysChoice = new GlideRecord('sys_choice');
grSysChoice.addEncodedQuery("element=assignment_group^name=sn_hr_core_case^dependent_value="+sys_id);
grSysChoice.orderBy('sequence');
grSysChoice.setLimit(1);
grSysChoice.query();
if(grSysChoice.next()) {
result = grSysChoice.getValue('value');
}
}
return result;
},
We need to use GlideAjax to call script include from client script.
var ga = new GlideAjax('sn_hr_core.scriptIncludeNameUtils'); //Script include
ga.addParam('sysparm_name','MethodName'); //Method/Function
ga.addParam('assignment_group',assignment_group); //Parameter
ga.getXMLAnswer(function(response){
coe = response;
if(coe){
g_form.setValue('u_hr_coe', coe);
}
});
Youtube video for Ref:
https://youtu.be/zNGdVSCGggE

ngTagsInput Autocomplete does not Open

I am unable to get the AutoComplete list to display. My service returns json model: TagID: 1, text:MyText
but the AutoComplete list never displays. My HTML:
<tags-input ng-model="tags" tag-class="{even: $index % 2 == 0, odd: $index % 2 != 0}" on-tag-added="addTag(tags)"> <auto-complete source="loadTags($query)"></auto-complete> </tags-input>
My Controller code:
$scope.loadTags = function ($query) {
var tags;
contractorService.gettags()
.success(function (data) {
tags = data;
return tags.filter(function(tag) {
return tag.text.toLowerCase().indexOf($query.toLowerCase()) != -1
UPDATE
I have discovered that it just does not like the Json returned from Ajax call to MVC Controller.
public async Task<ActionResult> GetMajorTags()
{
majorId = UserInfo.intMajorID;
var tags = await CompanyClient.GetAvailableTags(majorId);
return Json(tags, JsonRequestBehavior.AllowGet);
}
Even bypassing the service and calling the MVC Controller method directly like below:
$scope.loadTags = function (query) {
return $http.get('/SSQV4/SSQV5/Contractor/GetMajorTags');
};
If I make the source static like below:
var auto = [
{ TagID: 4,text: 'Tag4' },
{ TagID: 5, text: 'Tag5' },
{ TagID: 6, text: 'Tag6' }
];
It works, but it will not show what is returned from the MVC Controller even though the data returned is in the EXACT same format.
Any assistance is greatly appreciated!
This code is not correct:
$scope.loadTags = function ($query) {
var tags;
contractorService.gettags()
.success(function (data) {
tags = data;
// return where?
return tags.filter(function(tag) {
return tag.text.toLowerCase().indexOf($query.toLowerCase()) != -1
});
});
}
There is no reason to have a return statement within your success callback. Where would that return to? If you did something like this:
var tags = $scope.loadTags();
console.log(tags); // undefined
... tags would be undefined. The reason is because the return statement is NOT returning from the call to loadTags. It is instead returning from within a promise callback.
This is actually how it's done:
var tags = [];
$scope.loadTags = function () {
contractorService
.gettags()
.success(function (data) {
tags = data;
tags = tags.filter(function(tag) {
return tag.text.toLowerCase().indexOf($query.toLowerCase()) != -1;
});
});
};
Notice how there are no return statements (except for your filter).
This just does not work at all:
$scope.loadTags = function (query) {
return $http.get('/SSQV4/SSQV5/Contractor/GetMajorTags');
};
If you were to do something like this:
var tags = $scope.loadTags();
console.log(tags); // promise object. NO DATA
tags would contain a promise object NOT your data. You would need to do the following to get the actual data:
var tags = [];
$scope.loadTags().success(function(data) {
tags = data;
});

Meteor: Session problems

Im getting this error
TypeError: Cannot read property 'set' of undefined
Code is:
Router.map(function() {
this.route('/payment_return/:invoice_no/:amount/', {
where: 'server',
onBeforeAction: function() {
console.log("result");
result = paypal_return(this.params.invoice_no,this.params.amount,this.params.query.token,this.params.query.PayerID);
console.log(result);
if (result)
{
var tokens = this.params.amount*10;
console.log(tokens);
var playerId = this._id;
Session.set('selectedUser', playerId);
var selectedUser = Session.get('selectedUser');
Meteor.call('updateTokens', selectedUser, tokens);
this.response.end("Payment captured successfully");
}
else
{
this.response.end("Error in processing payment");
}
}
});
});
In, methods.js
Meteor.methods({
'updateTokens': function(selectedUser, tokens){
check(selectedUser, String);
check(tokens, Number);
var currentUserId = Meteor.userId();
if(currentUserId){
Meteor.users.update(selectedUser,
{ $inc: { 'profile.tokens': tokens}});
}
}
})
Basically, trying to update user's token amount after successful payment, but unfortunately it's returning just that error.
Sessions are only available in client side... Not sure where you are trying to call Session, but if Session package is included and you are calling Sessions.set/get on client it should work.
This looks like API call to me, so I will suggest you to use meteorhacks:picker
Then you can add on your server side:
var paymentRoutes= Picker.filter(function(req, res) {
return req.method == "POST"; //OR GET WHATEVER YOU NEED
});
paymentRoutes.route('/payment_return/:invoice_no/:amount/',
function(params, req, res, next) {
//UPDATE TOKEN
});
var paymentRoutes= Picker.filter(function(req, res) {
return req.method == "GET" || "POST";
});
paymentRoutes.route('/payment_return/:invoice_no/:amount/', function(params, req, res, next) {
result = paypal_return(params.invoice_no,params.amount,params.query.token, this.userId);
if (result){
var tokens = this.params.amount*10;
var playerId = this.userId;
Meteor.users.update({_id:playerId},{ $inc: { 'profile.tokens': tokens}});
res.end("Payment captured successfully");
}else{
res.end("Error in processing payment");
}
});
I hope this will be helpful, Cheers

fetch returning promise rather than value

Hopefully the code below communicates the problem clearly. The issue is that in the module which uses the get method of fetchData, the value being returned is the actual Promise, rather than the JSON as desired. Any thoughts on this?
// fetchData.js module
var _ = require('lodash');
function get() {
var endpoint1 = `/endpoint1`;
var endpoint2 = `/endpoint2`;
return fetch(endpoint1)
.then((endpoint1Response) => {
return endpoint1Response.json()
.then((endpoint1JSON) => {
return fetch(endpoint2)
.then((endpoint2Response) => {
return endpoint2Response.json()
.then((endpoint2JSON) => {
var data = _.merge({}, {json1: endpoint1JSON}, {json2: endpoint2JSON});
console.log('data in fetch', data); // this logs the json
return data;
});
});
});
});
}
exports.get = get;
// module which uses get method of fetchData get
var fetchData = require('fetchData');
var data = fetchData.get();
console.log('returned from fetchData', data); // this logs a Promise
Yes, that's exactly what's supposed to happen. The whole point of promises is that their result value is not immediately available and that doesn't change just because you're obtaining one from a separate module.
You can access the value like this:
var fetchData = require('fetchData');
fetchData.get().then(data =>
console.log('returned from fetchData', data);
);
Also note that you are using promises in a non-idiomatic way and creating a "tower of doom." This is much easier on the eyes and accomplishes the same thing:
function fetchJson(endpoint) {
return fetch(endpoint)
.then(endpointResponse => endpointResponse.json());
}
function get() {
var endpoint1 = `/endpoint1`;
var endpoint2 = `/endpoint2`;
return Promise.all([fetchJson(endpoint1), fetchJson(endpoint2)])
.then(responses => {
var data = { json1: responses[0], json2: responses[1] };
console.log('data in fetch', data); // this logs the json
return data;
});
}
Edit I haven't used async/await in JavaScript, but to answer your question, I presume this would work:
async function fetchJson(endpoint) {
var res = await fetch(endpoint);
return res.json();
}
async function get() {
var endpoint1 = `/endpoint1`;
var endpoint2 = `/endpoint2`;
var data = {
json1: await fetchJson(endpoint1),
json2: await fetchJson(endpoint2)
};
console.log('data in fetch', data); // this logs the json
return data;
}
// module which uses get method of fetchData get
async function main() {
var fetchData = require('fetchData');
var data = await fetchData.get();
console.log('returned from fetchData', data);
}
return main();

AngularJs 2 promises inside a watch the second one never works

I have 2 lists in my application and the user is supposed to drag and drop items from one list to another.
When the user drops an element from one of the lists to the other list a request has to be made to the server side code to update a field in the database (SelectedForDiscussion).
This is the code in my controller:
$scope.$watch("questionsDiscuss", function (value) {
var question = $.Enumerable.From($scope.questionsDiscuss).Where(function (item) { return !item.SelectedForDiscussion }).FirstOrDefault()
if (question != undefined) {
questionSelectionService.UpdateQuestionSelectionStatus(question.Id, true)
.then(function (output) {
var question = $.Enumerable.From($scope.questionsDiscuss)
.Where(function (item) { return item.Id == output.data.questionId })
.FirstOrDefault();
var index = $.Enumerable.From($scope.questionsDiscuss).IndexOf(question);
if (question != undefined)
if (output.data.result != "success") {
$scope.questionsDiscuss.splice(index, 1);
$scope.questionsReceived.splice(0, 0, question);
}
else {
question.SelectedForDiscussion = true;
$scope.questionsDiscuss[index] = question;
}
});
}
else {
var question = $.Enumerable.From($scope.questionsReceived).Where(function (item) { return item.SelectedForDiscussion }).FirstOrDefault();
if (question != undefined) {
questionSelectionService.UpdateQuestionSelectionStatus(question.Id, false)
.then(function (output) {
var question = $.Enumerable.From($scope.questionsReceived)
.Where(function (item) { return item.Id == output.data.questionId })
.FirstOrDefault();
var index = $.Enumerable.From($scope.questionsReceived).IndexOf(question);
if (question != undefined)
if (output.data.result != "success") {
$scope.questionsReceived.splice(index, 1);
$scope.questionsDiscuss.splice(0, 0, question);
}
else {
question.SelectedForDiscussion = false;
$scope.questionsReceived[index] = question;
}
});
}
}
}, true);
I have 4 javascript breakpoint placed at the following lines within Firebug:
2 of them at the following lines:
if (question != undefined) {
One at:
var question = $.Enumerable.From($scope.questionsDiscuss)
.Where(function (item) {
return item.Id == output.data.questionId
})
.FirstOrDefault();
And the other at:
var question = $.Enumerable.From($scope.questionsReceived)
.Where(function (item) {
return item.Id == output.data.questionId
})
.FirstOrDefault();
The following happens:
The breakpoints at:
if (question != undefined) {
are always reached.
The breakpoint at
var question = $.Enumerable.From($scope.questionsDiscuss)
.Where(function (item) {
return item.Id == output.data.questionId
})
.FirstOrDefault();
is also reached.
The other is never reached.
Both responses are OK(response code 200).
Everything should work perfectly but the then clause in the second promise is never reached.
Can anyone tell me what I am doing wrong?
The serverside appplication is an ASP.NET MVC application written in C#.
Edit 1:
I figured out why this was happening and I have a work around for it. I am stil interested in an actual solution.
The problem is angularjs throws an error then swallows it when calling $http for the second time. The error is:
digest alredy in progress
I think this is because in my directive I have this code:
dndfunc = function (scope, element, attrs) {
// contains the args for this component
var args = attrs.dndBetweenList.split(',');
// contains the args for the target
var targetArgs = $('#' + args[1]).attr('dnd-between-list').split(',');
// variables used for dnd
var toUpdate;
var target;
var startIndex = -1;
// watch the model, so we always know what element
// is at a specific position
scope.$watch(args[0], function (value) {
toUpdate = value;
}, true);
// also watch for changes in the target list
scope.$watch(targetArgs[0], function (value) {
target = value;
}, true);
// use jquery to make the element sortable (dnd). This is called
// when the element is rendered
$(element[0]).sortable({
items: 'div',
start: function (event, ui) {
// on start we define where the item is dragged from
startIndex = ($(ui.item).index());
},
stop: function (event, ui) {
var newParent = ui.item[0].parentNode.id;
// on stop we determine the new index of the
// item and store it there
var newIndex = ($(ui.item).index());
var toMove = toUpdate[startIndex];
// we need to remove him from the configured model
toUpdate.splice(startIndex, 1);
if (newParent == args[1]) {
// and add it to the linked list
target.splice(newIndex, 0, toMove);
} else {
toUpdate.splice(newIndex, 0, toMove);
}
// we move items in the array, if we want
// to trigger an update in angular use $apply()
// since we're outside angulars lifecycle
scope.$apply(targetArgs[0]);
scope.$apply(args[0]);
},
connectWith: '#' + args[1]
})
}
And there are 2 calls to apply at the end which trigger a new digest cycle I think.
Anyway I fixed it by adding this call before the calls to apply:
if (scope.updateLists != undefined)
scope.updateLists();
And moved all the code from the watch into the updateLists function.
Also because people have mentioned the service as having something to do with it I am pasting the relevant code within it:
GetQuestionsReceived: function (eid, criteria, page, rows) {
var promise = this.GetQuestionsReceivedInternal(eid,criteria, page, rows).then(function (response) {
// The return value gets picked up by the then in the controller.
return response;
});
// Return the promise to the controller
return promise;
},
GetQuestionsReceivedInternal: function (eid, criteria, page, rows) {
return $http({ method: 'GET',
url: '../QuestionManagement/GetQuestions?eventId='+eid+'&page=1&rows=5&'+serialize(criteria)
}).
success(function (data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
results = data;
}).
error(function (data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
if (window.console && console.log) {
console.log("Could not obtain questions received. Error:" + data + "Status:" + status + "Headers:" + headers + "Config:" + config);
}
});
},
GetQuestionsDiscuss: function (eid,criteria, page, rows) {
var promise = this.GetQuestionsDiscussInternal(eid,criteria, page, rows).then(function (response) {
// The return value gets picked up by the then in the controller.
return response;
});
// Return the promise to the controller
return promise;
},
GetQuestionsDiscussInternal: function (eid,criteria, page, rows) {
return $http({ method: 'GET',
url: '../QuestionManagement/GetQuestions?eventId=' + eid + '&page=1&rows=5&' + serialize(criteria)
}).
success(function (data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
response = data;
}).
error(function (data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
if (window.console && console.log) {
console.log("Could not obtain questions received. Error:" + data + "Status:" + status + "Headers:" + headers + "Config:" + config);
}
});
},
You have two very similar blocks of code, which could be generalized and placed in a function wrapper, leaving behind a very simple calling function.
If you can get everything into that form, then I think you will find it easier to debug.
Here is an attempt to do so :
function updateSelectionStatus(qA, qB, bool) {
var en = $.Enumerable.From(qA);
var question = en.Where(function (item) {
return bool ? !item.SelectedForDiscussion : item.SelectedForDiscussion;
}).FirstOrDefault();
if(question) {
questionSelectionService.UpdateQuestionSelectionStatus(question.Id, bool).then(function (output) {
if (output.data.result == "success") {
question.SelectedForDiscussion = bool;
}
else {
qA.splice(en.IndexOf(question), 1);
qB.unshift(question);
}
});
}
return question;
}
$scope.$watch("questionsDiscuss", function (value) {
if (!updateSelectionStatus($scope.questionsDiscuss, $scope.questionsReceived, true) {
updateSelectionStatus($scope.questionsReceived, $scope.questionsDiscuss, false);
}
}, true);
I may have made some false assumptions and simplified too much (eg. purging the inner $.Enumerable.From, which appears to reselect the same question as the outer), so you may well need to rework my code.
I'm advocating a principle here, rather than offering a solution.

Resources