I am having a problem with a hasMany property, but only under certain circumstances. I have a User model and a Group model. The user has a property:
groups: hasMany('group', { async: true })
In my template, I show the groups:
{{#each groups}}<span class="label">{{this.name}}</span>{{/each}}
When I go to /users/1, I see the groups. Then I can go to /users/1/edit. There, I show a Ember.Select view with multiple=true. The select view shows 'groups' as the selection and 'allGroups' as the full list. This works as expected. 'allGroups' is a computed property on UserEditController:
allGroups: function() {
return this.store.find('group');
}.property()
So far, so good. I can update the selected groups if I want, then save. After the save, I transition back to the /users/1 route. When the user is displayed there (after updating), the selected groups show nothing. No error in the console.
I can refresh the page and the selected groups are shown, showing the new choices I made when updating the user.
This one has me baffled, but I suspect it has something to do with the 'allGroups' function.
What version of Ember-Data are you using? This sounds like known bug that should be fixed in 1.0.0-beta-3:
https://github.com/emberjs/data/commit/4d717bff53f8c93bedbe74e7965a4f439882e259
https://github.com/emberjs/data/issues/1228
http://discuss.emberjs.com/t/hasmany-relationships-and-waiting-for-all-child-models-to-be-loaded/2461/3
The second link contains a workaround that should work if you have to use an earlier version of ember-data.
I ran into this issue before, but in this case you don't need to manually handle the synchronicity. Ember will render the data when it receives it...
Please provide more code and I will take a look, I think this could be related to the way you proceed for saving.
Also, although I am note sure about that, when you proceed to an update your backend, I think, should return the "inserted" or "updated" data. This would help to ensure synchronization with the backend.
Related
I'm trying to get my template to display a save button when the form is changed.
The when the value of an input field is changed, the model is set to isDirty=true, but template tag is not activated.
Pertinent Information
Using Ember Model ( not Ember Data )
Edit route is nested in item route
Model is being set to isDirty = true ( I think I'm not binding to it correctly )
JSBin with prototype of the problem
http://jsbin.com/owanef/19/edit
If you click on Edit, you will see edit form for the active model. When I enter anything into the field, the model doesn't become dirty or it doesn't propagate to the template.
What could be causing this?
Summary
Ember Model doesn't bind isDirty to the controller. As a result, controller's isDirty property is update correctly, but model's is not. Read more about this in Github Issue.
I changed the ember-model included to use the version on github master, and now it shows isDirty to be true always. See this jsbin using master.
This may be a bug in Ember-model. You may want to file an issue on github.
Based on what I've read (please correct me if I'm mistaken), the logic that handles when a model should be saved and where to transition next should be in the router.
If that is the case, I'm running into a bit of a problem: I don't know how to access the model from the route.
This is my controller (and the console logs "CREATED" after I press submit):
App.ScoutsNewController = Ember.ObjectController.extend
submit: ->
model = #get('model')
model.on 'didCreate', ->
console.log 'CREATED' # I want to redirect to the index after creation
model.save()
I should move that logic into the route, right? Let's try that:
App.ScoutsNewRoute = Ember.Route.extend
model: ->
App.Scout.createRecord()
events:
submit: ->
# Based on what I've read, the right place to put the code you see in the controller is here. How do I get access to the model?
# I have tried #get('model'), #get('content')
Note: I understand that the submit event bubbles up from the view, to the controller, then finally the route, stopping at any one of them that has "submit" defined. So since I want the route to handle it, I removed the controller. I'm able to see any console.log done in the route, I just need to be able to get to the model instance.
I'm using Ember v1.0.0-rc.5-7-g610589a
Thanks!
Two options: this.currentModel or this.modelFor(routeName)
Update
I spoke to SeƱor Alex Matchneer about this. There are no plans for this.currentModel to go away anytime soon, but he considers this.modelFor(this.routeName) the public API.
what should work is
this.controllerFor('ScoutsNew').get('content')
this.currentModel isn't really the approved way as described here
but in my version of Ember (1.11) this.modelFor(this.routeName) returns null, so this is what worked for me
this.controllerFor(this.routeName).get('model')
You could also use this.controller.get('model'); but there are plans to remove the controller.
Till that we can use the above code to retrieve the routes current model
With Ember 3.0.0 this is a documented way that works for me:
const model = this.controller.model;
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.
I have the following problem with ember.
I have a table with a set of datas. I have an event that returns me the current element of the table. Then it opens another view by transitioning into a new state and writes the selected table data in a textfield.
click: function(e) {
var element = $(e.target).closest("td");
App.tee = element.text().trim();
var router;
router = this.get('controller.target.router');
router.transitionTo('newRoute')
As you can see I have some other routes in my router as well.
The last two routes(home and profile) are part of a nav-tab. They work perfectly beside I click on the table. Then i get the following error when i click on a tab: Uncaught TypeError: Cannot read property 'enterStates' of undefined
Ok i give it another try to explain what i wanted to do.
What i want to do is to create a table with some data (for example persons).
When i click on a specific person in the table the corresponding table-data should be shown in the textfields that appear below. Whenever i click on another person the textfields below should change to the informations of the current clicked person in the table. When i click "New" Button a more detailed Tabview appears on the right side with some additional informations. I was playing around with ember and so far i just implemented some of the views and the routing. Im stucked as i have tried to implement the event that updates the textfield below the table. It updates once but after it has transitioned into the new state(newRoute) nothing happens. I know the code is very raw, but it is just a test to understand how this works in ember.
Ok the solution was easier than i thought. The problem was not the state changing. It was more a problem of how to access the data and how to effect the change of binded data. I realised too late that i needed to understand how the variable access works in Ember and what exactly the App.initialize() method does. So App.initialize() initializes all Controller classes in the router. If you want to access any variables within a controller you have to get the access over the router like
{{view Ember.TextField valueBinding="App.router.tableController.person"}}
Secondly i wasnt familiar with the usage of the set and get methods in Ember and the difference between extend and create. I wondered before where ember instantiates my object.
So my problem had nothing to do with states it was just a totally misunderstanding of the ember framework. Im a noob thats all.
Ok, this is the first shot of the answer.
I think the main issue is just a typo gotoHome instead of goToHome in the template.
By the way I get rid of some deprecation warnings by using <button {{action }}></button> instead of Ember.Button.
There is some other warnings when I click on the table, because you are referencing some properties which don't exist.
here is the corresponding fiddle: http://jsfiddle.net/Sly7/rKw9A/25/
Since I don't understand how it should work exactly, I'm not sure of the overall behavior. I let you explain me the flow (by editing the question please).
Any other comment is welcome :)
I am listing products as table rows, each row contains input fields for specifying the quantity of products.
I made a Fiddle for it here, http://jsfiddle.net/kroofy/4jTa8/19/
As you can see, after the input in the Qty field have been made, the whole row render again. And because of that the focus of the input field will be lost, which is not good if you want to input more than just one digit, or tab between input fields.
What would be the most elegant way to solve this?
I would handle this by setting model.set({qty: _qty}, {silent: true}) and then updating the non-input fields with this.$.
As an alternative to the silent treatment: rather than listening for change events, listen for change:qty and change:sellPrice and have a method that updates just the HTML that needs updating within this.$, rather than re-rendering the DOM object and breaking your focus.
Either way, your comment about "selective updating" on the fiddle is certainly the right way to go.
(this.$ is a backbone hack to jQuery that restricts all selectors to search only within the DOM of the View's element. The element doesn't even need an ID or class; it just needs to exist and the View maintains a handle to it. It's incredibly useful.)
i built a plugin for backbone called Backbone.ModelBinding that may be able to help in this situation. my plugin allows you to update portions of a view with data from a model, when the model changes.
i've forked / updated your fiddle to show it in action: http://jsfiddle.net/derickbailey/FEcyF/6/
i removed the binding to the model change. i've also added id attributes to the inputs of the form to facilitate the plugin (the attribute that the plugin uses is configurable, though). and lastly, i've added a data-bind attribute to the sell price total td.
you can get the plugin here: http://github.com/derickbailey/backbone.modelbinding/
hope that helps
FWIW: my plugin is an automated version of what Elf is suggesting. I've written code exactly like he is describing, numerous times, which is where the plugin came from. I just got tired of writing that code by hand :)