I am working on a admin and client portal in Meteor JS using Iron:Router.
I know i can create a route using:
this.route('tasks',{path:'/projects', layoutTemplate: 'adminLayout'});
But is it possible to make a route with a sub directory such as:
this.route('tasks',{path:'/admin/projects', layoutTemplate: 'adminLayout'});
So that way i can also have a sub directory of:
this.route('/admin/projects', {name: 'admin.projects', template: 'projects', layoutTemplate: 'adminLayout'}
and
this.route('/client/projects', {name: 'client.projects', template: 'projects', layoutTemplate: 'adminLayout'}
Thanks for any input.
All the paths you have can coexist in one app quite happily.
The router (or your browser) doesn't have any concept of directories/subdirectories, all it understands are strings and regular expressions. The nesting is purely something we (should) create to enable ourselves to understand how an app/api(/codebase, etc) is structured.
As Sasikanth points out that is not the full error message. However looking at packages/iron_middleware-stack/lib/middleware_stack.js line 31 it's easy to confirm what is happening:
throw new Error("Handler with name '" + name + "' already exists.");
This is within the Router.route function, which is documented here.
Router.route('/post/:_id', {
// The name of the route.
// Used to reference the route in path helpers and to find a default template
// for the route if none is provided in the "template" option. If no name is
// provided, the router guesses a name based on the path '/post/:_id'
name: 'post.show',
// To support legacy versions of Iron.Router you can provide an explicit path
// as an option, in case the first parameter is actually a route name.
// However, it is recommended to provide the path as the first parameter of the
// route function.
path: '/post/:_id',
// If we want to provide a specific RouteController instead of an anonymous
// one we can do that here. See the Route Controller section for more info.
controller: 'CustomController',
// If the template name is different from the route name you can specify it
// explicitly here.
template: 'Post',
// and more options follow
So for the code you included above, you provide explicit paths. Therefore the first parameter is the route name. These must be unique as they are used to lookup the path in the pathFor, urlFor and linkTo helpers. As you are not providing an explicit template option, the name is also used for that, but your code is throwing this exception before it gets that far.
I think what you were trying to achieve is this:
this.route('/projects', {name: 'projects', template: 'tasks', layoutTemplate: 'adminLayout'});
this.route('/admin/projects', {name: 'admin.projects', template: 'tasks', layoutTemplate: 'adminLayout'});
this.route('/client/projects', {name: 'client.projects', template: 'tasks', layoutTemplate: 'adminLayout'});
Related
Please may someone help me with a params/named route question.
I'm trying to achieve an optional named route change at the first level while maintaining nested structure. Is there a way to achieve this using named routes?
For example imagine use case, either:
/europe/train
or
/car/europe/spain
I would have a new named route going to train instead of car and the behaviour to link to the full path of:
/train/europe/spain
Currently this takes you to the base route with the first level /train removing nested routes, you then need to reselect Europe and Spain.
This is the current setup I'm trying to achieve this:
path: '/:transportSlug?',
name: 'Transport',
...
children: [
{
path: ':regionSlug',
name: 'Region',
...
children: [
{
path: ':countrySlug',
name: 'Country',
...
<router-link :to="{
name: 'Transport',
params: {
transportSlug: filter.slug,
regionSlug: region.slug,
countrySlug: country.slug
}
}">
This is passing in 3 params when navigating to a new base route and all 3 are being correctly passed. I can output them in the view which makes me think it may be a technical limitation/misunderstanding somewhere.
I'm aware of path routing and creating the full path with a computed properly.
Example here
Thank you.
With help from Posva from Vue I was able to solve this.
My approach and understanding of how Vue Router worked was slightly incorrect by thinking that you needed to reference the named route in a nested tree that you wanted to update.
To update the Transport type in /euope/spain I would need to instead reference the Country named route and update the param for the transport.
<router-link :to="{
name: 'Country',
params: {
transportSlug: filter.slug,
}
}">
This maintains the correct URL while updating the Transport type.
Hope this may be of some help to someone.
When I try to create a router-link with an array as parameter, the link works but I get the following warning :
missing param for named route "start-run": Expected "files" to not repeat, but received ["aaa"]
router.js
...
{
path: '/start-run/:config?/:files?',
name: 'start-run',
component: StartRun,
props: true
},
...
file.vue
...
<router-link :to="{name: 'start-run', params: { config: 'test', files: ['aaa'] }}">...</router-link>
...
I didn't find documentation to fix this warning.
I believe the error message comes from path-to-regexp version 1.7.0, which is used by Vue Router:
https://github.com/pillarjs/path-to-regexp/blob/v1.7.0/index.js#L185
The problem is that an array is treated as multiple values but the parameter in your path does not support multiple values.
It is unclear what you are trying to achieve by passing an array to files. The route path you've defined uses a ? suffix for :files?, which makes it optional but doesn't allow for an array. Perhaps you meant :files* or :files+ instead? Or maybe you just want to pass the first item in the array?
I try to create a new pieces page, kind of a blog style in apostrophe cms. I have trainings, trainings-widgets and trainings-pages folders. I registered them all in app.js; pieces by themselves and widgets work beautifully. The problem is when I try to add page of Trainings type. I get Error: template not found: pages/trainings-page.html in console.
In apostrophe-pages/index.js I have it configured:
module.exports = {
types: [{
name: 'home',
label: 'Home'
},
{
name: 'trainings-page',
label: 'Trainings'
}
]
}
And in trainings-pages/index.js:
module.exports = {
name: 'trainings-page',
label: 'Training Page',
extend: 'apostrophe-pieces-pages',
piecesFilters: []
}
I can't figure out what might be wrong here.
Edit: A showcase git:
https://github.com/msdsk/apostrophe-error
In addition to the module directory name being incorrect, as noted:
lib/modules/trainigs-pages should be:
lib/modules/trainings-pages
When we fix this we graduate to a new error:
Error: template not found: trainings-pages:layout.html
You are extending layout.html. But that file is in a different module, apostrophe-pages, that trainings-pages does not extend, and so it is never found. This is our fault for not recommending a more universal location for layout.html in the tutorial.
You can solve it two ways:
OPTION ONE
Move layout.html to lib/modules/apostrophe-templates/views/layout.html.
Always extend it like this:
{% extends 'apostrophe-templates:layout.html' %}
This "cross-module" path syntax will find it in the apostrophe-templates module no matter what module you're in.
OPTION TWO
Another option is to set the viewsFolderFallback option of apostrophe-templates in app.js, like this:
'apostrophe-templates': {
viewsFolderFallback: __dirname + '/views'
},
And create a views/ folder at the top level of the project and move layout.html there. Then you don't have to use the special syntax, you can just write layout.html and if the module doesn't have its own, it'll look in the fallback folder. This is what we usually do in-house.
I'll discuss with the rest of the Apostrophe core team whether the tutorial should recommend option one or option two, and adjust the apostrophe CLI to set up option two automatically if that is preferred.
(There is a third option: you can put things in lib/modules/apostrophe-module/views and it works as a fallback without any configuration. That's because all modules eventually inherit from apostrophe-module. But our feeling in the past has been that this approach is not very intuitive.)
There is a typo error on your module directory's name : lib/modules/trainigs-pages should be lib/modules/training-pages
Really new to ember and trying to setup basic (in my mind) routes.
I have calendars resource and I want to display individual calendars.
My app/router.js has the following:
this.route('calendar', {path: 'calendars/:calendar_id'}, function () {
this.route('show');
this.route('edit');
});
this.route('calendars', function(){
this.route('create');
});
Folders are as following:
app/routes: [
calendars: [create, index],
calendar: [edit, show]
]
app/templates: [
calendars: [create, index]
calendar: [edit, show]
]
In app/routes/calendar/show.js:
import Ember from 'ember';
export default Ember.Route.extend({
model(params) {
return this.store.findRecord('calendar', params.calendar_id);
}
});
Problems start when I go to http://SERVER/calendars/5/show (5 is a :calendar_id part, SERVER is what hosts ember app) :
when I log params - they are undefined
In dev tools I see that Ember somehow makes a POST request to my server as http://SERVER/calendars/5
(a :calendar_id part, SERVER is on same domain and where my back-end resides).
This happens regardless if I comment out model() function in app/routes/calendar/show.js file.
Apparently Ember knows what calendar_id to use for that request.
But I don't know where that call to the server happens:
If I comment out model(){} altogether, my template renders model record (the calendar record that Ember fetches).
If I on the other hand try to log params in model() and I comment out this.store.findRecord part out, the params are undefined and it raises an error.
I thought at first that it is my DS.RESTAdapter since I have defined updateRecord changes to fake PUT request (my server does not allow that), but I commented out the whole file and it still does this query.
I've cleaned both dist/, tmp/, upgraded to 2.9.0, but it does the same thing.
I have no controllers defined
How does Ember make POST request if model() hook is missing from route, I have no controllers difined. Also how do I fix it so that it works? ;p
Edit [2]:
I am trying this now and I think it kinda works, but looks ugly:
this.route('calendars',{ path: '/calendars'}, function(){
this.route('create');
});
this.route('calendar', { path: '/' }, function () {
this.route('show', { path: '/calendars/:calendar_id/show' });
this.route('edit', { path: '/calendars/:calendar_id/edit' });
});
this.route('index', { path: ''});
Ember is smart enough to generate a default route if you do not create one, and a default model if you do not create a model function.
It does this based on the routes name ie if your route is "calendar" it generates a model function based on the "calendar" model.
Try explicitly define your route path with the parameters as per ember docs:
https://guides.emberjs.com/v2.9.0/routing/defining-your-routes/
this.route('calendar', function () {
this.route('show', { path: '/:calendar_id/show' });
this.route('edit', { path: '/:calendar_id/edit' });
this.route('create');
});
I have this resource with a nested route in my ember app:
router.js:
Router.map(function() {
this.resource('posts', function () {
this.route('show', {path: '/:id'});
});
});
What is the convention in ember for my controllers? Do I create a separate file for each URL, or does the show handler go in /controllers/posts.js? Or is there perhaps multiple correct ways of doing this?
This is what I have so far in /routes/posts.js:
import Ember from 'ember';
var PostsRoute = Ember.Route.extend({
model: function() {
return posts;
}
});
var posts = [
{
id: '1',
title: 'Object nr one',
content: 'This is the content of Object nr one.'
},
{
id: '2',
title: 'Obelix',
content: 'A fat gaul. From a comic book.'
},
{
id: '3',
title: 'Werner',
content: 'Wat soek werner hier? Dis mos nou belaglik man.'
}
];
export default PostsRoute;
And this is /controllers/posts.js:
import Ember from "ember";
export default Ember.ArrayController.extend({});
I would appreciate if someone showed me the correct way of doing things in this example.. I'm really struggling to find proper examples on the web.
Please note that I'm using ember CLI
"Show handler" never goes to controller file, it's rather a Route. You create separate route, controller, template for each of your resource or route directives. You can tell controller that it should have the same behaviour as other controller, or use a mixin. For example:
router.coffee:
#resource 'training', ->
#route 'chest'
#route 'shoulders'
Means you need following structure:
app/routes/training[your parent resource]/chest.js[your child route]
app/routes/training/shoulders.js
If you need controller for each of this routes you would need files with following paths:
app/controllers/training/chest.js
app/controllers/training/shoulders.js
And templates:
app/templates/training/chest.js
app/templates/training/shoulders.js
It's because I've defined training as resource(parent) and routes as its children.
If you use Ember CLI you can use commands like:
ember g controller training/shoulders
or:
ember g route training/shoulders
Last command will generate you: Route, template and entry in router.js. You can use this commands so you won't have worry too much about your directory structure.
However, it's important to remember that when you define resource inside a resource - child resource isn't really a child and it shouldn't be placed inside parent resource directory. For example:
#resource 'tracks', ->
#resource 'track', path: '/track/:track_id', ->
#route 'edit'
Means you need 2 directories to store route files:
app/routes/tracks/
index.js
app/routes/track/
edit.js
Instead of app/routes/tracks/track/edit.
So, in your example, for following router:
Router.map(function() {
this.resource('posts', function () {
this.route('show', {path: '/:id'});
});
});
app/routes should look like this:
app/routes:
- posts.js # main route for whole resource
- posts/ # directory which contains files for routes inside posts resource
- show.js # posts/show route