I am trying to set a model value from an action received by my route.
//app/routes/map.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return {
trail: null
};
},
actions: {
event: function(name, value) {
if (name === 'trail.selected') {
this.modelFor('map').set('trail', value);
}
}
}
});
when I try to use
this.modelFor('map').set('trail', value);
I get the following error:
Uncaught TypeError: this.modelFor(...).set is not a function
When I try to use
this.modelFor('map').trail = value;
I get that error
Uncaught Error: Assertion Failed: You must use Ember.set() to set the trail property (of [object Object]) to <nested-component#model:mtg-trail::ember617:kvdpo>.
EDIT Added template
//app/templates/map.hbs
<h2>Trail's name: {{trail.name}}</h2>
{{#if trail}}
{{map-draw trail=trail.id}}
{{/if}}
Your routes model isn't an ember object so set won't work. Try:
model: function() {
return Ember.Object.create({
trail: null
});
},
Also, changing the models content from an action should really be done on the controller.
Well, since the action you are calling is on the 'map' route itself, why not just:
this.set('model.trail', value);
Related
My ember version:
DEBUG: -------------------------------
Ember : 2.10.2
Ember Data : 2.11.0
jQuery : 2.2.4
Ember Simple Auth : 1.1.0
Model Fragments : 2.3.2
DEBUG: -------------------------------
And my route code:
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
import RSVP from 'rsvp';
export default Ember.Route.extend(AuthenticatedRouteMixin, {
model() {
console.log(1);
return RSVP.hash({
...,
user: this.store.findRecord('user', this.get('session.data.authenticated.id'))
});
},
afterModel(model, transition) {
return this.store.findRecord('company', model.user.get('companyId')).then(company => {
console.log(2);
this.set('company', company);
});
},
setupController(controller, model) {
console.log(3);
controller.set('user', model.user);
controller.set('company', this.get('company'));
}
});
Look at console.log code, I think the correct order should be 1->2->3. But sometimes it turns out to be 1->3->2.
But my company id must come from user api. So what is way I set it in route? Thanks.
I am writing just another solution, From RSVP.hash api docs
Returns a promise that is fulfilled when all the given promises have been fulfilled, or rejected if any of them become rejected. The returned promise is fulfilled with a hash that has the same key names as the promises object argument. If any of the values in the object are not promises, they will simply be copied over to the fulfilled object.
So you can write your requirement like the below code,
model() {
var promises = {
user: this.store.findRecord('user', this.get('session.data.authenticated.id'))
};
return Ember.RSVP.hash(promises).then(hash => {
//then method will be called once all given promises are fulfilled, or rejected if any of them become rejected.
return this.store.findRecord('company', hash.user.get('companyId')).then(company => {
hash.company = company; // Here i am setting company property inside model itself, so you dont need to set it in route and carry over to controller
return hash;
});
})
}
Note:I am curious to know if you can reproduce 1->3->2 behavior in ember-twiddle.
Actually the right way to do this is to put all your model fetching in your model hook:
model() {
return RSVP.hash({
...,
user: this.store.findRecord('user', this.get('session.data.authenticated.id'))
}).then(hash => {
hash.company = this.store.findRecord('company', hash.user.get('companyId'));
return RSVP.hash(hash);
})
},
setupController(controller, model) {
controller.set('user', model.user);
controller.set('company', model.company);
}
I'm getting the following error on createRecord
Uncaught Error: Assertion Failed: You may not pass `null` as id to the store's find method
Create record is called here
var newSchool = this.store.createRecord('deal', {
name: newSchoolName,
timeZone: newTimeZone,
locale: newLanguage,
gradeNames: newGradeNames,
standardSourceIds: newStandardSources,
contentSourceIds: newContentSources,
adminUserId: '511a48a7781200b2cd000001',
numOfToken: 1,
higherEd: higherEd,
dealType: 'institution',
parentDeal: this.get('model.deal')
});
The problem is with the parentDeal it's a belongTo relationship if I change it to null there's no error.
Also the error is only thrown on switching routes and if I log this.get('model.deal') before hand it shows the object.
The model is declared in the route
model: function() {
return Ember.RSVP.hash({
deal: this.store.find('deal', this.get('session.dealId')),
contentSources: this.store.find('contentSource'),
standardSources: this.store.find('standardSource')
});
},
Edit: After kitlers comments
I added the following to deactivate
deactivate: function() {
var model = this.get('model.deal');
if(model && model.get('isDirty')){
model.get('transaction').save()
}
}
Also before hand this is what the store looked like in ember inspector
I get undefined when I do the console.log(this.get('item.product.description')); in the component object and an error message in ember inspector, console tab:
Uncaught TypeError: Cannot read property 'length' of undefined
I suspect this is happening because item.product.description is coming from a promise (async call). On page load, the promise isn't fulfilled yet. However, what I don't want to do, is create a .then block in the component, like:
this.get('item.product').then((product) => {
This just makes the component not so isolated, since it expects item.product to be a promise, instead of an actual string.
What other approaches should I consider?:
// Route
import Ember from 'ember';
export default Ember.Route.extend({
model(params) {
return this.store.find('user', params.user_id);
}
});
// Template
{{#each item in model.jobOrders.lastObject.checkout.items}}
{{product-card item=item}}
{{/each}}
The component:
// Component template
<p class="name">{{item.product.name}}</p>
<p class="description">{{truncatedDescription}}</p>
// Component object
import Ember from 'ember';
export default Ember.Component.extend({
truncatedDescription: Ember.computed('item.product.description', function() {
console.log(this.get('item.product.description'));
var truncatedText = this._truncate(this.get('description'), 48);
console.log(truncatedText);
return truncatedText;
}),
actions: {
// ...
},
// Private
_truncate(text, limit) {
if (text.length > limit){
text = text.substr(0, limit - 3) + '...';
}
console.log(text);
return text;
}
});
One possibility would be to pass the description itself to the component instead of the item.
// Template
{{#each item in model.jobOrders.lastObject.checkout.items}}
{{product-card description=item.product.description}}
{{/each}}
This way, when item.product.description resolves, it will update the computed property truncatedDescription in your component.
i face this error when saving data to api
Uncaught Error: Assertion Failed: Cannot delegate set('firstName', a) to the 'content' property of object proxy <>: its 'content' is undefined
below is my code
import Ember from 'ember';
export default Ember.ObjectController.extend({
isValid: Ember.computed(
'email',
'firstName',
'lastName',
'twitter',
function() {
return !Ember.isEmpty(this.get('email')) &&
!Ember.isEmpty(this.get('firstName')) &&
!Ember.isEmpty(this.get('lastName')) &&
!Ember.isEmpty(this.get('twitter'));
}
),
actions:{
save: function() {
if (this.get('isValid')) {
var _this = this;
this.get('model').save().then(function(friend) {
_this.transitionToRoute('friends.show', friend);
});
} else {
this.set('errorMessage', 'You have to fill all the fields');
}
},
cancel: function() {
this.transitionToRoute('friends');
}
}
});
Don't use ObjectController. Use simply Ember.Controller.extend.
I see this on the ember-cli-101 book. I encountered the same issue myself. It's likely that you are not properly setting the model attribute in your route. Based on the book, the error either occurs in the edit or new route.
if your router.js looks like this:
...
Router.map(function() {
this.resource('friends', function() {
this.route('new');
this.route('show', { path: ':friend_id' });
this.route('edit', { path: ':friend_id/edit' });
});
});
...
the friends/index route needs to set the model attribute:
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.find('friend');
},
});
and the friends/new route needs to set the model in a different way:
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.createRecord('friend');
},
});
For anyone not familiar with the book (mentioned above) the question is from code that is in the book, which is why I referenced it. In most cases, if you get this issue it is likely because you forgot to or did not set up the model attribute correctly in the appropriate route.
My Router defines the following:
this.resource('uoms', { path: '/uoms' }, function() {
this.route('new');
});
And the uoms route is defined as:
App.UomsRoute = Ember.Route.extend({
model: function() {
return this.store.find('uom');
},
actions: {
save: function() {
this.modelFor('uoms').save().then(function() {
console.log("saved UOMs");
});
}
}
});
But for some reason when I try and save it I am getting:
Uncaught TypeError: Object [object Object] has no method 'save'
Can someone help me identify what I'm doing wrong?
---- UPDATE ----
I also tried the following from the controller but with the same results:
App.UomsController = Ember.ArrayController.extend({
actions: {
save: function() {
this.get('model').save().then(function() {
console.log("saved UOMs");
});
}
}
});
---- UPDATE 2 ----
Looking at the object returned by the this.get('model') call we get the following:
This is what I would do:
Using Chrome Developer Tools set a breakpoint at the line where you try to save the model
To inspect the model held by the controller enter this.get('model') the Chrome Developer Tools Console.
Check if the console output is really what you expect. Most probably it is not the model instance you want to save. You will see that you will get the same error when you execute this.get('model').save() in the console.
BTW: Why are you using an ArrayController and not an ObjectController. It looks like you use it for a single model. See the docs for more details on that.
Edit:
Try this.get('model').get('transaction').commit()
The problem I was running into was that I was trying to call save() on an array of records rather than a singular record. This problem was created because I was operating on a singular record but doing this within an ArrayController. I don't think there's anything wrong with this although it could be argued that I should have created a sub-route called "edit" and then presumably my code logic would have worked.
That said, if you want to do as I did (aka, save a singular record within an ArrayController) then this code will work:
save: function(id) {
var promise = this.store.find('uom',id).then(function(uom){
console.log(uom);
uom.save();
});
}
And then in the template put something like this:
<span class="glyphicon glyphicon-floppy-disk" {{action "save" id}}></span>
This works but is not the best answer. Instead you can specify in the ArrayController an ObjectController with the itemController property. Below is an example of both a save() and deleteRecord() handler using this strategy:
App.PluralController = Ember.ArrayController.extend({
itemController: 'singular'
});
App.SingularController = Ember.ObjectController.extend({
actions: {
save: function() {
this.get('model').save();
},
deleteRecord: function() {
this.get('model').deleteRecord();
this.get('model').save();
}
}
});
Then you'll want to do something like the following for your handlebars template:
<span class="glyphicon glyphicon-floppy-disk" {{action "save" this}}></span>
<span class="glyphicon glyphicon-remove-circle" {{action "deleteRecord" this}}></span>