AngularFire objects - angularjs

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

Related

AngularJS: Move to next view and pass along object

I make a query to Parse.com to receive a lot of objects and then display all the objects in a view.
I now want to be able to click on one of the objects, which should load a new page where I can edit them.
My questions is, how do I pass one of the objects from the main view to a detail view where I can edit it?
When I tried:
With route, passing the whole object, but this seems like bad practice, and the whole object is printed out in the status bar:
// Route
.when('/job/:object', {
<a href="#/job/{{job}}" style=" ">
By just passing the objectId, and when query the database to get the object by it's id once the detail view is loaded.
.when('/job/:objectId', {
<a href="#/job/{{job.id}}" style=" ">
// Get Object by its ID from Parse.com.
Save the whole array of objects in the $rootScope in order to access them from the new detail controller.
Thanks in advance
as SSH said you need to create one angular service which can hold the object , and then when you move from one view to another simply inject the service and access the object.
Here is how you should do this.
.service('holdobj',function(){
var myobj;
this.set= function(obj){
myobj = obj;
};
this.get= function(){
return myobj;
};
});
now in your controller
.controller(function(holdobj){
$scope.setObject = function(obj){
holdobj.set(obj);
}
});
And then when you want to get object simply call holdobj.get();
You should save an incoming object in a service, and then use that service across different controllers
As long as you are using a shared controller between views I think you could probably set a model before you change the view.
I don't know if there is a way to pass model between controllers when checking router otherwise, without going the old-fashioned way and passing an id to the object, where the second controller would look it up based on that.

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

Backbone.js: Natively passing attributes to models when fetched with a collection

Let say you are defining a Backbone.js Model. From the documentation we have ...
new Model([attributes], [options])
This seems great for passing some default attributes to a model. When passed the model automatically inherits those attributes and their respective values. Nothing to do. Awesome!
On they other hand lets say we have a Collection of that model.
new Backbone.Collection([models], [options])
Okay, cool we can pass some initial models and some options. But, I have no initial models and no options I need to pass so let's continue. I am going to fetch the models from the server.
collection.fetch([options])
Well I don't have any options, but I want to pass some attributes to add to each models as it is fetched. I could do this by passing them as options and then adding them to the attributes hash in the initialize for the model, but this seems messy.
Is their a Backbone.js native way to do this?
You can pass the attributes as options to fetch and over-ride the collection's parse method to extend the passed options (attributes) on the response.
The solution would look like the following:
var Collection = Backbone.Collection.extend({
url:'someUrl',
parse:function(resp,options) {
if (options.attributesToAdd) {
for (var i=0;i<resp.length;i++)
_.extend(resp[i],options.attributesToAdd);
}
return resp;
}
});
Then to add attributes when you call fetch on the collection, you can:
var collection = new Collection();
collection.fetch({
attributesToAdd:{foo:'bar',more:'foobar'}
});
You may have to tweak the code a bit to work with your JSON structure, but hopefully this will get you started in the correct direction.

AngularJS custom model objects with methods?

When you have a JSON $resource how can you cast the resulting objects into more specific objects once obtained?
For example, right now they come back as an Array of Objects, but I want them to come back as an Array of "Appointment" objects, so that I can have some methods on that Appointment object which would answer questions about that Appointment object. Ex: Does This Appointment have any services associated with it? Is This appointment in the morning or afternoon?
At first I thought transformResponse hook would work from ngResource, but that doesn't appear to work. The return from that is not the actual objects. Seems that with that function you can only modify the actual data prior to the JSON parsing.
Finally, I question if this is even a proper angularJS technique? Or should these helper methods just show up in a controller or some other module and accept the object to work upon? I just think its cleaner to have them wrapped up in the object, but I admit that I'm not very experienced in angularJS.
If you're using a factory and want to add a function you can for example add the function to the prototype of the returned item (DEMO):
app.factory('Appointment', ['$resource', function($resource) {
var Item = $resource('appointments.json',{/*bindings*/},{/*actions*/});
Item.prototype.hasServices = function() {
if(this.services.length > 0) return true;
else return false;
};
Item.prototype.partOfDay = function() {
if(this.time.split(':')[0] > 12) return "afternoon";
else return "morning";
};
return Item;
}]);
And then access it on your resource in the controller:
$scope.appointments = Appointment.query({}, function() {
console.log($scope.appointments[0].partOfDay())
});
Or directly in the view inside for example an ng-repeat:
{{appointment.partOfDay()}}
To answer your last question, I think the above solution is a proper angularjs technique.
As soon as you have functions associated with a specific resource type it's in my opinion the best to directly append them to the respective resource object. Why should you create helper functions in the controller when you have to pass the resource as a parameter and additionaly the functions may be used in multiple controllers or scopes?!

push data from one controller to another, $resource service

I'm using angular routing for a SPA with a sidebar (on index.html) that loads a list of categories from a categoryListController, which has a categoryData $resource service injected for retrieving the category list.
Then i have a template, addCategory.html which adds a category with the help of a addCategoryController, which also uses categoryData $resource service.
$scope.categories = categoryData.query(); //categoryListController (for sidebar)
categoryData.save(newCategory) // on addCategoryController (for addCategory.html)
The problem is, the sidebar won't update unless I refresh the entire page. I'm thinking i've got to somehow tell the categoryListController to refresh, but i'm not sure how to do that. I can do $scope.categories.push(newCategory) right after categoryData.save(newCategory), and get the new category showing immediately on addCategory.html, but i don't think that's the answer for my sidebar, unless this is something that needs to be handled with $rootscope? I'm not sure. Thanks
One of the approach that you can take here to update the list of categories in categoryListController would be to use $rootScope to broadcast message detailing the category added.
Catch this message in the list controller to either fetch the list again from server or use the newly added item send using the broadcast message to the list.
Something like this in the Add controller
$rootScope.$broadcast('categoryAdded', { 'category': newcategoryObject });
Something like this in list controller
$scope.$on('categoryAdded', function (event, args) {
$scope.categories.push(args.category);
});
You can inject $rootScope as a dependency into the controller.
You can do a similar thing by creating a CategoryList service too. Since service are singleton by nature and can be shared across controllers, using the service approach you would define a CategoryList service with methods to get and `add' categories and bind to data returned by this service.
You should create a service that share the data structure and care of managing the content.
Something like this:
angular.service('categoryService', function() {
var categories = [], initilized;
return {
this.getCategories = function() {
if (!initialized) {
// call resource to fulfill the categories array
initialized = true;
}
// you cold return a promise that would be resolved as soon
// as you get the first response from server
return categories;
});
this.addCategory = function(category) {
// code to call $resource, add the category and update the
// categories array, shared between both controllers
//
// you could return the promise for adding the content
});
this.removeCategory = ...
};
});
 
You wouldn't need to even call $resource, this service would care of any need of persisting. Of course, you might change and add more method if you need to expose the promises.

Resources