I'm creating a component for rendering tables. The component is actually a set of nested components and receives a route model and config object, at the top level, then is processed within the component and passed on / iterated over in the next etc.
The final child component receives a model (representing just one row in the table) along with field name that defines which filed to display from the model.
All of this works perfectly and UI updates are bound to the model. The problem that I have is that model updates are not being pushed to the UI. Within my child component I bind to the UI element using the following:
tdVal : function(){
return this.get('data').get(this.get('details').get('field'));
}.property()
tdValUpdated : function(){
this.get('data').set(this.get('details').get('field'),this.get('val'));
}.property('tdVal'),
As you can see there is no computed property literal set for tdVal, which is why model updates are not being pushed to the UI. If I were to give this a literal value such as 'data.status' then status updates to the model are pushed to the UI.
What literal value can I use to compute on any attribute change in the model?
I've tried 'data.isUpdated', 'data.isSaving' etc. I can't use 'data.[]' as the single model, not an array of model.
OK, after much trial and error I think I've found a workaround for this. It's messy and I'm not very happy with it:
//as previous I render the the appropriate value from the model as defined
//by the passed in config object
tdVal : function(){
return this.get('data').get(this.get('details').get('field'));
}.property(),
//then detect UI changes and push to model if required
tdValUpdated : function(){
this.get('data').set(this.get('details').get('field'),this.get('val'));
}.property('tdVal'),
//Then I observe any changes to model isSaving and directly set tdVal with
//the value of the field for the current td
generalUpdateCatch: function() {
this.set('tdVal',this.get('data').get(this.get('details').get('field')));
}.observes('data.isSaving'),
I did try the following instead:
tdVal : function(){
return this.get('data').get(this.get('details').get('field'));
}.observes('data.isSaving'),
But get the error: 'Uncaught TypeError: unsupported content', no idea why? If anybody has a better solution then please post as I very much dislike these workarounds.
Related
I have the following code:
var msg = this.store.createRecord({text:'first title', createdAt: "2015-06-22T20:06:06+03:00" })
this.get('model.content').pushObject(msg);
msg.save();
We create new record. Then push in it to the model to display. It worked perfectly in 1.9 version but after upgrading it to the newest 1.13 it breaks and shows this error:
TypeError: internalModel.getRecord is not a function
after some researches I came out to this solution
this.get('messages.content').unshiftObject(message.internalModel);
and it partially help. Now I have two problems:
I'm not confident if using private ember data api is a good idea
I have an annoying delay between adding record to the model and
rendering it on the screen. More than that if I don't call
msg.save(); the record isn't rendered. So as far as I understood it
waits until we have response from server and only then renders it.
But I need opposite behaviour - I need to show the record first and
then save it(showing the saving state for the user), this way user
thinks that everything goes extrimely fast.
One possible solution without resorting to private API is to use toArray() (github issue):
var array = this.get('messages').toArray()
array.addObjects(this.get('messages'))
array.addObject(msg)
this.set('messages', array)
Before 1.13:
this.get('content').pushObjects(messages);
After 1.13:
messages.forEach(functio(message) {
this.get('model.content').pushObject(message._internalModel);
});
I would make all return models to array then, add array to this array
setPeople:function(){
this.set('people',this.get('content').toArray())
}.observes('content')
then, find more person models, to array
getMoreUsers(){
var self = this;
this.set('offset', this.get('offset')+1);
self.store.findAll('person').then(function(people){
self.get('people').pushObjects(people.toArray());
});
Going throught the getting started tutorial for ember js and I am somewhat confused by what the differences are in doing
function(){}.property('model.isCompleted')
and
function(){}.property('isCompleted')
Specifically, what is the model for?
The model is just another property, but instead of being a primitive such as a string or a number its an object.
For:
model = {
prop1: 'fi',
prop2: 'fai',
prop3: 'fo',
prop4: 'fu'
}
If you do this: function(){}.property('model.prop3') your computed property will be updated only when prop3 changes.
If you do this: function(){}.property('model') your computed property will be updated when model changes.
And model is a property in your controller set by the route you are in.
My App uses Fixture data (will port to Localstorage later) and I need to implement 'save' method depending on a user click. The user click is an action that maps to the View and from therein the view, it gets transferred to the controller in order to persist info to the model, essentially the template has:
<button {{action 'save' this target='view'}}>Save</button> <!-- note that the 'this' keyword I am sending corresponds to a specific instance of the model that is in a collection, done using an {{#each model}} loop
The view has
actions:{
save:function(card){
// perform some UI activity
this.get('controller').send('save',card); // card representing 'this'
}
}
The controller has:
actions:{
save:function(card){
console.log("controller reached"); // does execute
card.save(); // spits out an error
}
}
Everything works fine however the card.save() method call does not work in the controller. I mean, all I am trying to do is to persist the specific 'card' to my data, but it keeps spitting:
Uncaught TypeError: Object # has no method 'save'
What am I missing here ?
Side notes:
The Controller returns a collection of models
The corresponding'view' for the controller also has the 'edit' partial loaded in it.
So when the user chooses to 'edit' a specific model, it doesn't
transition into a different URL, rather it loads the 'editing' form
within the same URL.
This means that the model in this specific
controller is essentially the collection and I only want to save the
specific model that is being edited.
It appears as if you aren't using any client side record management library (such as ember-data or ember-model). That being said, your instances of App.Card aren't really instances of anything, they are just POJOs and there is no save method defined on a POJO.
It sounds like you'll want to do some research into ember data, or ember model (I'd suggest ember data, http://emberjs.com/guides/models/)
If you don't want to use either, you can just use ajax calls to save data:
save:function(card){
console.log("controller reached"); // does execute
// card; // spits out an error
$.ajax({... , data:$(card), ...});
}
If it's fixture and you have no intention of saving it anywhere, and it's just a dry run, add an ugly alert or log
save:function(card){
console.log("controller reached"); // does execute
console.log('pretend to save ' + card);
alert('pretend to save ' + card);
}
I updated to RC6 two weeks ago, and I'm noticing an error in one of the screens in the project I'm working on. I have an ember model, which has a hasMany relation, that model as a computed property based on a property on its hasMany relationship, something like this:
notReadyToSend: function() {
return this.get('tweets').filter(function(tweet){
return !tweet.get('readyToSend');
})
}.property('tweets.#each.readyToSend')
this belongs to the tweet model:
readyToSend: function() {
//if all properties are true, then this property returns true
}.property('title', 'body', 'alreadySent', and many other properties)
and, at the time in which the data is being loaded, all the tweets are not 'ready' because you know, data is being loaded, but when the whole data is loaded, some tweets remain not 'ready' in the 'notReady' property, but they are actually 'ready' in their object, I mean, the Tweet ember model hast its 'ready' property, which also has some logic, and that property is true, but the 'notReady' property is not fired, and this happens for the last(depends how many we have, sometimes only one, sometimes two, etc) tweets.
Is anyone experiencing this issue ?
I've updated the code, but as a note, those are not the real models, but that's basically what I'm doing. the readyToSend property, gets set to true for all records, but the notReadyToSend property in the parent model, doesn't get updated, but again, this does not happen with all the records, just a few ones(and only the last in in the relationship) do not fire the parent property.
One more update, I have another property in the parent model, which also checks one property of the tweets relationship, it looks like this:
hasAtLeastOneTweetALreadySent: function() {
return this.get('tweets').findProperty('alreadySent');
}.property('tweets.#each.alreadySent')
and the 'alreadySent' property is also being observed in the 'readyToSend' property of the tweet model. And for some reason, if I just comment out that(hasAtLeastOneTweetALreadySent) property, everything works fine, do you know why this is happening ? this is weird.
I'm struggling to do some of the simplest tasks in Ember data - getting hold of a model object and reading its attributes.
I just figured out to get a model's attribute, you can do App.Model.find(id).get('attr_name').
App.Model.find(id) does not return an object, but a class (a Promise) instead.
What is the proper way of obtaining the object? Or perhaps do you not get the object ever, but just getting or setting the attributes of the object instead?
What is the proper way of obtaining the object?
Pass a success function to the model promise returned by find(id):
App.Model.find(1).then(function(record) {
console.log('Found record: ', record.toString());
console.log('Inspecting record...', Em.inspect(record));
console.log('Serializing record...', record.serialize());
});
Here is an update after the Ember Data updates in Sept 2013:
To get the attribute of an object identified by its ID in the router or the controller, do:
this.store.find('model', 'insert_id_of_obj').then(function(obj){
console.log(obj.get('insert_attribute_name'))
});
If you want to test it in the console, do:
App.__container__.lookup('store:main').find('model', 'insert_id_of_obj').then(function(obj){
console.log(obj.get('insert_attribute_name'))
});