I am wondering how is possible to generate url for a given route.
My scenario
I have list of calls (db entity) and user can select several calls and share them with other people via email.
After submition of selected calls is created db row with hash and by relation contains selected calls. Now I need generate link which can be sended by e-mail. This link is not the same route as list of call's route.
So the question is: Is it possible to generate url by route and params in Ember.js? Thank you.
You can use Router#generate which delegates to the router.js library.
Ember 2.5 Example
App = Ember.Application.create();
App.Router.map(function() {
this.resource('post', { path: '/posts/:post_id' }, function(){
this.route('edit');
});
});
App.Post = Ember.Object.extend();
App.IndexRoute = Ember.Route.extend({
model: function() {
return [
App.Post.create({
id: 5,
title: 'I am post 5'
}),
App.Post.create({
id: 6,
title: 'I am post 6'
}),
App.Post.create({
id: 7,
title: 'I am post 7'
})];
},
actions: {
showUrl: function(post) {
alert(this.router.generate('post.edit', post));
}
}
});
Ember 1.3 Example
App = Ember.Application.create();
App.Router.map(function() {
this.resource('post', { path: '/posts/:post_id' }, function(){
this.route('edit');
});
});
App.Post = Ember.Object.extend();
App.IndexRoute = Ember.Route.extend({
model: function() {
return [
App.Post.create({
id: 5,
title: 'I am post 5'
}),
App.Post.create({
id: 6,
title: 'I am post 6'
}),
App.Post.create({
id: 7,
title: 'I am post 7'
})];
},
actions: {
showUrl: function(post) {
alert(this.router.generate('post.edit', post));
}
}
});
This is what the {{#link-to ...}} helper uses under the hood.
This can be done in any Ember.js class with the RouterService. It is available since Ember.js 2.15 and in 3.x. Routing functions are no longer confined to Routes.
Ember 2.15, 3.x Example
import Component from '#ember/component';
import { inject as service } from '#ember/service';
export default Component.extend({
router: service(),
actions: {
showUrl(post) {
alert(this.get('router').urlFor('post.edit', post));
}
}
});
Related
I have one problem in developing Angular project.
I tried to find the solution on how to implement the route relative redirects with
When the URL redirects, in which origin redirect has its relative the query params and the fragment.
For example, in the guide of Angular.io.
const heroesRoutes: Routes = [
{ path: 'heroes', redirectTo: '/superheroes' },
{ path: 'hero/:id', redirectTo: '/superhero/:id' },
{ path: 'superheroes', component: HeroListComponent },
{ path: 'superhero/:id', component: HeroDetailComponent }
];
in hero-detail, goback() function to navigate back to the HeroListComponent.
I added relativeTo: this.route. But it is not working.
gotoHeroes(hero: Hero) {
let heroId = hero ? hero.id : null;
// Pass along the hero id if available
// so that the HeroList component can select that hero.
// Include a junk 'foo' property for fun.
this.router.navigate(['/heroes', { id: heroId, foo: 'foo' }], {relativeTo: this.route});
}
When configuring to redirect to superheroes, I don't know how to implement this feature.
You need a relative route, so depending on where you are, this should work to go back:
this.router.navigate(['../', { id: heroId, foo: 'foo' }, {relativeTo: this.route}]);
You can use something like -
this.router.navigate(
['hero','12345'],
{
relativeTo: this.route,
queryParams: {
type: 'value',
},
}
);
I have a dynamic iron route with the template explicitly set, however iron router attempts to render the path instead of the template.
http://localhost:3000/blog/example-post
Couldn't find a template named "Blog:permalink" or "blog:permalink". Are you sure you defined it?
Router.route('/blog/:permalink'), {
template: 'blogPost',
name: 'blogPost',
path: '/blog/:permalink',
data: function () {
return Blogs.findOne({ permalink: this.params.permalink, published: true });
}
}
Router.route('blog'), {
path: '/blog',
waitOn: function () {
return [
Meteor.subscribe('blogs')
]
}
}
You closed route ) without adding there the options object ( see , after ) ). That's why iron:router tries to generate template name from path:
Router.route('/blog/:permalink'), {
Should be:
Router.route('/blog/:permalink', {
template: 'blogPost',
name: 'blogPost',
path: '/blog/:permalink',
data: function () {
return Blogs.findOne({ permalink: this.params.permalink, published: true });
}
})
I'm a Beginner trying to learn SPA / Durandal, Knockout etc...
Need some help with my routes for a Admin drop down button.
Here are my routes in the shell.js so far:
var routes = [
{ route: '', moduleId: 'home', title: 'Home', nav: 1 },
{ route: 'downtime', moduleId: 'downtime', title: 'Downtime', nav: 2 },
{ route: 'downtimeadd', moduleId: 'downtimeadd', title: 'Add A New Downtime', nav: false, settings: { admin: true } },
{ route: 'production', moduleId: 'production', title: 'Production', nav: 4 }];
I've also created adminRoutes in the shell.js to bind to the view with KO:
var adminRoutes = ko.computed(function () {
return router.routes.filter(function (r) {
return r.settings.admin;
});
});
From research, they say that router.routes is an array, but when I bind this to my view the button shows 0 items for the drop down.
When I do (below) I can get all the routes, but I only need the admin routes...
var adminRoutes = ko.computed(function () {
return router.routes;
});
How should I proceed? It seems like router.routes is not actually an array?
If I try to print it out to the console:
console.log(router.routes[0]); //Chrome says its undefined...
console.log(router.routes); //Shows array of size 4...
Yup no clue... Help would be appreciated!
Update:-------------------------------------------------------------------
Even after RainerAtSpirit's suggestions I still get an empty array when I filter in code.
var router = require('plugins/router');
//Array size 4
console.log(router.routes);
//Array size 0
console.log(router.routes.filter(function (r) { return r; }));
However when I run this in the "chrome console":
var router = require('plugins/router')
router.routes.filter(function (r) { return r; })
I do get the array back, so I don't know why in code it doesn't work.
I got this to work, although maybe not as perfectly as I would like.
The first problem I noticed was an issue that others were not seeing. In my example (with druandal 2.0 from the HotTowel template version 1.1 for VS 2013) I noticed that this code for adding the adminRoutes was called prior to the activate method. Therefore, my route.routes was an empty array. To fix this problem, I switched to just using the array of routes that the routes are getting mapped from the config.js with (note: config.routes rather than route.routes):
var adminRoutes = ko.computed(function () {
return config.routes.filter(function(r) {
return r.admin;
});
});
Finally, I'm return "r.admin". This is the part that would like to make work better because I added an admin property to the admin route without the "settings" group, see "admin: true":
var routes = [
{ route: '', moduleId: 'equipment', title: 'Equipment', nav: 1 },
{ route: 'testresults', moduleId: 'testresults', title: 'Test Results', nav: 2 },
{ route: 'testresultdetail/:id', moduleId: 'testresultdetail', title: 'View a test result', nav: false },
{ route: 'testresultadd', moduleId: 'testresultadd', title: 'Add a Test Result', nav: false, caption: '<i class="fa fa-plus"></i> Add Test Result', admin: true }
];
With these two changes, the menu item showed up.
In knockout when you make a property to be observable it turns in to a function wrapping ,so when you need to get the actual value you need to access it as a function. That means
router.routes[0] will be undefined but router.routes()[0] will work correct !
You can try
var adminRoutes = ko.computed(function () {
return router.routes().filter(function (r) {
return r.settings.admin;
});
});
Here is the issue I'm having.
Say you have an app with two models, Project and Post. All posts belong in a specific project. So, the paths to the posts contain the project ID as well (example.com/:project_id/:post_id).
How can I transition from post X on project A to post Y in project B? Simply calling transitionToRoute('post', postA) from post B's route will retain post B's project ID in the url.
Here's a fiddle describing my predicament. As you can see, when using the project links at the top of the page, the correct posts appear in the correct projects. However, click the link after "other post" and you'll see how Ember is happy to display the post in the context of the incorrect project.
How can I transition between these "cousin" routes in Ember?
The JS:
window.App = Ember.Application.create({
LOG_TRANSITIONS: true
});
App.Store = DS.Store.extend({
adapter: DS.FixtureAdapter
});
App.store = App.Store.create();
App.Router.map(function(match) {
this.resource('projects');
this.resource('project', {path: ':project_id'}, function(){
this.resource('post', {path: ':post_id'});
});
});
App.Project = DS.Model.extend({
title: DS.attr('string'),
posts: DS.hasMany('App.Post')
});
App.Post = DS.Model.extend({
title: DS.attr('string'),
body: DS.attr('string'),
project: DS.belongsTo('App.Project')
});
App.Project.FIXTURES = [
{
id: 1,
title: 'project one title',
posts: [1]
},
{
id: 2,
title: 'project two title',
posts: [2]
}
];
App.Post.FIXTURES = [
{
id: 1,
title: 'title',
body: 'body'
},
{
id: 2,
title: 'title two',
body: 'body two'
}
];
App.ApplicationController = Ember.ObjectController.extend({
projects: function() {
return App.Project.find();
}.property()
});
App.PostController = Ember.ObjectController.extend({
otherPost: function(){
id = this.get('id');
if (id == 1) {
return App.Post.find(2);
} else {
return App.Post.find(1);
}
}.property('id')
});
And the templates:
<script type="text/x-handlebars" data-template-name="application">
{{#each project in projects}}
<p>{{#linkTo project project}}{{project.title}}{{/linkTo}}</p>
{{/each}}
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="project">
<h2>{{title}}</h2>
{{#each post in posts}}
{{#linkTo post post}}{{post.title}}{{/linkTo}}
{{/each}}
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="post">
<h3>{{title}}</h3>
<p>{{body}}</p>
other post: {{#linkTo post otherPost}}{{otherPost.title}}{{/linkTo}}
</script>
I found 3 issues.
1. Your belongsTo fixture data is missing the id's they belong to.
App.Post.FIXTURES = [
{
id: 1,
title: 'title',
body: 'body',
project:1
},
{
id: 2,
title: 'title two',
body: 'body two',
project:2
}
];
2. When you transition to a resource, if you only send in a single model, it will only change that resource's model, if you want to update multiple models in the path, send in all the models necessary
{{#linkTo 'post' otherPost.project otherPost}}{{otherPost.title}
3. linkTo routes should be in quotes. (in the future it won't work properly without them), see example above
http://jsfiddle.net/3V6cy/1
BTW, thanks for setting up the jsfiddle, it makes me like a million times more likely to answer a question. Good luck working with ember, we love it!
Cheers! I've got routes:
TravelClient.Router.map(function() {
this.resource('tours', function() {
this.resource('tour', { path: ':tour_id' }, function(){
this.route('seats');
});
});
});
And a template:
<script type="text/x-handlebars" data-template-name="tour/seats">
{{...}}
</script>
Seats is an attribute of Tour object:
TravelClient.Tour.find(1).get('seats');
12
And I extend my TourSeats route like this:
TravelClient.TourSeatsRoute = Ember.Route.extend({
model: function(params) {
return TravelClient.Tour.find(params.tour_id).get('seats');
}
});
Question: how to render tour's seats in template?
UPDATE:
My fixtures looks like that:
TravelClient.Store = DS.Store.extend({
revision: 11,
adapter: 'DS.FixtureAdapter'
});
TravelClient.Tour = DS.Model.extend({
title: DS.attr('string'),
description: DS.attr('string'),
seats: DS.attr('number')
});
TravelClient.Tour.FIXTURES = [{
id: 1,
title: "Brighton, England",
description: "Lorem ipsum dolor ... .",
seats: 12
},...
And I've changed my route extend to this:
TravelClient.TourSeatsRoute = Ember.Route.extend({
model: function(params) {
return TravelClient.Tour.find(params.tour_id);
}
});
And in template:
<script type="text/x-handlebars" data-template-name="tour/seats">
{{tour.seats}}
</script>
UPDATE 2:
<script type="text/x-handlebars" data-template-name="tour/seats">
{{controller.model.seats}}
</script>
and it gives undefind back.
After some debugging I founded out, that there is no any id in params and params is empty, thats why I can't get the right model in TourSeatsRoute function.
If you're using ember-1.0-pre.4+, the params are only returned for the specific route you're on, not the whole URL. There's some discussion about this here.
I believe the desired approach at this time is to use this.modelFor passing the name of the parent resource you've set up in the parent route. So in your case, it would be:
TravelClient.TourSeatsRoute = Ember.Route.extend({
model: function() {
return this.modelFor("tour");
}
});
You just need to return the model from the model method:
TravelClient.TourSeatsRoute = Ember.Route.extend({
model: function(params) {
return TravelClient.Tour.find(params.tour_id);
}
});
And then in your template you can do the following where controller is the context:
{{model.seats}}
I'm still new to EmberJS but I would've written my router and routes like this.
I'm not sure that you need to wrap the post resource inside the posts resource. Note the double plurals in ToursSeatsRoute
TravelClient.Router.map(function() {
this.resource('tours', function() {
this.route('/:tour_id/seats');
});
});
This would give you the following urls:
/tours - you could map this to an ArrayController
/tours/:tour_id/seats - you could map this to an ObjectController
TravelClient.ToursSeatsRoute = Ember.Route.extend({
model: function(params) {
console.log(params);
return TravelClient.Tour.find(params.tour_id);
}
});
Give it a go? Or maybe put your code a in a JSFiddle?