I am trying to build an smarthome app and I am stuck with calling nested routes with serveral parameters. I want to show an information which user is logged in and below that template which is in my parent route i want to render child pages for showing households. After a specific household is chosen, i want to show the rooms in the household and then devices. This is my router.js
Router.map(function() {
this.route('about');
this.route('users', function() {
});
this.route('households', { path: '/:user_id' }, function() {
this.route('index', { path: '/:user_id' })
this.route('rooms',{ path: '/:household_id' });
this.route('devices', { path: '/:room_id' });
});
});
export default Router;
I link to households like this
<h3>{{#link-to "households" user.id}}{{user.surname}}{{/link-to}}</h3>
and now I want to declare a model in the route of households.js which returns an user from the ember data store and render the parent template. Afterwards the model should redirect to households.index with the user.id too and the households.index.hbs should render all households below the parent template. My households.js route looks like this:
export default Route.extend({
model(params){
{
return this.get('store').findRecord('user', params.user_id);
}
}
});
and my household.index route like this
export default Route.extend({
model(params) {
return this.get('store').findAll('household').then(results => results.filter((site) => {
return site.get('member').filter(x => x == params.user_id).length > 0;
}));
}
});
Actually the following error occurs:
Error: Assertion Failed: You attempted to define a
{{link-to "households.rooms"}}
but did not pass the parameters required for generating its dynamic segments. You must provide paramuser_id
togenerate
.
In general I need serveral parameters in all nested routes/subroutes, because I need the user_id for example in the route devices for checking if the calling user is a admin. If he is an admin he would be able to add and edit devices. And i need the room_id to show only devices which are in the chosen room.
Is there any way to pass serveral parameters or using the controllers in a way, I can handle my purpose?
In my understanding, you haven't set up the routing hierarchy well.
Assuming that you have multiple users, and every user has multiple households, and every household has multiple rooms, I suggest you make your router.js
like this:
Router.map(function() {
this.route('about');
this.route('users', function() {
this.route('index'); // Lists all the users, URL looks like /users
this.route('single', { path: '/:user_id' }, function() {
this.route('index'); // Shows a single user, URL looks like /users/123
this.route('households', function() {
this.route('index'); // Shows all households a user with user_id has, URL looks like /users/123/households
this.route('single',{ path: '/:household_id' }, function() {
this.route('index'); // Shows a single household, URL looks like /users/123/households/456
this.route('rooms', function() {
this.route('index'); // Shows all rooms a household with household_id has, URL looks like /users/123/households/456/rooms
this.route('single', { path: '/:room_id' }); // Shows a single room, URL looks like /users/123/households/456/rooms/789
});
});
});
});
});
});
Feel free to omit this.route('index');
lines in the router if you want, but make sure you make a route to handle this. Your templates should look something like this.
// templates/users.hbs
{{outlet}}
// templates/users/index.hbs
<h1>This shows all the users</h1>
<ul>
{{#each model as |user|}}
<li>{{user.name}}</li>
{{/each}}
</ul>
// templates/users/single.hbs
{{outlet}}
// templates/users/single/index.hbs
<h1>This shows a single user with id {{model.id}}</h1>
<p>This is the user named {{model.name}}.</p>
// templates/users/single/households.hbs
{{outlet}}
// ... And so on
You should implement model()
hooks in such a way that they fetch only what you really need. For the lists, you fetch them in the index route.js
of the type you want to display (i.e. the model()
of routes/users/index.js
for users), and for the single record not in the index, but in the single route.js
(i.e. for a single household in the model()
of routes/users/single/households/single.js
) to make that model accessible to both the index route and the child routes.
So, with this configuration, your links should look something like this:
// All users
{{#link-to 'users'}}All users{{/link-to}}
// Single user
{{#link-to 'users.single' user.id}}{{user.name}}{{/link-to}}
// Households of a single user
{{#link-to 'users.single.households' user.id}}All households of {{user.name}}{{/link-to}}
// Specific household of a single user
{{#link-to 'users.single.households.single' user.id household.id}}Household {{household.name}} of {{user.name}}{{/link-to}}
// Rooms within a specific household
{{#link-to 'users.single.households.single.rooms' user.id household.id}}All rooms within household {{household.name}} of {{user.name}}{{/link-to}}
Note: Make sure to specify models and their relationships properly to make your life easier from the very beginning. So, for the configuration assumed at the beginning of this answer, you should make your models something like this:
// models/user.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
households: DS.hasMany('household')
});
// models/household.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
user: DS.belongsTo('user'),
rooms: DS.hasMany('room')
});
// models/room.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
household: DS.belongsTo('household')
});
If you organize your models like this, then Ember will let you link from a rooms page (route) to the user's page like this:
{{#link-to 'users.single' model.household.user}}Go to user{{/link-to}}