Cannot make an array by multiple Restangular responses - angularjs

I am using Angular and have to populate a table and for this i need an array which has values by multiple calls to server.
I have following scenerio
Angular Controller:
var application={};
var data-[];
$scope.tableData=[];
Restangular.all("a").getList().then(function(arr1){
for(var i=0;i<arr1.length;i++)
{
application.app=arr1[i];
Restangular.one("b",arr1[i].id).get().then(function(obj1){
application.obj1=obj1;
});
Restangular.one("c",arr1[i].id).get().then(function(obj2){
application.obj2=obj2;
});
data.push(application);
application={};
if(i==arr1.length-1){
$scope.tableData=data;
}
}
});
Now the table in view shows row equal to length of arr1 and also shows the data in arr1 but the data by other Restangular calls are not attached with that array except last iteration.
OnlyiIn last iteration the array is fully made including arr1,obj1,obj2 other array indexes r missing obj1 n obj2.
This is because of async behaviour of Restangular response but cannot understand how to handle it.
Note:
(Expected result)
data[
{
app:{
app_id:1,
status:1
},
obj1:{
name:"user1",
gender:"male"
},
obj2:{
telephone:"63532367",
address:"abc"
}
},
{
app:{
app_id:2,
status:1
},
obj1:{
name:"user2",
gender:"female"
},
obj2:{
telephone:"63532367",
address:"xyz"
}
},{
app:{
app_id:3,
status:1
},
obj1:{
name:"user3",
gender:"female"
},
obj2:{
telephone:"63532367",
address:"xyz"
}
}
]
(Current Result)
data[
{
app:{
app_id:1,
status:1
}
},
{
app:{
app_id:2,
status:1
}
},
{
app:{
app_id:3,
status:1
},
obj1:{
name:"user3",
gender:"female"
},
obj2:{
}
}
]

Restangular is async (all the Restangular.one() is left before the callback you pass to .then). That's why Promises is used.
Even if it would be possible to make Restangular to be sync you shouldn't do that because this will block the browser until the data is requested which will be a bad user experience.
You should try to get into Promise as they were designed to look like sync code but behave async.
You can try something like this:
var a = Restangular.all("a").getList().then(function(arr1){
// Some modification of the backend data response
return modifiedData; // Now this should be passed to each of those Restanngular.one() methods sequentially
});
Above code will return the Promise that is returned by the .then call, which can be chained as following concept:
(new Promise(function( resolve, reject){
$timeout(function() {
resolve("some");
});
}))
.then(function(data) {
return data+' data';
})
.then(function(data) {
return new Promise(function(resolve, reject) {
$timeout(function() {
resolve(data+' !!!!!!');
});
});
})
.then(function(data) {
// this will have 'some data !!!!!!'
console.log(data);
});

Related

elasticsearch with angularjs no matter what I search, it always hits all data in the database

Question about Querys in AngularJs with Elasticsearch.
If I just use Kibana, the result of this will be 10 hits, which is make sense.
POST /_search
{
"query": {
"match": {
"fieldname": "Obama"
}
}
}
If I use q parameter like the official APIs describe:enter image description here
I will also get the answer by using
newsApp.controller('searchCtrl', function ($scope, client) {
$scope.searchFunc = function(){
client.search({
q: "fildname: Obama""
});
});
It will also be fine.
But when I need more:
newsApp.controller('searchCtrl', function ($scope, client) {
$scope.searchFunc = function(){
//I have tried this:
client.search({
"query": {"match": {"fieldname" : "Obama"}}
});
//I have tried this:
client.search(
{
body: {
query: {
match: {
fildname: "Obama"
}
}
}
});
});
Then I could only get Nothing. So I don't know what kind of query I could really use??
enter image description here
Try to add index and use the same the query format. see logs in callback function
client.search({
index: 'myindex',
q: 'title:test'
}, function (error, response) {
// ...
});

request timeout in node application

The request I make to my node api takes more than 4 minutes to respond. While the time the response is received. The angular app does not accept the response. On firebug, the url turns red.
How can I overcome this.
api.route('/allsearch')
.post(function(req,res){
var filters=req.body.everything;
var filterid=req.body.filterId;
var searchid=req.body.searchid;
var zipgroup=req.body.zipgroup;
var myObject = new Array();
function getData(docs, filters, filterid, callback) {
function loop(i) {
searchingalgo(docs[i], filters, filterid, function(pers){
myObject[i] = pers;
if (i < docs.length) {
loop(i + 1);
} else {
callback();
}
});
};
loop(0);
};//closing get data()
Searchradius.findOne({"searchid" : searchid, user: req.decoded.id}).exec(function(err, docs) {
// Array to hold async tasks
var asyncTasks = [];
// Loop through some items
zipgroup.forEach(function(item){
// We don't actually execute the async action here
// We add a function containing it to an array of "tasks"
asyncTasks.push(function(callback){
// Call an async function, often a save() to DB
console.log(item);
searchingalgo(item, filters, filterid, function(pers){
myObject[item] = pers;
// Async call is done, alert via callback
callback();
});
});
});
Async.parallel(asyncTasks, function(){
//console.log(myObject);
Searchradius.update({ _id: searchid }, { $set: { ucounteds: myObject , uzips: zipgroup }}, function(err, result){
if(err) {
res.send(err);
return;
}
var fields = ['city', 'state', 'zip','distance', 'count'];
var myresults = [];
var tc=0;
var newMyobj= new Array();
co=0;
zipgroup.forEach(function(item){
tc+=myObject[item];
//myresults.push(jobj);
});
for(i=0;i<zipgroup.length;i++){
newMyobj[i]=myObject[zipgroup[i]];
}
console.log(tc);
Searchfilter.update({ _id: filterid }, { $set: { counted_results: tc }}, function(err, resultupdate){
//console.log(resultupdate);
//console.log(tc);
});
// console.log(myObject);
// console.log(newMyobj);
res.json({
success: true,
zips: zipgroup,
states: docs.states,
cities: docs.cities,
distances: docs.distances,
counted_results : newMyobj,
});
}); //update searchradius
}); //getdata function
}); //searchradius findone
});
As requested, this is my node API. the zipgroup is a array of zips like
[37663, 37664, 37669, 37671, 37660, 37669, 37667, 37668, 37666, 37665, 37662, 37661]
Just to be clear the collection Consumer1s has more than 2900009876 documents. It is indexed properly and the query is taking the least time possible. But I am still facing this problem.
Any suggestions would be helpful.
This is my post request from angular controller.
$http.post('/api/allsearch',
{
"everything":$scope.filterSearch ,
"searchid":$routeParams.id,
"filterId": $scope.filterId,
"zipgroup" : $scope.zipgroup
})
.success(function(data){
for(var i=0; i<data.zips.length;i++){
oneset={
"zip": data.zips[i],
"state": data.states[i],
"city": data.cities[i],
"distance": data.distances[i],
"count": data.counted_results[i]
};
$scope.totalCount+=data.counted_results[i];
$scope.results.push(oneset);
}
angular.forEach($scope.results, function (result) {
result.distance = parseFloat(result.distance);
});
$rootScope.processing=false;
$scope.filterlinkdisplay=true;
});
There are at least several options:
set AngularJS $http timeout for 10 mins or so, so that AngularJS request doesn't time out, waiting for 4 mins to get the data
polling: 1) AngularJS app does initial request 2) Node.js server issues a unique token to AngularJS app for this request and starts working on collecting data 3) AngularJS app waits for several mins and does a request with previously received token to get data 4) If result is ready, you're done. If not, wait again and do another request from AngularJS
use WebSocket. On client side it is supported by many browsers, on server side use ws. It's a bi-directional protocol, so server can notify clients when data is ready.

unable to display the http get response from the factory in controller in Angularjs application

In my service I making http get request as shown below:
.factory('InvoicesGeneralService', function ($http) {
return {
getAgreementsByCourierId: function (courierId) {
console.log("Courier in Services" + courierId);
return $http.get('/api/agreements/byCourierId', {params: {courierId: courierId}}).then(function (response) {
return response;
});
}
};
});
And in browser console I am seeing the following response :
[
{
"id":3,
"number":"AGR53786",
"ediNumber":"EDI7365",
"startDate":"2012-09-02",
"endDate":"2018-07-01",
"courier":{
"id":2,
"name":"FedEx",
"url":"www.fedex.com",
"isActive":true,
"isParcel":true
},
"client":{
"id":4,
"code":"KJGTR",
"name":"Hearty",
"isActive":true,
"engageDate":"2011-07-07",
"isSendRemittance":true,
"upsUserName":"Tkd",
"upsPassword":"kuu",
"isEligibleForTracking":true,
"isEligibleForAuditing":true,
"status":5
}
}
]
And in my controller I am assigning it to result List :
$scope.resultList = InvoicesGeneralService.getAgreementsByCourierId(selCourierId);
But my resultList is always appearing as Empty. Can any one help me, why it is happening?
When I am trying to display resultList as shown below, it always shows empty object, {}. It supposed to display the response json array from the service but it is showing empty object.
<pre class="code"> {{resultList | json}}</pre>
$http returns a promise. Anything consuming that data needs to handle it like a promise too.
InvoicesGeneralService.getAgreementsByCourierId(selCourierId).then(function(data) {
$scope.resultList = data;
});
Also, your factory's then function is not doing anything at the moment. You should return the response's data from it.
return $http.get('/api/agreements/byCourierId', {params: {courierId: courierId}}).then(function (response) {
return response.data;
});

Passing 'filter' parameter to angular resource (DreamFactory rest api)

I am having an issue with query parameters from my AngularJS app
I am reading documents from MongoDB using DreamFactory rest api like this:
.service('Servant', ['$resource', function($resource) {
// define and return $resource
return $resource('https://mydsp.cloud.dreamfactory.com:443/rest/mongodb/tablename',
{
// set params to bind too
app_name: 'myapp',
fields: '#fields',
limit: '#limit',
offset: '#offset',
filter: '#filter'
},
{
// set update method to 'PUT'
update: {
method: 'PUT'
}
}
)
}]);
This all works great when I set filter like "parameter=value" but I failed to find a way of passing more complicated filter param in JSON format as described here, using $in parameter etc. Does anyone know the right syntax for this?
EDIT:
just tried something like
filter = angular.toJson("{'parameter':{$in:['value1','value2']}}")
with no success...
First...drop the port from your service url. 'https' for dreamfactory specifies port 443. No need for you to do it explicitly. Second...You should be able to pass a SQL style filter as a string in your params. When you set up your $resource the way you have you should be able to pass a params object to it. No need to stringify or toJson anything. DreamFactory should handle it. For example...
Here is your service:
.service('Servant', ['$resource', function($resource) {
return $resource('https://mydsp.cloud.dreamfactory.com/rest/mongodb/tablename',
{
app_name: 'myapp',
fields: '#fields',
limit: '#limit',
offset: '#offset',
filter: '#filter'
},
{
update: {
method: 'PUT'
}
}
}]);
Calling that service with a params object:
// the 'parameter' value in our filter string should relate to a field and/or property
scope.paramsObj = {
fields: '*',
limit: 10,
offset: 0,
filter: 'parameter in (5,15)'
}
// call service and handle promise returned by $resource
Servant.get(scope.paramsObj).then(
function(result) {
// handle success
// like assign to a var or something
// here we just log it
console.log(result)
},
function(error) {
// handle error
// probably should throw an error here
// but we just log it here
console.log(error);
});
EDIT
Ok. So...it should work with SQL style filter strings. An issue has been logged with DreamFactory. In the mean time you can create a custom $resource action to handle the filters and tunnel your GET request through a POST. Easier then it sounds. See code below.
Here is the service with custom action
.service('Servant', ['DSP_URL', '$resource', function (DSP_URL, $resource) {
return $resource(DSP_URL + '/rest/mongohq/Colors', {
// params to bind to
app_name: YOUR_APP_NAME_HERE,
fields: '#fields',
limit: '#limit',
offset: '#offset'
}, {
// custom $resource action
'getFiltered': {
// set our method to post because we have to post
// our filter object
method: 'POST',
// We can transform the data before the post.
// In the circumstance we do need to stringify
// So that's what we do here.
transformRequest: function (data) {
return JSON.stringify(data);
}
}
})
}]);
Here is the controller:
.controller('MongoCtrl', ['$scope', 'Servant', function ($scope, Servant) {
// Create a params object
// This requests all fields.
// And we explicitly set the method to
// GET. We are tunneling a GET request
// through our POST because our filter
// needs to be posted but we really want a GET.
$scope.params = {
fields: '*',
method: 'GET'
};
// Call our Service with our custom $resource action
Servant.getFiltered(
// Send our params
$scope.params,
// Send our filter as post data
{
"filter": {
"color": {
"$in": ["blue", "white"]
}
}
},
// handle success
function (data) {
console.log(data)
},
// handle error
function (error) {
console.log(error)
})
}])
I guess you should stringify your filter data:
resource.update( {
filter: JSON.stringify( {qty:{$in:[5,15]}} )
});
Or in this way:
resource.get({id:123}, function() {
resource.filter = JSON.stringify( {qty:{$in:[5,15]}} );
resource.$update();
});

Backbone.js model: overwriting parse for custom API

In Backbone.js, I'm working with an API which wraps the response in a meta and data hash. For example:
# GET /api/posts/1
meta: {
status: 200
},
data: {
id: 1
title: 'Hello World'
}
# GET /api/posts
meta: {
status: 200
},
data: [
{
id: 1
title: 'Hello World'
},
{
id: 2
title: 'Hi everyone!'
}
]
My Backbone.js Collection/Models have the following parse function overwritten:
# App.Models.Post
...
parse: function (response) {
this.meta = response.meta;
return response.data;
}
# App.Collections.Posts
...
parse: function (response) {
this.meta = response.meta;
return response.data;
}
However, when I fetch on the collection posts = new App.Collections.Posts(); posts.fetch(), the post attributes are all empty. I.e. posts.at(0).get('title') = undefined.
Now, this is fixed when the Model parse is changed to:
parse: function (response) {
return response;
}
But this means that post.fetch() is broken.
Any suggestions?
Thanks!
I think the problem is that your model's parse is getting inconsistent data passed into it when done via model fetch vs collection fetch. console.log the argument to model parse to confirm this. This is because the value return by collection's parse is just an array of object data and to convert those to models, the collection just delegates to the model's parse method. This might fix your issue:
//App.Models.Post
parse: function (response) {
if (response.data) {
return response.data;
}
return response;
}
For reference: https://github.com/documentcloud/backbone/pull/773

Resources