Angularjs scope variable after $http call isn't updated in the view - scope

I have this in the service:
UpdateQuestionsSmsStatus: function (smsProfileId, active) {
//TODO: ajax get data
var promise = this.UpdateQuestionsSmsStatusInternal(smsProfileId, active).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;
},
UpdateQuestionsSmsStatusInternal: function (smsProfileId, active) {
return $http({ method: 'GET',
url: '../QuestionManagement/UpdateQuestionsSmsStatus?smsProfileId=' + smsProfileId + '&active=' + active
}).
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);
}
});
},
This in my controller:
$scope.updateQuestionsSmsStatus = function () {
questionSelectionService.UpdateQuestionsSmsStatus($scope.smsProfile.Id, !$scope.smsProfile.Active).then(function (output) {
$scope.smsProfile.Active = (output.data.result == "success") ? output.data.active : !output.data.active;
});
};
Which is called onclick from the view.
And this in the view:
{{smsProfile.Active}}
The value in the view is never updated. Debugger doesn't show anything wrong, no errors appear.
Does anyone have any ideas? Thank you.

Your success callback in UpdateQuestionsSmsStatusInternalfunction needs to return a value:
return $http({ method: 'GET',
url: '../QuestionManagement/UpdateQuestionsSmsStatus?smsProfileId=' + smsProfileId + '&active=' + active
}).
success(function (data, status, headers, config) {
return data;
})
...
and, to accommodate that, your controller's updateQuestionsSmsStatus function should adjust the callback:
$scope.updateQuestionsSmsStatus = function () {
questionSelectionService.UpdateQuestionsSmsStatus($scope.smsProfile.Id, !$scope.smsProfile.Active).then(function (data) {
$scope.smsProfile.Active = (data.result == "success") ? data.active : !data.active;
}
);
};

Related

Wait for API to return its response before executing the next iteration in nodejs

I am new to nodejs.
I have an array of string that consists of around 30000+ values, which has the below format
tickerArray = ["A","AA","AAA", ..........., "C"]
I want to loop through these and need to sent each value to an external polygon.io API. But the Polygo.io free plan only allows 5 API Call per minute. Below is my code.
await tickerArray.reduce((key:any, tickerSymbol:any) =>
key.then(async () => await stockTickeDetails.runTask(tickerSymbol)),
starterPromise
);
}).catch(function (error: any) {
console.log("Error:" + error);
});
My runTask function is below :
public runTask(tickerSymbol:any) {
return axios.get('https://api.polygon.io/v1/meta/symbols/' + tickerSymbol + '/company?apiKey=' + process.env.API_KEY).then(
function (response: any) {
console.log("Logo : " + response.data.logo + 'TICKER :' + tickerSymbol);
let logo = response.data.logo;
let updateLogo = stockTickers.updateOne({ ticker: tickerSymbol }, { $set: { "logo": logo } })
}).catch(function (error: any) {
console.log("Error from symbol service file : " + error);
});
}
Here what I need is, if I pass the 0th index value ie, "A" to runTask method, it should process the API and should return the result and from the result I need to update the database collection accordingly.
Then should go back to the 1code and need to fetch the 1st index value ie "AA" and repeat the process.
Here after executing 2 APIs I am getting the following error
Request failed with status code 429. You've exceeded the maximum requests per minute.
I guess this is because it is not waiting till the request to get processed with each value. How can I resolve it by adding a set time out which delays 5 API call per minute.
You can easily achieve this using Promise pattern, here is your solution:
var tickerArray = ["A","AA","AAA", ..........., "C"]
let requests = tickerArray.map(tickerSymbol => {
//generate a promise for each API call
return new Promise((resolve, reject) => {
request({
uri: https://api.polygon.io/v1/meta/symbols/' + tickerSymbol + '/company?apiKey=' + process.env.API_KEY,
method: 'GET'
},
(err, res, body) => {
if (err) { reject(err) }
//call to resolve method which is passed to the caller
//method passed to the promise
resolve( { response : body, request: tickerSymbol })
})
})
})
Promise.all(requests).then((objArray) => {
//this is expected when all the promises have been resolved/rejected.
objArray.forEach(obj => {
if (obj) {
console.log("Logo : " + obj.response.data.logo + 'TICKER :' + obj.request);
let logo = obj.response.data.logo;
let updateLogo = stockTickers.updateOne({ ticker: obj.request }, { $set: { "logo": logo } })
}
})
}).catch(error => console.log("Error from symbol service file : " + error);)

Reading and writing to file is non-blocking in my code. Why?

I'm working on a bot used for Twitch Song Requests. The bot will read the Twitch chat, search for !sr command and get the name of the song. Then, it will search for the song in Spotify, get the URI of the song and add it in the streamer's playlist.
EDIT: I'm sorry if there are any "dumb" code problem (like the callback #ippi notified), I'm really new to programming and Node JS especially.
I now have two functions: one that is searching for the song and writing the received URI in a text file, and one getting the URI from the file. Here's the code:
main code (call of the two functions):
testSong(commandName, accessToken);
let uri = getUri();
console.log(uri);
search for the song:
function testSong(song, accessToken) {
let song1;
let song2;
song1 = song.replace("!sr", "");
song2 = song1.trim();
var uri = "";
axios.get('https://api.spotify.com/v1/search?q=' + encodeURIComponent(song2) + '&type=track&market=CH&limit=1', {
headers: {
Authorization: 'Bearer ' + accessToken
}
})
// handle success
.then(function (response) {
uri = response.data.tracks.items[0].uri;
console.log("yeet")
fs.writeFileSync('conf/uri.txt');
logger.log('info', 'Successfully obtained URI for track ' + song2);
})
// handle error
.catch(function (error) {
logger.log('error', 'Error while accessing Spotify.');
return error;
});
}
get the URI:
function getUri() {
try {
return fs.readFileSync('conf/uri.txt', 'utf-8');
} catch (e) {
logger.log('error', 'Error while reading the URI text file: ' + e.stack);
}
}
I'm having a problem at the reading time. When running the bot for the first time, the uri.txt file is empty.
When I'm sending the first !sr in the Twitch chat, the song is not added in the Spotify playlist beacause it seems that the testSong command is writing to text file AFTER the getUri function read the file.
Even after that, I have to send a new !sr to add the first song, so every request is shifted.
Any idea why this is happening ?
I've read about async functions, but as far as I've understood, it's not what I want because I want the execution of the program to be blocked when I'm writing to the text file, thus the getUri function can then read the current requested song URI, and not be shifted.
EDIT 2: as Felix said, I modified the code as follow:
testSong(commandName, accessToken).then(() => console.log(getUri()));
function testSong(song, accessToken) {
let song1;
let song2;
song1 = song.replace("!sr", "");
song2 = song1.trim();
var uri = "";
return axios.get('https://api.spotify.com/v1/search?q=' + encodeURIComponent(song2) + '&type=track&market=CH&limit=1', {
headers: {
Authorization: 'Bearer ' + accessToken
}
})
// handle success
.then(function (response) {
uri = response.data.tracks.items[0].uri;
console.log("yeet")
fs.writeFileSync('conf/uri.txt', uri, function (err) {
if (err) {
return console.log(err);
} else {
response = true;
}
});
logger.log('info', 'Successfully obtained URI for track ' + song2);
})
// handle error
.catch(function (error) {
logger.log('error', 'Error while accessing Spotify.');
return error;
});
}
Is that correct?
As I have already mentioned in my comments, you are having this problem because you are using promises, i.e. the file will be written some time in the future, after you are trying to read.
And as we discussed, there is no need to use a file to "transfer" the value at all. You can just return the value from testSong (wrapped in a promise):
function testSong(song, accessToken) {
song = song.replace("!sr", "").trim();
return axios.get('https://api.spotify.com/v1/search?q=' + encodeURIComponent(song2) + '&type=track&market=CH&limit=1', {
headers: {
Authorization: 'Bearer ' + accessToken
}
})
// handle success
.then(function (response) {
return response.data.tracks.items[0].uri;
});
// errors should probably be handled by the caller
}
and then:
testSong(commandName, accessToken)
.then(function(uri) {
console.log(uri);
})
.catch(function(error) {
// handle error
});
An async function makes working with promises a bit easier. So you could implement testSong also as
async function testSong(song, accessToken) {
song = song.replace("!sr", "").trim();
const response = await axios.get('https://api.spotify.com/v1/search?q=' + encodeURIComponent(song2) + '&type=track&market=CH&limit=1', {
// ^^^^^
headers: {
Authorization: 'Bearer ' + accessToken
}
});
return response.data.tracks.items[0].uri.
}

Nodejs, why lines after ASYNC call are not executing?

I am trying to write a AWS Lambda function with Nodejs.
Inside the code I have to call a API, wait for the response and do other things with that data (I haven't still write anything about this)
NOTE: sorry about declaring customerTAX as global, but I prefer to get the lambda function to work with and after, try to return the value from the function isself.
This is the code:
'use strict';
var customerTAX;
const https = require('https');
const options = {
host: 'xxxxxxx.com',
port: 443,
path: '/yyyyyyy.json',
method: 'POST',
headers: {
'Content-Type': 'application/graphql',
}
};
exports.handler = async (event) => {
const body = JSON.parse(event.body);
const orderId = body.id;
const customerId = body.customer.id;
console.log('ORDER ID: ' + orderId);
console.log('CUST ID: ' + customerId);
const query = `xxxxxxxxxxxxxxxxxxxx`;
//I CAN SEE ALL LOGS OF THIS FUNCTION IN CLOUDWATCH
await getCustomerTAX(query);
//I CAN'T SEE NOTHING BELOW THIS LINE IN AWS CLOUDWATCH
console.log('CUST TAX: ' + customerTAX);
if (customerTAX != null) {
console.log('LETs GO TO SAVE IT')
} else {
console.log('NOTAX: No customerTAX');
}
const response = {
statusCode: 200,
body: JSON.stringify(event.body),
};
return response;
};
var getCustomerTAX = function(query) {
return new Promise(function(resolve, reject) {
var req = https.request(options, function(res) {
res.setEncoding('utf8');
var bodyRaw = '';
res.on('readable', function () {
var chunk = this.read() || '';
bodyRaw += chunk;
console.log('getTAX CHUNK (' + Buffer.byteLength(chunk) + ' bytes): ' + chunk);
});
res.on('end', function () {
const body = JSON.parse(bodyRaw);
if (body.TAX.value != null) {
customerTAX = body.TAX.value;
} else {
customerTAX = null;
}
console.log("getTAX END: " + customerTAX);
resolve;
//console.log('body: ' + Buffer.byteLength(body) + ' bytes');
});
});
//handle the possible errors
req.on('error', function(e) {
console.log("ERROR: " + e);
reject(e);
});
//do the request
req.write(query);
//finish the request
req.end();
});
};
Function getCustomerTAX works perfectly, but I don't know why my lambda function is "finished" in this line, and I can't see more console-logs in cloudwatch.
Hope your answer and thanks a lot.
For starters in getCustomerTax(), resolve; needs to be resolve();.
It's a function. You need to call it.
Without calling resolve(), the promise is never resolved and thus await getCustomerTax() never finishes and the lines after it are never executed.
FYI, the request-promise module will automatically do a lot of what you have in getCustomerTax() (make an http request, get the response, handle all possible errors and return a promise that represents the result).
EDIT Jan, 2020 - request() module in maintenance mode
FYI, the request module and its derivatives like request-promise are now in maintenance mode and will not be actively developed to add new features. You can read more about the reasoning here. There is a list of alternatives in this table with some discussion of each one. I have been using got() myself and it's built from the beginning to use promises and is simple to use.

Live search using autocomplete node.js and express.js

community. I am trying to implement a live search using the autocomplete library but every try is unsuccessful. I get every time a 500 server error. Every assistant is appreciated because I am new in coding.
I have a simple model for an article with title and body and I would like to show suggestions when the user search for an article
model/article.js
// Method to construct the json result set
module.exports.buildResultSet=function(docs) {
var result = [];
for(var object in docs){
result.push(docs[object]);
}
return result;
}
routes/article.js
router.get('/search', function(req, res){
encyclopediaModel.getMyArticlesByName(theRequester, function (pError, pFoundedArticles) {
if (!pError) {
// Method to construct the json result set
var result = encyclopediaModel.buildResultSet(pFoundedArticles);
res.json(result);
} else {
return res.json(JSON.stringify(pError), {
'Content-Type': 'application/json'
}, 404);
}
},req.query.title)
});
//Ajax call
$("#search-query").autocomplete({
source: function (request, response) {
$.ajax({
url: "/encyclopedia/search",
type: "GET",
data: request, // request is the value of search input
success: function (data) {
response( data );
console.log('success', data);
}
});
},
// The minimum number of characters a user must type before a search is performed.
minLength: 3,
// set an onFocus event to show the result on input field when result is focused
focus: function (event, ui) {
this.value = ui.item.label;
// Prevent other event from not being execute
event.preventDefault();
},
select: function (event, ui) {
}
});
<input id="search-query" type="text" placeholder="Articles...">
module.exports.getMyArticlesByName = function (requester, callback, pTitle){
var regex = new RegExp(pTitle["term"], 'i');
article.find({title: regex}, { 'title': 1 }).sort({"updated_at":-1}).sort({"created_at":-1}).limit(20).exec(callback);
}

mocha returns "callback is not a function" for async calls

i'm trying to use nodejs (es6 + babel) along with mocha.
Here is the Base class i'm testing :
import cheerio from 'cheerio';
import ResourceRequest from './ResourceRequest';
export default class HtmlValueParser {
constructor(url, headers) {
this.rr = new ResourceRequest(url, headers);
this.body = null;
this.$ = null;
}
getValue(query) {
if (!query) {
return;
}
if (this.$ === null){
this.$ = cheerio.load(this.body);
return 'toto';
}else {
return 'titi';
}
}
getAValue(query, callback) {
if (this.body === null) {
this.rr.getResource((error, response, body) => {
this.body = body;
let val = this.getValue(query);
callback(null, val);
});
}else {
process.nextTick(callback(null, this.getValue(query)));
}
}
}
I'm just downloading an HTML ressource and then willing to do a css query to get a specific value into it.
I have put in place a basic caching of the content downloaded so i can query it with the getAValue multiple time and using nextTick allows me to keep the function consistently asynchronous.
The ResourceRequest Object is just a simple abstraction of the request module :
import request from 'request';
export default class ResourceRequest {
constructor(url, headers){
this.options = {
url: url,
headers: headers
};
}
getResource(callback) {
request(this.options, callback);
}
}
This all works flawlessly in my index.js, but using mocha (along with Istanbul for coverage) to test it (once without caching, next to see if caching is used), i get the following error :
TypeError in plugin 'gulp-mocha' Message:
callback is not a function Details:
domain: [object Object]
domainThrown: true Stack: TypeError: callback is not a function
at doNTCallback0 (node.js:407:9)
at process._tickDomainCallback (node.js:377:13)
here is my testfile :
import assert from 'assert';
import HtmlValueParser from '../lib/HtmlValueParser';
var url = 'http://google.fr';
var headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36'
};
describe('HTMLValueParser', function() {
var hvp = new HtmlValueParser(url, headers);
describe('Empty Cache', function() {
it('should not use cache', function(done) {
hvp.getAValue({}, function(error, value) {
assert.equal(value, 'toto', 'value should be toto');
done();
});
});
});
describe('Cache Enabled', function() {
it('should use cache', function(done) {
hvp.getAValue({}, function(error, value) {
assert.equal(value, 'titi', 'value should be titi');
done();
});
});
});
});
the error happens after the second "it" test.
Not sure if this me using it wrongly or if this is a bug in gulp-mocha or ... well i don't know !
Anyway thanks in advance for your help.

Resources