I would like to access a global query param in a nested route (child route).
The localisation setting is stored in a Global Query Param on the Application Route:
App.ApplicationController = Ember.Controller.extend({
queryParams: ['localSelected']
});
Now I would like to access that value in my App.IndexRoute
App.TranslateRoute = Ember.Route.extend({
model: function(params){
params.localSelected **NOT AVAILABLE**
}
});
Finally found a solution by setting a global variable every time the query params updates.
In the Application Controller
App.ApplicationController = Ember.Controller.extend({
queryParams: ['localSelected'],
localSelectedOberver: function(){
App.set('localSelected', this.get('localSelected'));
}.observes('localSelected').on('init'),
localSelected: "en"
});
And because the controller initializes to late, you also need:
App.ApplicationRoute = Ember.Route.extend({
model: function(params){
App.set('localSelected', params.localSelected)
}
)}
})
Then whenever you need to know the localisation query param value you can just go:
App.get('localSelected');
Related
I've defined some properties in a controller for a pagination:
import Ember from 'ember';
export default Ember.ArrayController.extend({
limit: 1,
skip: 0,
pageSize: 1
}
});
I'd like to access limit in the Route's model-function but I don't know how.
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
console.log(this.get('controller').get('limit')) <- doesnt work for example
return this.store.find('post', {limit: 1,
sort:'createdAt desc'});
}
});
Maybe you should take a look at the queryParams option (http://emberjs.com/guides/routing/query-params/).
With query params you can set the limit to be a query param in your URL like http://yourdomain.com/someroute?limit=15.
Your controller will become:
export default Ember.ArrayController.extend({
queryParams: ['limit'], // Here you define your query params
limit: 1 // The default value to use for the query param
});
You route will become:
export default Ember.Route.extend({
model: function(params) {
return this.store.find('post', {
limit: params.limit, // 'limit' param is available in params
sort:'createdAt desc'
});
}
});
Alternative:
If you don't want to use query params, another solution might be to define the limit property in one of the parent route's controller. By doing so you can access the property in the model hook by doing:
this.controllerFor('parentRoute').get('limit');
In my EmberJS application I am displaying a list of Appointments. In an action in the AppointmentController I need to get the appointments owner, but the owner always returns "undefined".
My files:
models/appointment.js
import DS from 'ember-data';
export default DS.Model.extend({
appointmentStatus: DS.attr('number'),
owner: DS.hasMany('person'),
date: DS.attr('Date')
});
models/person.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string')
});
templates/appointmentlist.js
{{#each appointment in controller}}
<div>
{{appointment.date}} <button type="button" {{action 'doIt'}}>Do something!</button>
</div>
{{/each }}
controllers/appointmentlist.js
export default Ember.ArrayController.extend({
itemController: 'appointment'
});
controllers/appointment.js
export default Ember.ObjectController.extend({
actions:{
doIt: function(){
var appointment = this.get('model');
var owner = appointment.get('owner'); //returns undefined
//Do something with owner
}
}
});
Now, I know I can change the owner-property to owner: DS.hasMany('person', {async: true}), and then handle the promise returned from appointment.get('owner');, but that is not what I want.
I have discovered that if I do this {{appointment.owner}} or this {{appointment.owner.name}} in the appointmentlist template, the owner record is fetched from the server. So I guess Ember does not load relationships unless they are used in the template.
I think that the solution to my problem is to use the appointmentlists route to fetch the record in the belongsTo relationship. But I can't figure out how.
Maybe something like this?
routes/appointmentlist.js
export default Ember.Route.extend({
model: function() {
return this.store.find('appointment');
},
afterModel: function(appointments){
//what to do
}
});
EDIT
I did this:
routes/appointmentlist.js
export default Ember.Route.extend({
model: function() {
return this.store.find('appointment');
},
afterModel: function(appointments){
$.each(appointments.content, function(i, appointment){
var owner= appointment.get('owner')
});
}
});
and it works, but I do not like the solution...
You are still asynchronously loading those records, so if you are fast enough you could still get undefined. It'd be better to return a promise from the afterModel hook, or just modify the model hook to do it all.
model: function() {
return this.store.find('appointment').then(function(appointments){
return Ember.RSVP.all(appointments.getEach('owner')).then(function(){
return appointments;
});
});
}
or
model: function() {
return this.store.find('appointment');
},
afterModel: function(model, transition){
return Ember.RSVP.all(model.getEach('owner'));
}
Another way to go is:
export default Ember.Controller.extend({
modelChanged: function(){
this.set('loadingRelations',true);
Ember.RSVP.all(this.get('model').getEach('owner')).then(()=>{
this.set('loadingRelations',false);
});
}.observes('model')
});
This way the transition finishes faster and the relations are loaded afterwards. The loading-state can be observed through loadingRelations.
When there are a lot of relations to load I think this gives a better UX.
You want to load all the assocations in the route, because you want to use Fastboot for search engines and better first time site opened experience.
Holding your assocation loading after primary models are loaded, might not be the best decision.
I am using a syntax to load all assocations in the route:
let store = this.store;
let pagePromise = store.findRecord('page', params.page_id);
let pageItemsPromise = pagePromise.then(function(page) {
return page.get('pageItems');
});
return this.hashPromises({
page: pagePromise,
pageItems: pageItemsPromise
});
And for this.hashPromises I got a mixin:
import Ember from 'ember';
export default Ember.Mixin.create({
hashPromises: function(hash) {
let keys = Object.keys(hash);
return Ember.RSVP.hashSettled(hash).then(function(vals) {
let returnedHash = {};
keys.forEach(function(key) {
returnedHash[key] = vals[key].value;
});
return returnedHash;
});
}
});
I read at
http://emberjs.com/guides/controllers/
the following code:
I have a search box and want to send the value of the search box to the SearchController.
App.ApplicationController = Ember.Controller.extend({ // the initial
value of the `search` property search: '',
actions: {
query: function() {
// the current value of the text field
var query = this.get('search');
this.transitionToRoute('search', { query: query });
} } });
How can i get the query parameter in the SearchController and then show it in search.hbs?
I am working with ember- cli.
The router is
import Ember from 'ember';
var Router = Ember.Router.extend({
location: NENV.locationType
});
Router.map(function() {
this.route('search');
});
export default Router;
I set up a route under routes/search.js
export default Ember.Route.extend({
model : function (params) {
console.debug("hi");
return params;
},
setupController: function(controller,model) {
var query = model.query;
console.debug("query is");
console.debug(query);
}
});
When debugging i get an error:
ember More context objects were passed than there are dynamic segments
Thanks,
David
You need to define your search route to be dynamic, so if you change your route definition to something like this
Router.map(function() {
this.resource('search', {path: '/search/:query});
})
This should work as you are expecting. Let me know if anything.
Cheers!
I have a route like this:
App.PeopleRoute = Ember.Route.extend({
model: function()
{
return App.Persons.find(personId);
}
});
where personId is loaded asynchronically and is a normal JavaScript variable outside Ember. Now when route is displayed it gets the current PersonId and displays proper data. But when i change the value of personId it does not update the view.
So my question is what is a way to refresh this route to find records with new personId?
This is because model hook is executed only when entered via URL for routes with dynamic segments. Read more about it here.
The easiest solution for this would be to use transitionTo.
App.PeopleRoute = Ember.Route.extend({
model: function(params)
{
return App.Persons.find(params.personId);
},
actions: {
personChanged: function(person){
this.transitionTo("people", person);
}
}
});
App.PeopleController = Em.Controller.extend({
observeID: function(){
this.send("personChanged");
}.observes("model.id");
});
I'm trying to access an instance of a controller that has been wired automatically using App.initialize();
I've tried the below but it returns a Class not an instance.
Ember.get('App.router.invitesController')
I have a quick post about this exact subject on my Blog. It's a little big of a different method, but seems to work well for Ember.js RC1.
Check it out at: http://emersonlackey.com/article/emberjs-instance-of-controller-and-views
The basic idea is to do something like:
var myController = window.App.__container__.lookup('controller:Posts');
This answer works with RC1/RC2.
Now you can use the needs declaration in order to make the desired controller accessible. Here's an example:
Suppose I want to get something from my SettingsController from within my ApplicationController. I can do the following:
App.SettingsController = Ember.Controller.extend({
isPublic: true
});
App.ApplicationController = Ember.Controller.extend({
needs: 'settings',
isPublicBinding: 'controllers.settings.isPublic'
});
Now in the context of my ApplicationController, I can just do this.get('isPublic')
You can access a controller instance inside an action in the router via router.get('invitesController'), see http://jsfiddle.net/pangratz666/Pk4k2/:
App.InvitesController = Ember.ArrayController.extend();
App.Router = Ember.Router.extend({
root: Ember.Route.extend({
route: '/',
index: Ember.Route.extend({
route: '/',
connectOutlets: function(router, context) {
var invitesController = router.get('invitesController');
},
anAction: function(router) {
var invitesController = router.get('invitesController');
}
})
})
});
You can access any controller instance by name using lookup method of Application instance.
To get Application instance you can use getOwner from any route or controller.
const controllerName = 'invites';
Ember.getOwner(this).lookup(`controller:${controllerName}`));
Works for me in Ember 2.4 - 3.4.