Emberjs array controller - javascript

My route is:
export default Ember.Route.extend({
model: function (params) {
var blocks = this.store.find('block', {'objectId': 777});
this.controllerFor("blocks").set('model', blocks);
return Ember.RSVP.hash({
object: this.store.find('object', params.id),
blocks: blocks
});
//return this.store.find('object', params.id);
}
});
My controller is:
export default Ember.ArrayController.extend({
init: function(e){
alert('jere');
}
});
Alert in init function works but next I get the error:
Error while processing route: objects.bc.index Cannot read property
'length' of null TypeError: Cannot read property 'length' of null
What is the right way to get collection of models through ajax and show it in template with custom array controller?

This code has a number of problems. First, ArrayController assumes that its model is an array, whereas your model hook is returning a hash. Second, your this.controllerFor("blocks").set('model', blocks) call attempts to set the model for the controller to a promise, which is useless. You do not set the model for the controller in the model hook like this. You set it by returning the model, which is then installed (after it resolves) into the controller by your (or the default) setupController hook.
You should not use an ArrayController, which is soon to be deprecated anyway, and instead use a plain old controller. The model for this controller will be the hash returned from the model hook. You need to access it explicitly in the template with {{model}}.
So you want something like this:
// route.js
export default Ember.Route.extend({
model: function(params) {
var blocks = this.store.find('block', {'objectId': 777});
return Ember.RSVP.hash({
object: this.store.find('object', params.id),
blocks: blocks
});
}
});
// controller.js
export default Ember.Controller.extend({
init: function(e) {
alert('jere');
}
});
In your templates, instead of
{{#each controller}}
blockProp is {{blockProp}}
as you are presumably doing now, use
{{#each block in model.blocks}}
blockProp is {{block.blockProp}}
{{/each}}
And objectProp is {{model.object.objectProp}}

Related

cant get model from route action in ember

i just wanna refresh model in route while get an action from controller and run doRefresh action in this route
this is my code
import Ember from 'ember';
export default Ember.Route.extend({
profileFormService: Ember.inject.service(),
profileFormAtributeService: Ember.inject.service(),
model(){
return Ember.RSVP.hash({
profileForms: this.get('profileFormService').find(),
profileFormsAttributes: this.get('profileFormAtributeService').findByProfileFormId("1"),
inputTypes: {data: ['CHECKBOX', 'NUMBER_FIELD', 'PHONE_NUMBER', 'TEXT_FIELD', 'EMAIL', 'TEXT_AREA', 'RADIO_BUTTON', 'DESA', 'KABUPATEN_KOTA', 'PROVINSI', 'KECAMATAN', 'MAP_POINT', 'MAP_POLYGON']}
});
},
setupController(controller, model) {
this.controllerFor('backend.setting-profile-form-attribute').set('profileForms', model.profileForms);
this.controllerFor('backend.setting-profile-form-attribute').set('profileFormsAttributes', model.profileFormsAttributes);
this.controllerFor('backend.setting-profile-form-attribute').set('inputTypes', model.inputTypes);
},
actions:{
doRefresh(param){
let context = this;
this.get('profileFormAtributeService').findByProfileFormId(param).then(function (response) {
context.set("profileFormsAttributes",response);
}), function (e) {
this.debug(e);
};
}
}
});
unfortunately this is does'nt affect the profileFormsAttributes model.
I've ben trying to debug the model with this
this.debug(this.get('controller.model.profileFormsAttributes'))
this.debug(this.get('model.profileFormsAttributes'));
but the console log said undefined
can you resolve this and explain what happen in this my route..
thank's for your concern
Your problem is that you cannot achieve the object returned from within route in action handler directly like this.get('profileFormsAttributes'); hence your setting does not work.
this.get('controller.model.profileFormsAttributes');
this.get('model.profileFormsAttributes');
Even above two statements does not work; because you cannot retrieve model or controller like this.
You have two options; either you need to save what you are going to return from model directly within model hook with this.set('model', model) or you can achieve it with this.controllerFor(this.get('routeName')).get('model')
I would recommend the second approach for your case. Please take a look at the following twiddle that I have prepared to illustrate the case for you.
Please take a look at index.js where foo attribute of object returned from model hook is set with
Ember.set(this.controllerFor(this.get('routeName')).get('model'), 'foo', 'foo updated');
I hope this helps.

Storing initial model property value in Ember.js

Probably a simple answer but as a beginner, say for example I wanted to store a property from my ember model inside of my controller which I could then compare against new data, how could I go about doing it?
To provide more context, I have an input field where the value is retrieved using model.user_input, I want to be able to store this somewhere when the view is first loaded and then compare it when the value changes. I've tried using computed properties but they are also getting updated when the model changes.
In your controller's route, you could set up your controller such that your controller saves the initial value:
import Ember from 'ember'
export default Ember.Route.extend({
model() {
return {
'user_input': /* ... */
}
},
setupController(controller, model) {
this._super(...arguments)
controller.set('original_input', Ember.get(model, 'user_input'))
}
})
That way, when the value changes, you could simply fetch the original value via Ember.get(this, 'original_input') on your controller:
import Ember from 'ember'
export default Ember.Controller.extend({
'original_input': '',
isChanged: Ember.computed('model.user_input', function() {
return Ember.get(this, 'original_input') !== Ember.get(this, 'model.user_input')
})
})

EmberJS, How access in a child template to the model in the parent controller

I have this router:
// app/router.js
Router.map(function() {
this.route('battle', function(){
this.route('combats');
})
});
In the combats route I can access to the battle model easily using:
// app/routes/battle/combat.js
this.modelFor('battle');
But if I want to access to this model also in the combats template things start to be complicate:
// app/templates/battle/combats.hbs
<h1>Combats for Battle {{<how to access to the battle>.title}}</h1>
{{#each model as |combat|}}
{{combat.date}}
{{/each}}
I have solved this sending properties to the combats Controller from the combats Route:
// app/routes/battle/combat.js
setupController: function(controller, model) {
controller.set('content', model);
controller.set('battle', this.modelFor('battle'));
}
But I don't know if it is the correct way, it looks too much indirect under my perspective, like that you have to make a long workaround to make this property available in the template.
It depends on how generic you want your code to be. For your special usecase it might be appropriate to use the Ember.RSVP.hash in your model hook in combats.js like this:
model(){
return Ember.RSVP.hash({
combats: //here your combat.js model code,
battle: this.modelFor('battle');
})
}
Then you can remove your setupController function and rewrite your template to:
<h1>Combats for Battle {{model.battle.title}}</h1>
{{#each model.combats as |combat|}}
{{combat.date}}
{{/each}}

Returning dictionary of Promises for asynchronous EmberJS route

I'm learning how to use Ember promises with async routes, and stumbling a bit here. If I write my route like so:
App.ActivitiesRoute = Ember.Route.extend({
model: function() {
return getClient().getActivities()
}
});
Where getActivities() returns an Ember.RSVP.Promise type, I can use in my template:
{{#each activity in model}}
However, I would rather not have my entire base model subsist of a single attribute. When I try this:
App.ActivitiesRoute = Ember.Route.extend({
model: function() {
return {
activities: getClient().getActivities()
}
}
});
And change my template to:
{{#each activity in model.activities}}
I receive an error message:
"Uncaught Error: Assertion Failed: The value that #each loops over must be an Array. You passed {_id: 82, _label: undefined, _state: undefined, _result: undefined, _subscribers: }"
And I'm not sure how to return a named collection of Promises that can be accessed individually in my template.
model needs to return a promise in order for the promise-based transition mechanisms to work property. You're not returning a promise; you're returning a hash of promises, which is an entirely different thing. You can return a hash-valued promise which fulfills when all its individuals keys fulfills with Ember.RSVP.Promise.hash:
model() {
return Ember.RSVP.Promise.hash({
activities: getClient().getActivities()
});
}
This promise will resolve to a hash that looks like { activities: activities }. Remember, all else being equal this is what will be set as the model property of your controller. Therefore, in the controller and in templates, you will now need to refer to model.activities.
If you want to wait for several asynchronous calls (such as multiple calls to this.store) to finish before transitions proceed, you can use the same hash approach in your model hook:
model() {
return Ember.RSVP.Promise.hash({
activities: getClient().getActivities(),
toys: this.store.findQuery('toy', type })
});
}
and then set the "main" one as the model on the controller in setupController:
setupController(controller, model) {
controller.set('model', model.activities);
}
In some cases, a simpler approach would be to retrieve the main model in the model hook, and use afterModel to retrieve and wait for the secondary model.

Ember - What's the difference between controller's content and model property

In ember's official guide, it provides two ways to set the controller's underlying object.
First is setting the model property:
App.SongsRoute = Ember.Route.extend({
setupController: function(controller, playlist) {
controller.set('model', playlist.get('songs'));
}
});
Second is setting the content property:
MyApp.listController = Ember.ArrayController.create();
$.get('people.json', function(data) {
MyApp.listController.set('content', data);
});
Are these two properties represent the same thing? Which way should i use?
It seems they are the same thing,
https://github.com/emberjs/ember.js/blob/v1.3.0/packages/ember-runtime/lib/controllers/controller.js#L44
Ember.ControllerMixin = Ember.Mixin.create(Ember.ActionHandler, {
....
model: Ember.computed.alias('content'),
....
The model property is an alias for content.
Also,
https://github.com/emberjs/ember.js/blob/v1.3.0/packages/ember-routing/lib/system/route.js#L849
which mentions that,
By default, the `setupController` hook sets the `content` property of
the controller to the `model`.
UPDATE
Deprecated since v1.7.0 and the code placed in a mixin.
https://github.com/emberjs/ember.js/blob/v2.12.0/packages/ember-runtime/lib/mixins/controller.js
Along with the related deprecation mixin.
https://github.com/emberjs/ember.js/blob/v2.12.0/packages/ember-runtime/lib/mixins/controller_content_model_alias_deprecation.js
In the documentation - http://emberjs.com/api/classes/Ember.Controller.html#property_model - it clearly states that when retrieving or modifying a controller's model, the model property should be used instead of the content property.

Categories

Resources