Backbone.js model: overwriting parse for custom API - backbone.js

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

Related

$resource PUT operation not extracting id

I can't seem to get an "id" to come through to the $resource function from the controller. Here is the offending code...
Controller:
$scope.update_user_extra = function () {
UserExtraResource.update($scope.user_extra_details, function (data) {
$scope.user_extra_details = data;
$scope.user_extra_details = {mobile:data.mobile,
landline:data.landline,
position:data.position,
notes:data.notes,
language:data.language};
});
};
Resource:
module.exports = function ($resource) {
return $resource('/api/user_extra/:id/', { id: '#_id' }, {
details: {method: 'GET', url: '/api/user_extra/details'},
update: {method: 'PUT'}
});
};
The GET works fine but the custom PUT returns:
http://127.0.0.1:8000/api/user_extra/ 404 (Not Found)
hardcoding the id like:
return $resource('/api/user_extra/1/', { id: '#_id' }, {
works fine. Any help is much appreciated!!
hmm ... changing this line to:
return $resource('/api/user_extra/:id/', { id: ̶'̶#̶_̶i̶d̶'̶ '#id' }, {
seems to have done it. Thank you very much!
If the default parameter value is prefixed with #, then the value for that parameter will be extracted from the corresponding property on the data object. For example, if the defaultParam object is {someParam: '#someProp'} then the value of someParam will be data.someProp.
In the above question, the PUT operation was trying to extract the property _id of the data object when the name of the property was actually id.
For more information, see AngularJS $resource API Reference.

How to modify angular $http.get().then response invalid JSON to valid JSON

We need to implement type ahead functionality in inbox box ,but when we got response from $http get is invalid JSON so that i cant able do that.
below method i am using for view level
uib-typeahead="name for name in collections ($viewValue)"
Angular:
$scope.collections = function(val) {
return $http.get('/Documents/DocumentsList/', {
params : {
stk : val
}
}).then(
function(response) {
if (response.data.suggestions) {
$("[uib-typeahead-popup].dropdown-menu").css('display','block');
return response.data.suggestions
.map(function(item) {
return item.term;
});
};
});
};
JSON Response:
{} && {
"name": "John",
"age": 31,
"city": "New York"
}
How to modify the invalid JSON to valid JSON and pass the valid response in then.
It would be better to fix the problem at the source but, if you can't do that, implement your own response transformer
return $http.get('/Documents/DocumentsList/', {
params: { stk: val },
transformResponse: function(data) {
return angular.fromJson(data.substring(6));
}
})...

Cannot make an array by multiple Restangular responses

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);
});

Backbone fetch single model attributes

im trying to fetch a single Models attributes. I use this model as kind of a config file for an app im currently building. But i cant get my head around how to get the attributes in a nice way.
The model looks like this:
WelcomeModel = Backbone.Model.extend({
url: "assets/json/config.json",
parse: function (response) {
return response.data;
}
});
The json looks liks this:
{
"data": [{
"companyName": "lorem ipsum",
"companyLogo": "loremipsum.png"
}]
}
And in my view i fetch it like this.
this.model = new WelcomeModel();
this.model.fetch({
success: function(model,response) {
console.log(model);
},
error: function() {
console.log('error')
}
});
1) parse method returns array instead object. Replace
return response.data
with
return response.data[0];
2) add defaults hash to your WelcomeModel model.
defaults: {
companyName: '',
companyLogo: ''
}

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();
});

Resources