Force loading a single attribute with ember-data - ember.js

I'm trying to find a way to update a single attribute of a model without it getting dirty. Just like Store.load but with just a single attribute.
The use case is that I want to upload an avatar image (which cannot be done with the current adapter's semantics AFAIK). I do it against a particular API endpoint and I afterwards I want to update the user with the resulting URL (so all his avatar appearances get updated).
I am in the context of a profile edition, so if I just load the whole user I loose all the changes of the form (because the values get overriden).
Is there any way to do so? Thanks!

You could model 'Avatar' separately, as a model in itself instead of an attribute. Then, that model can be updated via the store without worrying about conflicting changes with the rest of the User model.

I can think of two ways, but I haven't tried them. (They're both just workarounds)
You can set a user's property that is not a DS.attr. If it's a normal property, it shouldn't dirty the record.
If url is a database attribute, then create a computed property that listens to URL and use that in your templates.
App.User = Em.extend({
url: DS.attr('string'),
URL: function() {
return this.get('url');
}.property('url')
});
And then user.set('URL', imageUrl)
Another way could be to transition the record to the clean state.
user.get('stateManager').send('becameClean');
The second method is an ugly hack though.

Related

How can I model singletons without an id in ember?

I am new to ember and am trying to migrate an existing application, and would like to know what the recommendation is for modeling a single object that will be reused in multiple components on every page. ie: As part of the initial load, I would like to perform a GET request against a URL like 'https://example.com/currentUser' and get an object back like:
{
name: "Users Name"
email: "user#email.com",
profileImg: "http://example.com/pictureOfUser.png"
... snip ...
}
This object will then be used in components for menus, toolbars, and a form for updating it via a post to the same URL.
What is the best way to model this workflow in ember? Given that this is an incidental object and not the focus of most routes, it does not seem to make sense to specify it as the model of them. Also, does ember data handle cases where a model is a singleton and does not have an ID, or would I need to use something like Ember.$.ajax ?
What do you mean by "where a model is a singleton"?
If you use the ember-data default adapter, then yes, a model needs to have an ID, it's part of the JSONAPI spec. If you already have a backend with different conventions, take a look at extending or swapping out the default adapter.
A service is a singleton, and there is nothing preventing you from making an AJAX call there. You would be losing out on all the nice things that come along with ember-data, but, you can do it.

Transition to same route with same model

I have a "Filter" model, and the user can alter this model by clicking on the page.
So when the user makes a change to the model, I want to transition to the same route he is currently on, because the URL is different depending on the details of the model (I have overridden "serialize" on the route to ensure that this is the case).
As things stand now, Ember seems to ignore my please to transition to the same route with the same model. The model is altered and my template changes, but I want the URL to also reflect the change to the Filter.
How can I do this?
Edit:
Here is the code in my ApplicationController
App.ApplicationController = Ember.Controller.extend
currentFilter: null
actions:
toggleRegion: (region_id) ->
region = this.store.getById('region', region_id)
filter = this.get('currentFilter')
# modify the filter
if filter.containsAtLeastOneCityOfRegion(region)
filter.disableRegion(region)
else
filter.enableRegion(region)
this.replaceRoute('listings', filter)
Now, this works as intended when I am in the "index" route, but if I am already in the "listings" route, the model is modified as intended, but route replacement is not happening, and consequently, my URL is not updated with the correct dynamic segments (coming from my ListingsRoute's "serialize" method).
It looks like Ember does a no-op if you want to transition to (or replace, as is the case with me) to the same route you are on, with a model object with the same identity as the current model.
So what I needed to do was clone the object, make the change I needed to make, and then do the transition.

Ember Data Binding

Supposed I have a model containing 2 pre-populated fields. I would like to display these fields in the DOM for the user to modify if necessary. If I bind the DOM to the model using: {{input value=field1}} and {{input value=field2}}, then every time the user types in a character in one of these fields, Ember updates the bound model immediately. This is not the behavior I want. I prefer to show a button; when pressed, I want to validate data in the two fields in relation to each other, and if valid, update the model.
I considered creating mirrored fields in the controller and binding these to the DOM. Then create an action associated with the button to do the validation, and if data is found to be valid, copy data from the controller fields to the respective model fields. This technique may work, but seems like a very round-about way of doing something conceptually simple.
Do one of you Ember gurus out there have an opinion on how best to do this? I'm looking for best practices; please help.
I am not a guru nor am I familiar with client side validation in EmberData since our app uses server side validation.
Are you sure you can't allow your model to be updated immediately (i.e. bound to the template fields)?
If you did bind the model, then you could validate upon submission. If validation fails, you can just rollback the changes. If it passes, you can save the record. This is probably what I would do.
However, you clearly state that you do not want your model updated immediately, which means you don't want to bind your model.
Also, you have to do some processing that depends on multiple fields to validate, so it really sounds like binding to the controller and having a validation action is a good solution and that's what I would do if I wasn't binding to the model.

ember (+ ember-auth) linkTo loggedIn user profile

To get straight to the point, I have an app with a profile accessible like that:
this.resource('user', {path: '/user/:user_id'});
This can accessed from visitors and (logged in users). Now I also have a menu-bar which has, only for logged in users, a link to the user-profile (so that would be /user/:loggedin-user_id). I am using ember-auth to authenticate the user and ember data for my models.
The problem here seems to be {{linkTo 'user'}} doesn't work, because for one user that should link to /user/28, for the next one to /user/15. Simply to his/her own profile. I kinda get that it doesn't work, because how should ember know what ID to display (though yes, I don't understand the underlying reasons fully).
Ember-Auth does provide App.Auth.get('userId') to get the Id of the currently logged in user, but I don't really know how I can tell ember to know that as well.
So what I had to do know is setting the link manually via
<a {{bindAttr href="App.loggedInUser"}}>
where-as this variable gets set to the right url in the Application controller with App.Auth.get('userId'). This works, but is obviously quite a hack.
Is there any 'ember' way of solving that?
ember-auth dev here.
Straight to solution:
First, ask ember-auth to load the user current user model. Assuming that your user model is called App.User, and it implements App.User.find(id).
App.Auth = Ember.Auth.create
# ...
userModel: 'App.User' # default null
# pass the string, not a class App.User
# access the current user model
# as with all things ember, this is loaded asynchronously
App.Auth.get('user')
(copied from the docs.)
Next, pass this dynamic model to your handlebars links:
{{#linkTo 'user' App.Auth.user}}Link To Current User{{/link}}
Or otherwise - e.g. make it a binding to App.Auth.get('user'), etc.
Just in case, (js) App.get('foo') is equivalent to ember-handlebars App.foo.
Your user route has a dynamic segment. You can pass the user model to the linkTo and the anchor will point to that route for different users depending on the id of user model passed.
{{linkTo 'user' userObj}}Profile{{/linkTo}}
The model passed can be plain object with an id and the default serialization would still work. So if you wrap App.Auth.get('userId') into a object with an id you won't need a full model object.
Here's an example jsbin.

Assigning a "database id" to multiple html ids on a page

I will use model.id when referencing the id for the table in the database, and id when referencing the id given to elements in my html.
I have a django project where I am using some hidden form fields (all forms have the same id right now for that hidden field) to house the model.id. This works great as long as the model.id is known when the page is rendered.
I am now attempting to modify the process to work when no model.id is given (ie someone has chosen to create a new instance of my model). As far as the backend goes I have this working. No model.id supplied and the view knows it should give empty forms. At this point I choose not to create a new instance of the model, as I only want to if the user actually enters something in one of the forms.
If the user enters something in a form then the form processing creates a new instance of model and passes the id back to the users browser. What I was attempting to do is use the jquery form plugin to save the return data somewhere hidden, which I would then look at and use val to set all of the hidden fields' ids to the model.id that was returned so the next field/form the user submits will know to write to the model that was just created.
Now looking at this I'm guessing the idea of having multiple elements with the same id is bad, but I really do want them to always be the same and only have the hidden fields there to house that same Model.id on every form on the page.
I tried doing something like follows. However only one of the ids on the page actually got the value assigned. Is there a different way I should be accomplishing this goal? Is there something I should add to make all occurrences of id to be set with something like .val(model.id)? If not, does anyone have any suggestions on how to go about this? Maybe django provides a cleaner way of doing exactly what I'm trying to accomplish?
A response returned from form submission.
<response>
<the_model_id_brought_back>3732</the_model_id_brought_back>
...
<response>
The jQuery code attempting to set all of the "id_in_multiple_places" ids to the model.id returned.
jQuery('#descriptionForm').ajaxForm({
target: '#response',
success: function(data) {
the_model_id = jQuery('#response').find("the_model_id_brought_back").html();
jQuery('#id_in_multiple_places').val(the_model_id);
}
});
To explain why I have multiple forms like this. Forms consist of 1 visible field. Multiple forms are on the page. When a user leaves a field (which means they leave the form as well) I will submit that form to the server. This will allow their data to always be saved even if they stop half way through and throw their computer out a window. They can go to a different computer and pick up where they left off.
Thanks.
Now looking at this I'm guessing the idea of having multiple elements with the same id is bad
It's not only bad, it's impossible. You cannot do this. You can get around this by using classes, which don't have to be unique, but you probably shouldn't.
What you should do, is assign the elements sensible class names, and assign their common ancestor the ID. You can start at that element and traverse downwards to find the sub-elements by class name.