AngularJS serverside variable to ng-init and methods sequence - asp.net-mvc

I´v got a "detail" view and a controller that initilizes data with an id.
My view:
<div ng-app="AFApp" ng-controller="AgentCtrl" ng-init="init('#Model.Id')">
My controller:
$scope.id;
$scope.agent = {};
$scope.init = function (id) {
$scope.id = id;
getAgent();
getAgentStatus();
getSystemInfo();
getActions();
};
The problem is that the method "getAgentStatus();" gets executed before "getAgent();". The "getAgentStatus" needs the $scope.agent data that "getAgent" provides. The function getAgentStatus has an attached timer, and it gets the value as the timer elepses but not in the init function. Can someone please help me out with the method execution sequence in angular controllers and how the id parameter is provided the best possible way.
See methods below:
function getAgent() {
agentDataFactory.getAgent($scope.id)
.success(function (data) {
$scope.agent = data;
})
.error(function (error) {
console.log('Unable to load data: ' + error.message);
});
};
function getAgentStatus() {
if (typeof ($scope.agent.ServiceUrl) == 'undefined' || $scope.agent.ServiceUrl == null) {
console.log('getAgentStatus: ServiceUrl is undefined ' + JSON.stringify($scope.agent));
}
agentDataFactory.getAgentStatus($scope.agent.ServiceUrl)
.success(function (data) {
$scope.agent.CurrentStatus = data.Status;
$scope.agent.CurrentInterval = data.Interval;
})
.error(function (error) {
console.log('Unable to load data: ' + error);
});
$timeout(getAgentStatus, 3000);
};

You can pass getAgentStatus() as a callback parameter to getAgent() and have it executed in the success callback (at which point agent will be defined):
function getAgent(callback) {
agentDataFactory.getAgent($scope.id)
.success(function (data) {
$scope.agent = data;
callback && callback();
})
.error(function (error) {
console.log('Unable to load data: ' + error.message);
});
};
$scope.init = function (id) {
$scope.id = id;
getAgent(getAgentStatus);
getSystemInfo();
getActions();
};
Short explanation:
Some highlights first:
agentDataFactory.getAgent($scope.id).success(...).error(...);:
Creates a promise (which will be resolved) asynchronously and registers two callbacks, one if the promise is successfully resolved and one for the case of an error.
.success(function (data) { $scope.agent = data; }):
Registers a callbackfor when the promise is successfully resolved. When (and if) that happens, $scope.agent will be set.
function getAgentStatus() { if (typeof ($scope.agent.ServiceUrl...:
Tries to access some properties of $scope.agent and thus requires the object to be defined.
So, what happens with your code:
getAgent() is gets called.
[$scope.agent is undefined]
A promise is created that when resolved will set $scope.agent.
[$scope.agent is undefined]
getAgent() returns and getAgentStatus() is called.
[$scope.agent is undefined]
getAgentStatus() tries to access $scope.agent's properties and fails.
[$scope.agent is undefined]
The promise created in step 2 is resolved and its success callback get executed.
[$scope.agent is finally defined]
My version of the code ensures that getAgentStatus() is not executed before the promise is resolved and thus $scope.agent is defined:
getAgent() is gets called.
[$scope.agent is undefined]
A promise is created that when resolved will set $scope.agent.
[$scope.agent is undefined]
getAgent() returns and other functions get called (e.g. getSystemInfo(), getActions(), etc.).
[$scope.agent is undefined]
The promise created in step 2 is resolved and its success callback get executed.
[$scope.agent is finally defined]
Only now does getAgentStatus() get called and it works as expected since...
[$scope.agent is defined]
Take a look at the $q service for more info on Angular promises.

Related

Manifest v3 extension: asynchronous event listener does not keep the service worker alive [duplicate]

I am trying to pass messages between content script and the extension
Here is what I have in content-script
chrome.runtime.sendMessage({type: "getUrls"}, function(response) {
console.log(response)
});
And in the background script I have
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.type == "getUrls"){
getUrls(request, sender, sendResponse)
}
});
function getUrls(request, sender, sendResponse){
var resp = sendResponse;
$.ajax({
url: "http://localhost:3000/urls",
method: 'GET',
success: function(d){
resp({urls: d})
}
});
}
Now if I send the response before the ajax call in the getUrls function, the response is sent successfully, but in the success method of the ajax call when I send the response it doesn't send it, when I go into debugging I can see that the port is null inside the code for sendResponse function.
From the documentation for chrome.runtime.onMessage.addListener:
This function becomes invalid when the event listener returns, unless you return true from the event listener to indicate you wish to send a response asynchronously (this will keep the message channel open to the other end until sendResponse is called).
So you just need to add return true; after the call to getUrls to indicate that you'll call the response function asynchronously.
The accepted answer is correct, I just wanted to add sample code that simplifies this.
The problem is that the API (in my view) is not well designed because it forces us developers to know if a particular message will be handled async or not. If you handle many different messages this becomes an impossible task because you never know if deep down some function a passed-in sendResponse will be called async or not.
Consider this:
chrome.extension.onMessage.addListener(function (request, sender, sendResponseParam) {
if (request.method == "method1") {
handleMethod1(sendResponse);
}
How can I know if deep down handleMethod1 the call will be async or not? How can someone that modifies handleMethod1 knows that it will break a caller by introducing something async?
My solution is this:
chrome.extension.onMessage.addListener(function (request, sender, sendResponseParam) {
var responseStatus = { bCalled: false };
function sendResponse(obj) { //dummy wrapper to deal with exceptions and detect async
try {
sendResponseParam(obj);
} catch (e) {
//error handling
}
responseStatus.bCalled= true;
}
if (request.method == "method1") {
handleMethod1(sendResponse);
}
else if (request.method == "method2") {
handleMethod2(sendResponse);
}
...
if (!responseStatus.bCalled) { //if its set, the call wasn't async, else it is.
return true;
}
});
This automatically handles the return value, regardless of how you choose to handle the message. Note that this assumes that you never forget to call the response function. Also note that chromium could have automated this for us, I don't see why they didn't.
You can use my library https://github.com/lawlietmester/webextension to make this work in both Chrome and FF with Firefox way without callbacks.
Your code will look like:
Browser.runtime.onMessage.addListener( request => new Promise( resolve => {
if( !request || typeof request !== 'object' || request.type !== "getUrls" ) return;
$.ajax({
'url': "http://localhost:3000/urls",
'method': 'GET'
}).then( urls => { resolve({ urls }); });
}) );

Amazon Lex- slot elicitation not working inside callback

I have a call back function which is getting data from an external API and depends on a data check I have tried for a slot elicitation inside callback but looks like elicitation is not working inside the callback. Please find the code snippet below,
GetCustomerDetails().then(response => {
var serializedcustomerDetails = convert.xml2json(response.data, {
compact: true,
spaces: 2
});
var customerDetails = JSON.parse(serializedcustomerDetails);
let filteredCustomerDetails = _.filter(customerDetails.CustomerInfo.CustomerDetails, function (o) {
return o.CustomerName._text.includes(customerName);
})
if (filteredCustomerDetails.length == 1) {
callback(elicitSlot(outputSessionAttributes, intentRequest.currentIntent.name,
intentRequest.currentIntent.slots, '​CustomerCode', {
contentType: 'PlainText',
content: `Do you mean ${filteredCustomerDetails[0].CustomerName._text} of ${filteredCustomerDetails[0].SpecialityName._text} department?`
}));
return;
}
}).catch(error => {
console.log(`${error}`)
})
This is my first Awnser on stack so please bear with me.
I have come accross the same problem in a recent project and there are a few things that you can check.
How long does the API call take?
If your API call takes a long time it will be worth checking the timeout settings on your Lambda function. AWS Console -> Lambda -> Your Function -> Basic settings -> Timeout.
Does your Lambda function finish before the API call is done?
I fixed this issue by building a node module to handle my business logic, the module has a function called getNextSlot it returns as a Promise. Inside this function I check the incoming event and figure out which slot I need to elicit next, part of my flow is to call an API endpoint that takes around 10 seconds to complete.
I use the request-promise package to make the api call, this node module makes sure that the lambda function keeps running while the call is running.
exports.getData = function (url, data) {
var pr = require("request-promise");
var options = {
method: 'POST',
url: 'api.example',
qs: {},
headers:
{
'Content-Type': 'application/json'
},
body: {
"example": data
},
json: true,
timeout: 60000
};
return pr(options);
}
In my main code I call this function as:
apiModule.getData("test", "data")
.then(function (data) {
//Execute callback
})
.catch(function (error) {
console.log(error);
reject(error);
});
This solved the issue for me anyways.
Thanks,

Falcor Router should return the value from external API

I am new to JavaScript frameworks and currently trying to setup a falcor router calling an external api (for now consider it as an express api app + mango db, hosted at 3000 port).
Now, I am able to use the request package (commented out lines) and successfully call the Express Api app (which returns obj.rating = 4). But I am unable to send this value from the falcor router instead of the hard-coded value "5".
Below is the falcor-router's server.js code:
app.use('/rating.json', falcorExpress.dataSourceRoute(function (req, res) {
return new Router([
{
route: "rating",
get: function() {
var obj;
// request('http://localhost:3000/rating/101', function (error, response, body) {
// obj = JSON.parse(body);
// console.log('rating:', obj.rating); // obj.rating = 4
// });
return {path:["rating"], value:"5"};
}
}
]);
}));
The below is the code for index.html:
<script>
function showRating() {
var model = new falcor.Model({source: new falcor.HttpDataSource('http://localhost/rating.json') });
model.
get("rating").
then(function(response) {
document.getElementById('filmRating').innerText = JSON.stringify(response.json,null, 4);
});
}
</script>
I also tried to look at the global variable declaration, synchronize http request calls, promises, then statements etc. But nothing seemed to work, clearly I am missing out something here - not sure what.
The router's get handler expects the return value to be a promise or an observable that resolves to a pathValue. To get your request against the db to work, simply return a promise that resolves to a pathValue, e.g.
return new Router([
{
route: "rating",
get: function() {
return request('http://localhost:3000/rating/101', function (error, response, body) {
return { path: ["rating", value: JSON.parse(body).rating };
});
}
}
]);

entityAspect.loadNavigationProperty returns null

return datacontext.fetchEntity('Hearing', vm.hearingID()).then(function (result) {
vm.hearingEntity = result.entity;
vm.hearingEntity.entityAspect.loadNavigationProperty("Client");
});
What can be the reason behind "Client" navigation property returned as null in the above code ?
"loadNavigationProperty" is an asynchronous method that returns a promise. You need to wait for the promise to return. Something like:
vm.hearingEntity.entityAspect.loadNavigationProperty("Client").then(function(data) {
// this is your result.
var clients = data.results;
});

How to wait for all ajax queries to finish (and use combined result)

var display_message="";
$('input:checked').each(function(index) {
var profile_id=$(this).val();
$.ajax({
type: 'post',
url: 'myUrl',
data: data,
success: function(data) {
if(data=="ok")
display_message = display_message + data +", ";
}
});
});
alert(display_message);
alert(display_message);
if($.trim(display_message)!=""){
jAlert("Your birthdate already exits in "+display_message.substring(0, display_message.length - 2)+".", "Bdate");
return false;
}
in this code, i use two alert-box for display display_message variable value.
when i run successfully this code, in 1st alert-box i get blank value and second alert-box i get value which i needed, then it will go in if condition.
if i doesn't use alert box then it will always take null value in display_message variable and never enters into the if condition. so what i need to change to run this code without alert box?
You are making an asynchronous call via AJAX, but your code is executing synchronously. So it is returning before the AJAX call completes. The first alert box just gives the function time to catch up. You need to handle all this code in your success callback.
var display_message="";
$('input:checked').each(function(index) {
var profile_id=$(this).val();
$.ajax({
type: 'post',
url: 'myUrl',
data: data,
success: function(data) {
if(data=="ok")
display_message = display_message + data +", ";
if($.trim(display_message)!=""){
jAlert("Your birthdate already exits in "+display_message.substring(0, display_message.length - 2)+".", "Bdate");
return false;
}
});
});
You want all your ajax queries to finish and return results, right?
Then this is a synchronization problem.
I would suggest this approach (code is simplified for clarity).
var inputs_processed = -1;
var inputs_to_process = -1;
function queryData() {
inputs_to_process = $('input:checked').length;
$('input:checked').each(function() {
$.ajax({success: function(data) {
inputs_processed += 1;
// build up that message
}});
});
}
function displayResult() {
if (inputs_processed == inputs_to_process) {
// display result
} else {
// not all queries finished yet. Wait.
setTimeout(displayResult, 500);
}
}
queryData();
displayResult();
Basically, you know how many requests should be made and you don't display result until that number of requests returns.
Why your data is "data"? I cant see any variable called data is declared here. You should pass in the value you want to use as the parameter into the data options.
Edit: This is why u getting the null value. data is not initialize into anything. Only after the success function, your "data" will have the value since you declare the return value with the same name

Resources