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.
Related
i made a loading view when the route has to much waiting for the data, this is my route
import Ember from 'ember';
import ENV from '../../config/environment';
export default Ember.Route.extend({
desaService: Ember.inject.service(),
model(){
return Ember.RSVP.hash({
currentlyLoading:true,
desas: this.get('desaService').find(ENV.defaultOffset, ENV.defaultLimit),
desaCount: this.get('desaService').count()
});
},
setupController(controller, model) {
this.controllerFor('backend.master-desa').set('desas', model.desas);
this.controllerFor('backend.master-desa').set('currentlyLoading', model.currentlyLoading);
this.controllerFor('backend.master-desa').set('desaCount', model.desaCount);
},
renderTemplate(controller, model){
let controller2 = this.controllerFor('backend.master-desa');
if(controller2.get('currentlyLoading')){
this.render('components/common/loading-view', {
into:'application'
});
}
},
actions:{
loading(transition, originRoute){
let controller = this.controllerFor('backend.master-desa');
controller.set('currentlyLoading', true);
transition.promise.finally(function() {
controller.set('currentlyLoading', false);
});
}
}
});
first i set currentlyLoading true, then the renderTemplate will be called and showing 'components/common/loading-view' into application.hbs.
this is work but i need to remove that 'components/common/loading-view' after the loading actions has complete.
please help me :(
You can make use of disconnectOutlet method of router. What you need to do is to call the following to remove the template that is rendered within renderTemplate hook method.
actions:{
loading(transition, originRoute){
let _this = this;
let controller = this.controllerFor('backend.master-desa');
controller.set('currentlyLoading', true);
transition.promise.finally(function() {
controller.set('currentlyLoading', false);
_this.disconnectOutlet({
outlet: '',
parentView: 'application'
});
});
}
}
However, if you run your application probably you are going to see that nothing is rendered. Here is the reason:
renderTemplate hook is run after model is already solved; hence you will see nothing until the model is fully resolved. renderTemplate hook will be run to make a rendering; however loading event within actions will be fired and you will remove the template that is about to be rendered since loading is finished. Hence, you will not achieve what you want with this design approach.
You need to is to render something before model is fully resolved; and that is explained in the guide specifically. I suggest you to go over it and ask more if you run into some issues.
I have prepared the following twiddle for you that illustrates both usage of a loading template to show until model is fully resolved and usage of disconnectOutlet to remove a template that is rendered to a specific outlet. I hope this will help you understand better. Best Regards.
You doing it wrong, read the guide. All you need is to create a loading.hbs file and put html for loading screen there.
Also, if you want to create a loading indicator that will be displayed while assets are loading and application is starting, you can use this addon
Also, Your setupController can be simplified to controller.setProperties(model);. setProperties doc
I'm make a search for a application in Ember 2 which my backend only accept a POST for this search, so Im trying send data through customize createRecord, but the behavior is completely different from I'm expected, two points I believe be a problem.
After several console.log(), I see my actions don't work, even action setted in route.
Inside Ember Inspector the route for this search haven't a model related
Anyone have a hint about why my route don't have a model related, follow the model declaration for this specific route.
model() {
return {
data: this.store.findAll('booking'),
booking: {}
};
}
PS: I edited the title, to be more clear about I need.
I believe you need to use Ember.RSVP.hash for that:
model() {
return Ember.RSVP.hash({
data: this.store.findAll('booking'),
booking: {}
});
}
I'm working on a webapp to teach myself Ember, and I've walked into one large issue:
The page halts while it is attempting to fetch json, and my IndexRoute and IndexController feel very bloated. Additionally, this.store.find('pokemon') uses the RESTAdapater, and can freeze the page from rendering anything (besides the loader) for up to 1.5 seconds.
App.IndexRoute = Ember.Route.extend({
model: function() {
var store = this.store;
return Ember.RSVP.hash({
pokeballs: App.Pokeball.all(),
pokemon: store.find('pokemon'),
status: App.Status.all(),
levels: App.Levels
});
}
});
Updated Question: As it is now, my IndexController is larger than I would like, and is acting as a mediator for the pokeballs and pokemon collections. I am thinking it would be a good idea to split up IndexController so that I have an IndexController, a PokemonListController, and a PokeballListController. The problems I have are:
How should I populate the content of the PokemonListController and PokeballListController if I am on '/', which maps to the IndexRoute?
Is this actually a good idea, am I treating controller's they way they are intended to be treated?
Webapp Demo: http://theirondeveloper.github.io/pokemon-catch-rate
Github: https://github.com/TheIronDeveloper/pokemon-catch-rate
On one hand you are not tied to a single controller in a route, there is generally only a single controller associated with a route, but you can always set more controllers if you need them to, remember they are decorators of your models.
App.IndexRoute = Ember.Route.extend({
model: function() {
return store.find('pokemon');
},
setupController: function(controller, model) {
var pokemonListController = this.controllerFor('pokemons');
var pokeballListController = this.controllerFor('pokeball');
controller.set('model', model); //this would be the index controller
pokemonListController.set('model', model.pokemon);
pokeballListController.set('model', model.pokeballs);
}
});
Also you can render your page if you need to, without waiting for the responses, Ember will handle updating your UI once the response is received. if your response is too slow, the user will see the page, and an empty list (in this case, empty list of pokemon), and then once the request is resolved, the list will fill up with it.
To do that, just return an empty array from your model hook, and update it async:
App.IndexRoute = Ember.Route.extend({
model: function() {
var pokemon = [];
var store = this.store;
store.find('pokemon').then(function(allPokemon) {
pokemon = allPokemon; //untested, you may need to push them instead
});
return Ember.RSVP.hash({
pokeballs: App.Pokeball.all(),
pokemon: pokemon,
status: App.Status.all(),
levels: App.Levels
});
}
});
Not seeing anything "bloated" about your IndexRoute or IndexController. It is true that a lot of Ember apps will have multiple routes and thus multiple controllers, but that happens when it makes sense to switch to other routes. If it doesn't make sense for your application - then what you have is great.
If you have multiple routes (and thus multiple controllers), the approach #Asgaroth suggested will work great for setting multiple controllers. Otherwise, if you only have a single route - there is really no need to have multiple controllers.
The fact that your data gets fetched and that takes some time is normal. Now, ideally this (data fetching) should only happen once and your data would then get cached and as you peruse around your other routes (which you currently do not have) your data would already be available to you without any extra penalty.
If you do need to have multiple controllers and are wondering how to communicate between them, you are probably looking for the needs API outlined here.
UPDATE
I took another look at the model hook and it is weird how 3 out of 4 things in there are not promises at all and don't look like they belong in there.
So, here is how you can clean that up.
App.IndexRoute = Ember.Route.extend({
model: function() {
return this.store.find('pokemon');
}
});
That's the only thing that belongs in there. The other properties might as well be properties on your controller, as in:
App.IndexController = Ember.Controller.extend({
levels: function(){
return App.Levels;
}.property(),
pokeballs: function(){
return App.Pokeball.all()
}.property(),
status: function(){
return App.Status.all();
}.property(),
Of course, you would then need to change references to those properties in your template and other code. So, for example, you would change from model.pokeballs to just pokeballs. You would also change from model.pokemon to just model
I submitted a pull request to show you the way I did this - see here
Not a full answer, but to reveal the magic between the route and controller ... here is how the model gets drop'd into the controller instance for you
App.IndexRoute = Ember.Route.extend({
model: function() {
return store.fin('pokemon');
},
setupController: function(controller, model) {
//the model that gets returned from the above method is added to the controller instance for you in this generated method on the route
controller.set('model', model); //also alias'd as content in older versions of ember
}
});
Obligatory version info:
"DEBUG: Ember : 1.6.0-beta.1+canary.ffa2c83c"
"DEBUG: Ember Data : 1.0.0-beta.7+canary.d55198c2"
"DEBUG: Handlebars : 1.3.0"
"DEBUG: jQuery : 2.1.0"
I have an ember data model set up like this
App.User = DS.model.extend({
username: DS.attr(),
sites: DS.hasMany('site', {async:true})
});
And a route set up like this:
App.SitesRoute = Ember.Route.extend({
setupController: function (controller, model) {
this.controllerFor('auth').get('model.sites').then(function(sites){
controller.set('model', sites);
});
});
});
The auth controller gives me the currently logged in user and I want the Sites route to only display sites that are relevant to the currently logged in user.
This however does not work and throws an error
"Error while loading route: App.SitesRoute<.setupController"
What is interesting is that this setupcontroller hook actually works if I throw a break point in there, no error occurs and the data loads fine in to the UI.
This leads me to believe that there is a problem with the promise loading going on here but I cannot workout why. I would have thought that when the 'model.sites' promise fulfills the controllers model gets set which in turn populates the content and my ui. But this does not seem to be the case.
Any ideas? What am I doing wrong here?
Edit 1
Here is a variation which has similar results. if I put a break point on the return statement in the model hook of the route, it works. Otherwise it does not
App.SitesRoute = Ember.Route.extend({
model: function () {
return this.controllerFor('auth').get('model.sites');
},
setupController: function (controller, model) {
controller.set('model', model);
}
});
Edit 2
Ok here is something that makes this code work. But seems to me is contrary to the docs which state this:
"In cases where data is available asynchronously, you can just return
a promise from the model hook, and Ember will wait until that promise
is resolved before rendering the template."
I had thought that the call to self.controllerFor('auth').get('sites') was a promise if the 'sites' relationship was marked 'asyc:true' am I mistaken in this?.
So I can do this and it works, which I guess it kind of simulating the break point:
App.SitesRoute = Ember.Route.extend({
model: function() {
var self = this;
return new Ember.RSVP.Promise(function(resolve) {
Ember.run.later(function() {
resolve(self.controllerFor('auth').get('sites'));
}, 3000);
});
},
setupController: function(controller,model) {
controller.set('content', model);
}
});
Edit 3
Ok, I have found something that works, which I will go with for now, but I am still unhappy with not understanding what is going on or why. There is something that I neglected to mention which is that I am using the ember-data-django-rest-adapter I cant tell if this is what is causing the issue despite several hours of debugging the internals of ember and the adapter.
Without further ado here is what ended up working:
App.SitesRoute = Ember.Route.extend({
setupController: function(controller,model) {
this.controllerFor('auth').get('content').then(function (user) {
user.get('sites').then(function (sites) {
controller.set('content', sites);
});
});
}
});
Any insights to why this works when the other approaches don't would be greatly appreciated.
What I would do to keep all controllers aware of the current user is to inject the currentUserController into all my controllers in the ember initializer. Then, you can get the currentUser from any point in your controller by accessing it like this.get('currentUser').]
In your case, I would try this and see if it works:
model: function() {
return this.controllerFor('auth').get('sites');
},
setupController: function(controller,model) {
model.then(function(response) {
controller.set('content', response);
}
}
I've found that when I have a model relationship that uses async: true I can expect that when I get that relationship the result is a promise, for example:
var stuff = model.get('relatedCollection');
var actualStuff;
if (typeof stuff.then === 'function') {
stuff.then(function (collection) {
actualStuff = collection;
});
} else {
actualStuff = stuff;
}
The above is pseudo code to illustrate that when you use aysc: true when you define your model reltionship that you most likely will see a promise when you get that related collection.
I've noticed that when the promise is resolved, maybe even when you have a breakpoint set, then when you get the related collection you may see the actual collection instead of the promise as a result.
So, when I do use aysc: true I typically use the branching code to first check if the result is thenable typeof thing.then === 'function' If so, I treat the assigned value as a promise; and use the thenable syntax to get the actual collection of models after the promise is resolved.
Edit 2013-03-02
This appears to be resolved in RC1
In previous versions of Ember.js, controllers would keep state assigned to them, but this seems to be an issue in Pre4.
So if I were to have this controller
App.UsersController = Ember.ArrayController.extend({
content: ['mike', 'jen', 'sofia'],
_content_observer: (function(){
/* I'm called, but my author doesn't know why */
console.log('Content was altered! But why? And by whom?');
}).observes('content')
});
The content is overwritten for some unexplained reason. I don't want to use ember data, but it seems like I'm being forced that direction.
This JS Fiddle exemplifies the issue.
What's going on? How do I stop it or is this so engrained in embers opinionatedness that I need to just accept it and go with the flow?
Edit
Taking this a bit further, it appears that whatever is setup as the model will be set to the content value, even if you override the setupController hook.
e.g.:
UsersRoute = Ember.Route.extend({
model: function() {
/*I should never be called, but I am. How curious.*/
return ['This','Shouldnt','Be','Assigned'];
},
setupController: function() {
/* According to http://emberjs.com/guides/routing/specifying-a-routes-model/, I should prevent the model from being assigned to content, but I don't */
}
});
The UsersController.content will end up with the value ['This','Shouldnt','Be','Assigned']
See this updated fiddle
This isn't really an ember-data thing. The new router sets controller's content property automatically. Instead of setting content from within the controller dedinition, customize the model that will be used for your route by overriding the model hook. For example:
App.UsersRoute = Ember.Route.extend({
model: function() {
return ['mike', 'jen', 'sofia', 'greta']
}
}
I modified your jsfiddle here: http://jsfiddle.net/WGYmg/
You may use the setupController method to set the controller's contents as you like:
setupController: function(controller) {
controller.set('content', []);
}
See this fiddle
Edit
You can use the model method to return the original content:
model: function () {
var c = this.controllerFor('users');
return c.get('content');
}
This is a bit hackish, but still..:)
See updated fiddle