ng-repeat convert resource objects to simple objects - angularjs

Iam getting my data with help of the Angular's $resource service as array. Each element of that array is an Resource-Object. So i can use methods like $save and $update of these Objects. In a view i represent my array with the help of the ng-repeat directive like:
<div ng-repeat="appointment in object.appointments" ng-click="editAppointment(appointment)">
And here i get in trouble. The appointment-Object i get in the editAppointment-Method is a simple Object. No Resource Object anymore. So i cant use the helpfull methods like i mentioned above.
$scope.editAppointment= function(appointment){
console.log(appointment); // > Object
console.log(object.appointments); // > Array of Resource
}
Have somebody noticed that problem too? May its a bug, but i cant imagine that.

Assuming your resource class is called Appointment, you should just be able to do:
$scope.editAppointment= function(appointment){
new Appointment(appointment).save();
}
Presumably your Appointment resource looks something like the following (i.e. it correctly maps some sort of id property from existing objects to the URL parameters):
var Appointment = $resource('/appointment/:appointmentId', {appointmentId:'#id'});
This would be the case if your appointment objects (i.e. the underlying JSON objects handled by your API) have an ID property called id. If it's called something else (or if there are multiple path variables in your URL) you'll just need to change the second argument to map all of the properties of the objects being saved (the values starting with '#') to the URL path variables (the things starting with ':' in your URL).
See where they save a new card in the credit card example here: http://docs.angularjs.org/api/ngResource.$resource. The fact that they're dealing with a totally new object and that you're trying to save an existing one is irrelevant. Angular doesn't know the difference.

Related

Unique AngularFire calls in Angular template functions

I'm using AngularFire and have an ng-repeat list with items that contain data specific to the "author" of that item (multiple users can add to the list), such as name, location, etc. I'm not writing that data into the array being iterated over by ng-repeat since it could change in the future. Instead, that author-specific data is store in a different location so the goal is that if the author changes their information, all of it is reflected in the list.
For a contrived example, imagine I'm iterating over a list of books from different authors. That list will contain the book-specific data (such as title, publish date, etc.) but I will also want to display the author's information in the list. Instead of including the author's information directly within the book data, I want to simply reference that author ID, and pull in whatever data is in their profile so if they change their name, it'll reflect the changes in all of their book listings.
That means I'm left to make async calls to Firebase to retrieve that information for each list item via a template function, such as {{getAuthorName(authorId)}}. The only problem is that they're async calls and the template function evaluates before the data is available.
I've looked into how to accomplish but have yet to find a solution that accommodates what I need. The answers here seem close, but they appear to no longer work in Angular >= 1.2.0 and they don't account for having to return different data for each template function call.
Update
Here is a JSFiddle with what I have now. I've made some progress, but all that's being returned now is the promise object as expected. I'm not sure how to implement .then in this scenario to get the actual value.
Any help would be great.
You can make use of $firebaseObject and then store that in an object to make sure it doesn't get hit again. like so:
var authors = {};
$scope.getAuthorName = function(authorId){
if(!authors[authorId]){
var authorRef = new Firebase(fburl + "/authors/" + authorId);
authors[authorId] = $firebaseObject(authorRef);
}
return authors[authorId];
};
You can see the working fiddle here: http://jsfiddle.net/0rcdpq47/

Search if ID is on an array in another collection in mongo with mongoose and angular

So, I have a collection called users where I store the user data like password, username and so on, and then I have another collection called couples where I store inside an array of the users who are in that couple.
In the angular page I want to check if the current user logged in has a couple, so I search for its ID in the couples collection like this:
$scope.couples = Couples.query({
members: $scope.authentication.user._id
});
This return the couple info if the user ID is found in a couple in the couples collection.
The problem is that I get in my scope an array and I can't figure it out how to access the data inside that array (inside the array is the object with the couple information).
So in the $scope.couple if I print the value I get everything in console, but $scope.couple[0].members fails or $scope.couple.members fails.
If a go to the network usage I see a call to couples that returns the info in a json, but I can't understand why is an array in my scope.
Thanks

backbone.js model and collection overhead

When I fetch models or collections from the server, I am not able to access properties of the model unless I stringify then re-parse. Presumably the models themselves have some extra overhead from backbone.js? Note that in the below code I can perform stringify/parse sequentially, which is supposed to give the same result as I started with. However, clearly I have killed off some superfluous info by performing these two steps because my model's properties are now exposed differently from before. Surely I do not need to go through these two steps to access my model properties, right?
Eg.
thismodel = /// assume this came from server fetch
alert(thismodel.name); // DOES NOT WORK - undefined
jsonmodel = JSON.stringify(thismodel);
var providerprefslistJSON = jQuery.parseJSON(jsonmodel);
alert(providerprefslistJSON.name); // WORKS
Backbone Model objects are not plain old JavaScript objects. They keep their attributes in an internal hash. To access the name attribute you can either do this:
alert(thismodel.attributes.name);
Or better yet use the get() method:
alert(thismodel.get("name"));
The reason it works when you convert the model to JSON and then back again is because JSON.stringify calls the toJSON() method, which creates a JSON string from the internal attributes hash, meaning when you parse that string you get a plain old JavaScript object - which is not the same as a Backbone Model object.
First, are you trying to access the property of the model or response?
From alert(thismodel.name) it would seem that you're going for a property of the model not the attribute. If you're looking for the model attribute then perhaps you want alert(this.model.get('name'))
If you're indeed going for model.name, then basically the problem may lie in how you're parsing the data. Say for example the JSON from your server is like this {'name':'Jimmy'}.
While the model.response the raw JSON sent has "Jimmy" namespaced under object.name, Backbone will automatically take that and turn it into a model attribute unless instructed otherwise (e.g. modelObj.attributes.name) at which point you'd use the get() function.
You should be able to access model data fairly simply if everything works.
E.g. Fetch
var model = new MyModel();
model.id = 1;
model.fetch({
success: function(model, response) {
console.log(model.get('name')); // The model name attribute
console.log(response.name); // The RAW response name property
}
});
Or maybe your server isn't sending the data back as JSON data. Is the server response content-type="application/json" ?
Some things to check.

Are collections required?

Sorry this is a noob question but if I only need some initial data when the application first loads is a collection always needed or can the model fetch the data and pass it directly to the view?
Nothing in backbone is really "required". It's a very thin, more-than-one-way-to-do-it framework. Jeremy recommends data that can be bootstrapped in the initial page load be handled that way, so your HTML could include you initial data as JSON in a <script> tag. You can pass that JSON to a Backbone.Collection (if it's a list of similar records) or a new Backbone.Model (if it's a single domain object). You can also just use a model and call model.fetch to get your initial data. Model vs. Collection is more about single domain object with name/value pairs vs list of many objects where iterating, sorting, filtering are common.

How to populate a Backbone.js collection's _byId array so that I can use `get` on it?

I have a collection, and the collection.models returns an array of models. However, when I call collection.get(someId) (and this id is the id of the model that is in the collection.models array), I get undefined. Looking at collection._byId, it looks like an empty object.
How do I properly populate _byId, so that I can use get? Or perhaps I'm doing something wrong when initializing my collection, which is why _byId is empty.
I'm a little late, but hopefully this is still useful to some other people.
Collection._byId is just a normal js hash object. There's really nothing fancy about it. If you want Collection.get to work, just add all the models into the _byId hash.
Inside the collection's scope:
var someId = '123'; // any id will do
this._byId[someId] = someModel; // someModel.id = '123'
console.log(!!this.get(someId)); // should return true
Since I'm using this with Rails, the default json generated by Rails doesn't work well with Backbone. I don't know why I didn't see it while trying to learn Backbone. Anyway, you could either:
Change the way Rails generates its JSON
Change the way your Backbone app reads the JSON.
Sounds like the OP had a slightly different problem, but I experienced a similar issue and thought I'd post what worked for me.
Like the original issue, collection.models contained the right model, but in my case, the _byId hash contained a cid version of the model that wasn't empty. Nevertheless, _byId didn't contain a model with normal id (there's usually two version - an id one and a cid one), so I wasn't able to use collection.get(id) to retrieve it. My problem became a bit clearer when I read up about cid. From the docs:
Client ids are handy when the model has not yet been saved to the server, and does not yet have its eventual true id, but already needs to be visible in the UI.
I didn't think it was a problem with waiting for the server as my cid model and the collection.model had the correct ids. However passing in { wait : true } as an option in collection.create fixed this issue for me.

Resources