How to Restangularize items in collection off parent object - angularjs

I am returning an object using Restangular over AngularJS (GPT object is the parent object being returned), with an array being returned corresponding to the projects withing the GPT.
I can do all the Restangular "stuff" like save() etc. on the parent GPT object. However, when I get a reference to individual items in the "projects" collection, I am unable to do a Restangular save() on it. How do I make sure all items returned in the collections below the main object are "Restangularised" so I can perform restful operations on them? i.e. I guess I want a "deep Restangularisation" if that makes sense ;-)...if not, how do I Restangularize an instance just before I attempt to do a save() operation and provide the relevant URL for the PUT/POST etc.
Hope this makes sense.
Regards
i

There is a Restangular.restangularizeElement method.
You can use it as follows (for collection):
Restangular.one('courses', 123).get().then(function (course) {
course.students = Restangular.restangularizeCollection(course, course.students, 'students');
// You should now be able to do 'course.students[0].remove()'
// And if you want to chain promises:
return course;
});
source

Related

Angularjs caching vs fetching live data

I have a service I'm using to fetch data for an application.
Since a service is a singleton, I'd like to cache some reference data in the service, but I'm not sure how to get that to happen.
I'm using Strongloop and right now have a function in the Service like this:
function fetchReferenceData() {
return refInfo.find().$promise;
}
I'd like to have a property where I store the reference data.
I could add a property in the code, like
var myRefData;
and then I could edit fetchReferenceData() to check that property, but since the client is expecting a promise back, this won't work:
function fetchReferenceData() {
if (myRefData) { return myRefData; }
else { return refInfo.find().$promise;}
}
What's a good programming pattern to work with this kind of thing?
Do I pass in a function to call in a .then() to set the data in the client?
If the client is expecting a promise, you can use the $q service to create a promise from your cached value.
function fetchReferenceData() {
if (myRefData) { return $q.when(myRefData); }
else { return refInfo.find().$promise;}
}
The client can access it with the standard .then method.
fetchReferenceData().then (function (myRefData) {
//use myRefData
});
Best practices
You need a way to destroy the information in your cache.
You need to avoid calling refInfo.find() again if a query is already in progress.
Update for ngResource objects
Methods from Angular $resource services return references to empty objects.
From the Docs:
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data. This is a useful trick since usually the resource is assigned to a model which is then rendered by the view. Having an empty object results in no rendering, once the data arrives from the server then the object is populated with the data and the view automatically re-renders itself showing the new data. This means that in most cases one never has to write a callback function for the action methods.
So you can cache the query reference but you need to be aware the data on it will be undefined for a period of time.
The $resource service also adds a $promise property that can be used by clients that accept a promise.
function fetchReferenceData() {
var cache;
return cache = cache || refInfo.find();
}
clientThatNeedsPromise(fetchReferenceData().$promise);

How to set an object to the updated value returned by Angular $resource?

How do you save an object to a $resource and then set the object to the API response value returned by the $resource?
I have an object, value (which is part of an array of objects I am iterating through), that I save to a ReST API.
When the save is successful, the API responds with same object, plus any extra details such as the object's id (if the save was a create) or perhaps the file paths that the back end saved to. Stuff the front end can't know about until the back end adds it.
I want to update the saved value object with those extra details returned in the response, but I can't figure out how to do it.
I have tried returning the response from the $resource callbacks, but I can't make it work. It returns a $$state object (which I don't know what to do with) rather than the response. I may be doing that wrong.
In any case I would rather set the value object to the response object inside the success callback, because I only want to set the object to the response when the save is successful, not when there's an error.
But I don't know how to pass the value object to the callback to be updated, which is the crux of my problem.
(And I can't figure out how search the array for the object from inside the callback because the $resource success response doesn't include the $$hashkey. Only the error response includes the $$hashkey. This approach seems like a kludge to me anyway)
Here is the basic pattern I am trying to use. I'm hoping someone will point out the flaw with the pattern, or show me how to pass value to the callbacks, or whatever. Ideally I'd like to know what the best practice pattern is for saving objects to a $resource and immediately updating them with the response data.
(Resource is the name I have given in this example to an Angular factory that returns a $resource object.)
function success(response) {
//I want to set value to response here, but value is out of scope
//so instead I do this but it returns $$state rather than response
return response;
}
function error(response) {
Status.reportError(response);
}
value = Resource.create(value)
.$promise.then(success, error);
I imagine I could find value somewhere in the $scope of the callback (?) but I'm trying avoid using $scope due to its pending deprecation.
Thanks in advance
Jay Dee
Should be like this:
Resource.create(value, function(success) {
value.id = success.id;//depends on what you return, may be success.data.id or similar
}, function(error) {});

Issue with performing a $save on a new resource in Angular JS

I am attempting to implement a sample application with Angular that interacts with a backend REST API using $resource objects. However, the backend system does not generate id's for the resources, so these need to be defined on the objects being created on the client. This causes a problem when invoking the $save method on the new'ed resource because it forces the JSON data to be POSTed to the wrong URL, i.e., it POSTs to:
/resources/employees/1234
rather than:
/resources/employees
I would prefer not to have to drop down to using the low level $http service if I can avoid it.
Does anyone know how I can work around this issue?
Thanks.
This is because of the fact that you configured your $resource constructor in this way, for example:
$resource('resources/employees/:employeeId', {
employeeId: #id
});
That means that when you call methods like $save or $delete etc. on the resource objects made by this constructor, the variable :employeeId in the url will be filled with the value id that exist on the object on which you called the method. To avoid this you have to modify the constructor config so that the url variable does not depend on the object id property.

Backbone PUT request explicitly with out using id

I'm trying to PUT the data and my model doesn't have an id.
Is it possible to explicitly tell the Save() method to PUT the data irrespective of ID.
The save method has an options parameter that can override anything on the XHR:
model.save(newVals, { type: 'PUT' })
You can also override the isNew method. PUT vs POST is determined by the result of that method. You'll also want to make sure the URL is being created correctly for new and non-new objects.
Also consider setting the idAttribute correctly so that your model does have an id field that can be used to generate a correct url. Using POST and PUT correctly (POST new items, PUT updates to items) makes your api more intuitive.

Why doesn't UnderscoreJS's _.extend() method copy AngularJS promises to the extended object?

Example:
$scope.post = Posts.get({id: id});
scope = _.extend({}, $scope);
alert($scope.post.id); // undefined
alert(scope.post.id); // exception - post is not defined
I feel that I'm doing something obviously wrong, but I can't figure out what. I expected it to shallowly copy the post reference to the new object:
alert($scope.post.id); // undefined
alert(scope.post.id); // undefined
$scope.post === scope.post; // true
This is from Angular documentation about ngResource
It is important to realize that invoking a $resource object method
immediately returns an empty reference (object or array depending on
isArray). Once the data is returned from the server the existing
reference is populated with the actual data. This is a useful trick
since usually the resource is assigned to a model which is then
rendered by the view. Having an empty object results in no rendering,
once the data arrives from the server then the object is populated
with the data and the view automatically re-renders itself showing the
new data. This means that in most cases one never has to write a
callback function for the action methods.
At the time when you are trying to extend the scope, your object is not fully there.
I hope that helps...

Resources