I need to save multiple records in loop. In dialog.js i m getting my correct object which i m sending to service js to save. calling service js in loop only. while i m running this service js save function is called after dialog js loop. how is this happening? How can i save data in loop?
Dialog-controller.js
function save () {
vm.isSaving = true;
for(var i in resourceData)
{
vm.timesheet.sunday=resourceData[i].sunday;
vm.timesheet.monday=resourceData[i].monday;
vm.timesheet.tuesday=resourceData[i].tuesday;
vm.timesheet.wednesday=resourceData[i].wednesday;
vm.timesheet.thursday=resourceData[i].thursday;
vm.timesheet.friday=resourceData[i].friday;
vm.timesheet.saturday=resourceData[i].saturday;
vm.timesheet.resource=resourceData[i].saturday;
vm.timesheet.resource=resourceData[i];
Timesheet.save(vm.timesheet,onSaveSuccess, onSaveError);
}
this is my timesheet.service.js
(function() {
'use strict';
angular
.module('timesheetApp')
.factory('Timesheet', Timesheet);
Timesheet.$inject = ['$resource', 'DateUtils'];
function Timesheet ($resource, DateUtils) {
var resourceUrl = 'api/timesheets/:id';
return $resource(resourceUrl, {}, {
'query': { method: 'GET', isArray: true},
'save': {
method: 'POST',
isArray: false,
transformRequest: function (data) {
alert("123");
var copy = angular.copy(data);
return angular.toJson(copy);
}
}
});
}
})();
You might have to write a recursive function, depending upon the promise returned.
Timesheet.save(vm.timesheet,onSaveSuccess, onSaveError);
This returns a promise which calls you onSaveSuccess method.
in the function
function onSaveSuccess(){
// Need some recursive logic
}
Or try to implement this answer.
Need to call angular http service from inside loop and wait for the value of the service to return before executing code below call
Related
I'm developing an app with the following node.js stack: Express/Socket.IO + React. In React I have DataTables, wherein you can search and with every keystroke the data gets dynamically updated! :)
I use Socket.IO for data-fetching, so on every keystroke the client socket emits some parameters and the server calls then the callback to return data. This works like a charm, but it is not garanteed that the returned data comes back in the same order as the client sent it.
To simulate: So when I type in 'a', the server responds with this same 'a' and so for every character.
I found the async module for node.js and tried to use the queue to return tasks in the same order it received it. For simplicity I delayed the second incoming task with setTimeout to simulate a slow performing database-query:
Declaration:
const async = require('async');
var queue = async.queue(function(task, callback) {
if(task.count == 1) {
setTimeout(function() {
callback();
}, 3000);
} else {
callback();
}
}, 10);
Usage:
socket.on('result', function(data, fn) {
var filter = data.filter;
if(filter.length === 1) { // TEST SYNCHRONOUSLY
queue.push({name: filter, count: 1}, function(err) {
fn(filter);
// console.log('finished processing slow');
});
} else {
// add some items to the queue
queue.push({name: filter, count: filter.length}, function(err) {
fn(data.filter);
// console.log('finished processing fast');
});
}
});
But the way I receive it in the client console, when I search for abc is as follows:
ab -> abc -> a(after 3 sec)
I want it to return it like this: a(after 3sec) -> ab -> abc
My thought is that the queue runs the setTimeout and then goes further and eventually the setTimeout gets fired somewhere on the event loop later on. This resulting in returning later search filters earlier then the slow performing one.
How can i solve this problem?
First a few comments, which might help clear up your understanding of async calls:
Using "timeout" to try and align async calls is a bad idea, that is not the idea about async calls. You will never know how long an async call will take, so you can never set the appropriate timeout.
I believe you are misunderstanding the usage of queue from async library you described. The documentation for the queue can be found here.
Copy pasting the documentation in here, in-case things are changed or down:
Creates a queue object with the specified concurrency. Tasks added to the queue are processed in parallel (up to the concurrency limit). If all workers are in progress, the task is queued until one becomes available. Once a worker completes a task, that task's callback is called.
The above means that the queue can simply be used to priorities the async task a given worker can perform. The different async tasks can still be finished at different times.
Potential solutions
There are a few solutions to your problem, depending on your requirements.
You can only send one async call at a time and wait for the first one to finish before sending the next one
You store the results and only display the results to the user when all calls have finished
You disregard all calls except for the latest async call
In your case I would pick solution 3 as your are searching for something. Why would you use care about the results for "a" if they are already searching for "abc" before they get the response for "a"?
This can be done by giving each request a timestamp and then sort based on the timestamp taking the latest.
SOLUTION:
Server:
exports = module.exports = function(io){
io.sockets.on('connection', function (socket) {
socket.on('result', function(data, fn) {
var filter = data.filter;
var counter = data.counter;
if(filter.length === 1 || filter.length === 5) { // TEST SYNCHRONOUSLY
setTimeout(function() {
fn({ filter: filter, counter: counter}); // return to client
}, 3000);
} else {
fn({ filter: filter, counter: counter}); // return to client
}
});
});
}
Client:
export class FilterableDataTable extends Component {
constructor(props) {
super();
this.state = {
endpoint: "http://localhost:3001",
filters: {},
counter: 0
};
this.onLazyLoad = this.onLazyLoad.bind(this);
}
onLazyLoad(event) {
var offset = event.first;
if(offset === null) {
offset = 0;
}
var filter = ''; // filter is the search character
if(event.filters.result2 != undefined) {
filter = event.filters.result2.value;
}
var returnedData = null;
this.state.counter++;
this.socket.emit('result', {
offset: offset,
limit: 20,
filter: filter,
counter: this.state.counter
}, function(data) {
returnedData = data;
console.log(returnedData);
if(returnedData.counter === this.state.counter) {
console.log('DATA: ' + JSON.stringify(returnedData));
}
}
This however does send unneeded data to the client, which in return ignores it. Somebody any idea's for further optimizing this kind of communication? For example a method to keep old data at the server and only send the latest?
I'm trying to write a server in node, and I am taking data from a SQL database, I have another function that does that, but inside this function I have that list of data (thisData). In my server I need to query another server (offsite) to get a status update, update objects in the list based on this, and then respond with the JSON data.
I've been working on this for a long time and tried to find solutions based on other answers on here and I've yet to find something. I was originally trying to do this with just callbacks, but now I'm trying to do it with Promise.all()
I have my object thisData, it is a list of three "areas" which each contain a list of objects.
Both of these code snippets are inside a standard listener function for the standard http lib:
var server = http.createServer((request, response => {...
Immediately inside this function I also have a call to get the data:
getData(function(Data){
thisData = JSON.parse(data);
all the code snippets are inside this getData which is inside my listener function.
I also have a function that returns a promise to do the async web query:
var statusRequest = function(myArea, obj){
var url = 'https://www.example.com/data/' + obj.id + '/mode.json';
var options = {
method: 'GET',
uri: url,
strictSSL: false,
headers: {
'Authorization': config.auth_key,
'Accept': "application/json",
}
}
return new Promise((resolve, reject) => {
request(options, function (err, body, resp) {
var status = JSON.parse(resp).mode;
if (status == "success") thisData[area][obj.col].status = 0;
else if (status == "fail") thisData[area][obj.col].status = 1;
else thisData[area][obj.col].status = -1;
resolve(thisData[area][obj.col].status);
});
});
}
Then I have a loop that traverses the areas and objects, and I add each promise to a list and call Promise.all(), then I respond with the updated list:
var promises = [];
Object.keys(thisData).forEach(function(area){
for (var col = 0; col < thisData[area].length; col++){
promises.push(statusRequest(area, thisData[area][col]));
}
});
Promise.all(promises).then( (val) => {
console.log(val);
response.end(JSON.stringify(thisData));
});
I was initially having problems with all the promises resolving when col == thisData[area].length, and so I passed the actual object (which contains its own column information) into the statusRequest function so it shouldn't matter if the col variable changes.
The problem I'm having is that my console prints the correct status, but my JSON response does not contain the correct status, in fact it seems as though none of them are updating.
I would really appreciate any help, thanks in advance!
Hi Am doing an automation using PhantomJS combined with nightmare, I need to make a DB call once my UI automation via nightmare is executed am making use of the evaluate function of nightmare to make the DB call what i expected was that the call will be made synchronously but what actually happens is that my DB function is triggered first before the UI automation execution gets completed as a result am passing incorrect data for DB verification .
Below is a sample of ma code
exports.rejectProcess = function (testData, resultfolder, ConnectionStrings) {
"use strict";
return function (nightmare) {
nightmare
.waitForEnable('#Process')
.click('#Process')
.wait()
.waitForNotVisible('div.spinnerFullLight')
.waitForEnable('#createProcess')
.click('#createProcess')
.wait()
.click('#ContinueBtn')
.wait()
....etc
.evaluate(
function ()
{
var element = document.querySelector('#ProcessNumber');
return { data: element.value }
},
function (result) {
nightmare
.waitForEnable("#spanDashBoardArrowd")
.click("#spanDashBoardArrowd")
.waitForVisible("#topNavdropdownSubMenu")
.click("#navApprovals")
.wait()
...etc
.click("#Reject")
.evaluate(function () { nightmare.wait(60000);},valuateDB(testData, ConnectionStrings, result.data))
})
}
};
function valuateDB(testData, ConnectionStrings,concessionNumber)
{
console.log(concessionNumber);
var ApprovalInfo = dataOperation.getRejectStatus(testData, ConnectionStrings, concessionNumber); ------->place where i make the DB call
console.log(ApprovalInfo);
}
I am using MEAN (Mongo Express Angulars NodeJs) for a project. The problem is I have to add one extra attribute to data received from query object. And make new data array with exactly old data array but have one extra attribute. I know how to add attribute and pass them into callback using waterfall model, as I am using multiple callback functions and for loops I am not able to get expected result.
code:
var fetchRevenue = function(restaurantArray, type, startDate, endDate, fn) {
_.forEach(restaurantArray, function(rest) {
fetchDateWiseReport(new Date('07/10/2015'), new Date('07/16/2015'), rest._id, type, function(orders) {
var newOrders = [];
async.waterfall([
function(callback) {
if(orders && orders.length > 0){
async.forEach(orders, function(order) {
getSellingPriceOfItems(order.orders, function(sp) {
order.sp = sp;
newOrders.push(order);
if (newOrders.length === orders.length)
callback(null, newOrders);
});
});
} else {
newOrders.push([]);
}
},
function(newOrders, callback) {
var restArr = []
//get sum of all orders of each restaurant and add into restArr
callback(null, restArr);
},
function(restArr, callback) {
callback(null, newOrders);
}
], function(err, result) {
fn(result);
});
});
});
};
where my functions:
fetchDateWiseReport = fetches restaurant record for given date and send result in callback
getSellingPriceOfItems = query to item model find price for each item and return selling price of given array and send result in callback.
my complete code including all functions is here.
now I want orders should be equal to newOrders with additional attibute 'sp'. But I am unable to get this. Will you suggest me something to proceed?
Use Express way to handle callback problem
in you route
app.get('you/route',fetchDateWiseReport(), second(),finalReturningREsult())
your first function will be doing first async loop function assiggn reult in req.body.firstResult and pass to second function. and so on
How can I callback two function in node?
For example:
request('http://...',[func1,func2])
Is there any module for that?
Is there some reason you can't put a wrapper around the two functions, then use the wrapper as a callback? For example:
function handleCallback(data)
{
func1(data);
func2(data);
}
request('http://...',handleCallback);
As noted in other answers it's trivial to wrap multiple functions in a single callback. However, the event emitter pattern is sometimes nicer for handling such cases. A example might be:
var http = require('http');
var req = http.request({ method: 'GET', host:... });
req.on('error', function (err) {
// Make sure you handle error events of event emitters. If you don't an error
// will throw an uncaught exception!
});
req.once('response', func1);
req.once('response', func2);
You can add as many listeners as you like. Of course, this assumes that what you want your callbacks to be registered on is an event emitter. Much of the time this is true.
You can create a little module for that:
jj.js file:
module.exports.series = function(tasks) {
return function(arg) {
console.log(tasks.length, 'le')
require('async').eachSeries(tasks, function(task, next) {
task.call(arg)
next();
})
}
}
example of use:
var ff = require('./ff.js')
function t(callback) {
callback('callback')
}
function a(b) {
console.log('a', b)
}
function b(b) {
console.log('b', b)
}
t(ff.series([a, b]))