Get single item from a collection in angularjs - angularjs

I'm new to AngularJS and need to consume a REST API. I can successfully load the collection of projects from the server using two different ways, but I fail to get a single project from this list (after it's been populated) by its id. I do not want to get the item again from the server.
When I try with angularjs-rails-resource, I can get the list of items using Project.query()and store it in $rootScope.projects. However I now wonder how to get an item out of this list by its id (actually it's not an array but a promise)?
I also tried with restangular using $rootScope.projects = Restangular.all("projects").getList() and project = $rootScope.projects.get(id). But this also fails, because it seems to return a collection and not a single item...?!

For angularjs-rails-resource you should be able to just use get(id). It will always return a promise which is fine if you're using it in your template because templates understand promises.
If you don't want a promise, you can use then
Project.get(1234).then(function (project) {
//project is NOT a promise
$scope.project = project;
});
rather than
//project is a promise, but you're template is cool with that
$scope.project = Project.get(1234);

In order to return single item use:
$scope.project = Project.get(id: some_id);

Related

Adding additional data from server to existing restangular collection

What is the right way to add more data in to an existing collection with Restanglar?
Currently on page load I am performing:
app.factory('Post', ['Restangular', function(Restangular) {
return Restangular.service('posts');
}]);
var Posts = Post.getList({embed:'comments.replies,tags', limit:'50'}).$object;
$scope.posts = Posts;
This gets my initial bunch of posts nicely.
On the front end the user can then select a tag which filters the results, and I want to load up some more from the server for the specific tag. Currently I am replacing the existing posts with:
Posts = Post.getList({embed:'comments.replies,tags', limit:'100', tag:tag.name}).$object;
$scope.posts = Posts;
The data is coming back great from the API. What is the best practice way to push the data in to the exiting/original Restangular collection?
Ideally I want to keep adding to this collection, merging the result so that there are no dupes.
Is there a Restangular method that is used to merge as it seems a common use case. (Could be used for loading additional paginated data too.)

AngularJS $resource management

I am trying to find a clean way to manage my $resource models in my application. I have some RESTful endpoints for a template model:
GET /api/templates/ //query all template
GET /api/template/:id // get single template by id
PUT /api/template/ // create a new template
PATCH /api/template/:id // update a template
DELETE /api/template/:id // delete a template
var TemplateResource = $resource('/api/templates/:templateId', {templateId:'#id'}, {
'create':{method:'PUT'}
})
I can simply run
var templates = TemplateResource.query(function(){
console.log(templates) // an array of template models
}
Once I have the list in memory, I use an Angular service to keep the list in state and consecutive calls just return the list rather then making the call again.
Now my question is regarding how to manage a single template. If the user goes to the "Edit Template" view, then saves the template I run template.$save() to run a POST on the template. The problem is that this template is seperate from the list that was pulled in from the query, so the list doesn't get updated in the UI.
Should I stem all my single template requests from my list of templates? (meaning I never actually call GET /api/template/:id, instead I just always find the template in the list)
OR
Should I just continue to run individual calls on the template, and when the POST request comes back, I just "update" the current list of templates with the updated model.
Let me know if I should provide more info about something

Angular CRUD, update view when backend/database changes ($resource and REST)

I am currently making an application in angular which does this:
(On page load) Make an api call in angular controller (to symfony2 end point) to get: items.
$scope.items = ItemsService.query(function(data){
$scope.loading = false;
}, function(err){
$scope.loading = false;
});
items is an array containing many item objects.
Each item contains parameters e.g. item.param1 item.param2.
I have built it in a similar way to this tutorial:
http://www.sitepoint.com/creating-crud-app-minutes-angulars-resource/
i.e. The angular controller calls a service which calls the (symfony2) backend api endpoint.
The endpoint passes back items which is gets from a database. Items are then put into the view using ng-repeat (item in items).
This all works fine.
Now, I have a button (in the ng-repeat) which effectively causes a PUT request to be made to (another symfony2 endpoint), thus updating item.param1in the database. This also happens in the tutorial I linked to.
The problem is that (in my application and in the tutorial) I have to again make an api call which updates ALL the items, in order to see the change.
I want to just update the data in the view (immediately) for one object without having to fetch them all again.
i.e. something like:
$scope.items[4] = Items.get({id: item.id}, function(){});
Except the application array key isn't known so I cant do that.
(so something like: $scope.items.findTheOriginalItem(item) = Items.get({id: item.id}, function(){});.
Another possible solution (which seems like it may be the best?). I have looked here:
http://teropa.info/blog/2014/01/26/the-three-watch-depths-of-angularjs.html
And tried doing the equality $watch: $scope.$watch(…, …, true);. Thus using watch to see when the item sub-array is updated. This doesn't seem to update the data in the view though (even though it is updating in the database).
Any advice on the best way of doing this (and how to do it) would be great! Thanks!
Essentially the button click should use ng-click to execute a function and pass the item to that function. Example:
...ng-repeat="item in items"...
<button type="button" ng-click="updateItem(item)">Update</button
...
Then in the function you have the exact item that you want to update. If you are using $resources, it would be something like:
$scope.updateItem = function(item) { item.$update(...); };
Unless I didn't understand you

AngularFire objects

I've been playing with AngularFire, and I understand the documentation for collections. But I feel like I'm totally missing things when it comes to loading specific items inside the collection, by anything besides position in the array.
All of the examples in the Firebase data have pretty names for the api like user/name/first
But when I use angularFireCollection to save a collection I get my object inside a unique $id. (not as pretty)
Is that the expected behavior? And if so, how would I get() an item based on a value instead?
ex. I created a key called slug. That has 'my-theme' in the collection. And I want to load it by $routeParams.
.when('/themes/:slug/', {
templateUrl: 'views/theme.html',
controller: 'ThemesCtrl'
})
How would I load an object into themes/my-theme instead of themes/-J50neNBViK9l7P4QAYc
Thanks in advance...
angularFireCollection automatically creates a list of items with auto-generated incremental IDs (generated by Firebase's push() method). If you want to create a list of items with custom names, angularFire might be a better service to use (it uses set instead of push). For example:
function ThemesCtrl($scope, angularFire) {
$scope.themes = {};
angularFire(new Firebase(URL), $scope, 'themes');
$scope.addTheme = function() {
$scope.themes["my-theme"] = $scope.currentTheme;
}
}

How to refresh local data fetched using $resource service in AngularJS

I have AngularJS application that use $resource service to retrieve data using query() method and create new data using model.$save() method. This works fine exactly as the docs say it should.
My question is how to update my local data fetched using MyService.query() in the first place after I've changed it?
I took the most simple approach for now and I simply call the query() method again. I know this is the worst way efficiency-wise but it's the simplest one.
In my server-side I return the whole state-representation of the new model. How can I add the newly created model to the array of the local data?
UPDATE
I've end up simply pushing the model return from the server but I'll still be happy to know if that's the way to go. From what I can understand from the source code the return array is plan-old-javascript-array that I can manipulate myself.
This is the code I used
$scope.save = function () {
var newComment = new CommentsDataSource();
newComment.Content = $scope.todoText;
newComment.$save({ id: "1" }, function (savedComment) {
$scope.comments.push(savedComment);
});
}
I would simply get the whole list again, to be able to see the modifications brought to the list by other users.
But if the solution you're using suits you, then use it. It's corrrect. Angular uses bare-bones JavaScript objects. Adding a new instance to a list in the scope will refresh the list displayed on the page.

Resources