If the user access the site directly www.mysite.com the routes should transition to first product page of first category.
If the user copy paste url of a particular product. user should be navigate to that particular product page.
I need some directions how to go about it as when I copy a product url www.mysite.com/Men/shirts it navigate to default first category first product as per my transitionTo
My router.js looks like this
MyApp.Router.map(function () {
this.resource('categories', {path: '/'}, function () {
this.resource('category', { path: '/:category_id'}, function () {
this.resource('product', { path: '/:product_id' });
});
});
});
my categories route's after model look like this
afterModel: function(categories,transition){
this.transitionTo('category',categories.get('firstObject'));
},
my category route after model looks like this
afterModel: function (category) {
var self = this;
self.transitionTo('product', category.get('products').get('firstObject'));
}
You should probably do the default transition from the Index Routes.
MyApp.CategoriesIndexRoute = Em.Route.extend({
afterModel: function(model) {
this.transitionTo('category',model.get('firstObject'));
}
});
MyApp.CategoryIndexRoute = Em.Route.extend({
afterModel: function(model) {
this.transitionTo('product', Em.get(model, 'products.firstObject'));
}
});
Child resources/routes inherits parent's model since this PR. You can use this.modelFor if you are using older version
Working Demo
This is an example following your routing structure,
http://emberjs.jsbin.com/viyagaga/1/edit
specific category: http://emberjs.jsbin.com/viyagaga/1#/category/2
specific product: http://emberjs.jsbin.com/viyagaga/1#/category/2/product/4
hbs
<script type="text/x-handlebars" data-template-name="categories">
this is all categories<br/>
<ul>
{{#each category in model}}
<li>
{{#link-to "category" category.id}}
id:{{category.id}} name:{{category.name}}
{{/link-to}}
</li>
{{/each}}
</ul>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="category">
this is category {{model.name}}<br/>
with products:<br/>
<ul>
{{#each product in model.products}}
<li>
{{#link-to "product" product.id}}
id:{{product.id}} name:{{product.name}}
{{/link-to}}
</li>
{{/each}}
</ul>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="product">
this is product:<br/>
{{model.name}}<br/>
</script>
js
App = Ember.Application.create();
App.Router.map(function () {
this.resource('categories', {path: '/'}, function () {
this.resource('category', { path: 'category/:category_id'}, function () {
this.resource('product', { path: 'product/:product_id' });
});
});
});
App.IndexRoute = Ember.Route.extend({
beforeModel: function() {
this.transitionTo("categories");
}
});
App.CategoriesRoute = Ember.Route.extend({
model:function(){
return allCategoriesData;
}
});
App.CategoryRoute = Ember.Route.extend({
model: function(params) {
return allCategoriesData.findBy("id",parseInt(params.category_id,10));
}
});
App.ProductRoute = Ember.Route.extend({
model: function(params) {
return this.modelFor("category").products.findBy("id",parseInt(params.product_id,10));
}
});
var allCategoriesData = [
{"id":1,"name":"Category1",
"products":[
{"id":1, "name":"product11"},
{"id":2, "name":"product12"}
]
},
{"id":2,"name":"Category2",
"products":[
{"id":3, "name":"product21"},
{"id":4, "name":"product22"},
{"id":5, "name":"product23"}
]
},
{"id":3,"name":"Category3",
"products":[
{"id":6, "name":"product31"}
]},
{"id":4,"name":"Category4",
"products":[
{"id":7, "name":"product41"},
{"id":8, "name":"product42"},
{"id":9, "name":"product43"},
{"id":10, "name":"product43"}
]}
];
If you need to show each route on its own window without the corresponding master then the routing and hbs templates need to change as follows,
http://emberjs.jsbin.com/cajalosu/1/edit
hbs
<script type="text/x-handlebars" data-template-name="categories">
this is all categories<br/>
<ul>
{{#each category in model}}
<li>
{{#link-to "category" category.id}}
id:{{category.id}} name:{{category.name}}
{{/link-to}}
</li>
{{/each}}
</ul>
</script>
<script type="text/x-handlebars" data-template-name="category">
this is category {{model.name}}<br/>
with products:<br/>
<ul>
{{#each product in model.products}}
<li>
{{#link-to "product" model.id product.id}}
id:{{product.id}} name:{{product.name}}
{{/link-to}}
</li>
{{/each}}
</ul>
</script>
<script type="text/x-handlebars" data-template-name="product">
this is product:<br/>
{{model.name}}<br/>
</script>
js
....
App.Router.map(function () {
this.route('categories', {path: '/'});
this.resource('category', { path: 'category/:category_id'});
this.resource('product', { path: 'category/:category_id/product/:product_id' });
});
....
App.ProductRoute = Ember.Route.extend({
model: function(params) {
return allCategoriesData.findBy("id",parseInt(params.category_id,10)).products.findBy("id",parseInt(params.product_id,10));
}
});
....
EDIT - transition to first object of first category
http://jsbin.com/felalizo/1#/category/1/product/1
Related
Taking the following as an example:
<script type="text/x-handlebars">
<h2>Welcome to Ember.js</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
<ul>
{{#each model as |item|}}
<li>{{item}}</li>
{{/each}}
{{magnus-component name=firstName}}
</ul>
</script>
<script type="text/x-handlebars" data-template-name="components/magnus-component">
<!-- Doesn't appear -->
{{name}}
</script>
...and
App = Ember.Application.create();
App.Router.map(function() {
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return ['red', 'yellow', 'blue'];
},
name: "Magnus",
surname: "Womble",
fullName: Ember.computed('name', 'surname', function(){
return this.get('name') + ' '+this.get('surname');
})
});
Which can be found in the following jsbin:
http://emberjs.jsbin.com/higako/edit?html,js,output
How do you correctly pass the fullName property to the component template?
You should move your logic from IndexRoute to IndexController:
App.IndexController = Ember.Controller.extend({
name: "Magnus",
surname: "Womble",
fullName: Ember.computed('name', 'surname', function(){
return this.get('name') + ' '+this.get('surname');
})
});
And then, if you use:
{{magnus-component name=fullName}}
instead of (firstName isn't defined anywhere):
{{magnus-component name=firstName}}
It will work.
Working demo.
I got an error with
GET http://localhost:63342/people 404 (Not Found)
and
Assertion failed: Error while loading route:....
Why does this error http://localhost:63342/people 404 appears? I don't have this route.
here is my js code:
window.Models = Ember.Application.create();
Models.Router.map(function () {
//匹配路由后显示person_list模板
this.resource('persons', { path: '/' });
});
Models.PersonsRoute = Ember.Route.extend({
model:function(){
return this.store.find('person');
},
setupController:function(controller, model){
controller.set('content', model)
}
});
Models.Person = DS.Model.extend({
name: DS.attr('string'),
description:DS.attr('string')
});
Models.Person.FEATURES = [{
name:'Kratos Zhang',
description:'a c# coder in 7agree.'
}]
and template
<script type="text/x-handlebars" data-template-name="persons">
<ul>
{{#each item in persons}}
<li>
<h4>{{item.name}}</h4>
<p>{{item.description}}</p>
</li>
{{/each}}
</ul>
why isn't it working?
You can override pathForType in the adapter if that isn't your endpoint, Ember Data by default pluralizes endpoints
App.ApplicationAdapter = DS.RESTAdapter.extend({
pathForType: function(type) {
//return Ember.String.pluralize(type);
return type;
},
});
This isn't necessary, you can delete it
setupController:function(controller, model){
controller.set('content', model)
}
persons doesn't exist in the template
{{#each item in model}}
<li>
<h4>{{item.name}}</h4>
<p>{{item.description}}</p>
</li>
{{/each}}
or
{{#each item in controller}}
<li>
<h4>{{item.name}}</h4>
<p>{{item.description}}</p>
</li>
{{/each}}
My Ember app automatically show a list of tasks. The model are populated like this:
model: function(){
return this.store.find('task');
}
My question is, how i can show a filtered version of this model in view?
If i create a route to this? tasks/completed?
Updating:
I created a route:
App.Router.map(function(){
this.resource('tasks', function(){
this.resource('task', { path:'/:task_id' }, function(){
this.route('edit');
});
this.route('create');
this.route('completed');
});
});
Then i call:
App.TasksCompletedRoute = Em.Route.extend({
// What i have to put here to show only completed tasks?
});
This is my project: https://github.com/fernandoperigolo/ember-crud-todo
You can create a filteredContent property, and set with all the tasks in the TasksRoute, and with just the completed tasks in TasksCompleted. Like the following:
Routes:
App.TasksRoute = Em.Route.extend({
model: function(){
return this.store.find('task');
},
setupController: function(controller, tasks) {
controller.set('filteredContent', tasks);
},
actions:{
check:function(task){
task.set('done', true);
task.save();
},
uncheck:function(task){
task.set('done', false);
task.save();
}
}
});
App.TasksCompletedRoute = Em.Route.extend({
setupController: function() {
this.controllerFor('tasks').set('filteredContent', this.modelFor('tasks').filterBy('done', true));
}
});
So in your tasks template use the filteredContent instead of controller:
<script type="text/x-handlebars" id="tasks">
{{#link-to "tasks.create"}} Add task {{/link-to}}
<h2>Task List:</h2>
<ul>
{{#each task in filteredContent}}
<li>
{{#if task.done}}
<button {{action "uncheck" task}}>Uncheck</button>
{{else}}
<button {{action "check" task}}>Check</button>
{{/if}}
{{#link-to "task" task}}{{task.title}}{{/link-to}}
</li>
{{else}}
<li>no tasks… :(</li>
{{/each}}
</ul>
{{outlet}}
</script>
EDIT: I found this very interesting question and answer here, but unfortunately it does not work with Ember 1.0. It would be great if someone could edit it for ember 1.0. The JsFiddle is here.
I want to articulate my app around (a) first language choice, then (b) a page choice, so I have the following routes
App.Router.map(function () {
this.resource('lang', { path: '/:lang_id' }, function() {
this.resource('page', { path: '/:page_id' });
});
});
Implemented by
App.ApplicationRoute = Em.Route.extend({
model: function() {
return this.store.find('lang');
}
});
App.LangIndexRoute = Em.Route.extend({
model: function(params) {
return this.store.find('lang', params.lang_id);
}
});
App.PageRoute = Em.Route.extend({
model: function(params) {
return this.store.find('page', params.page_id);
}
});
model is :
App.Lang = DS.Model.extend({
name: DS.attr('string'),
pages: DS.hasMany('page')
});
App.Page = DS.Model.extend({
lang: DS.belongsTo('lang'),
name: DS.attr('string'),
title: DS.attr('string'),
extra_title: DS.attr('string'),
});
App.Lang.FIXTURES = [
{
id: 'en',
name: 'EN',
pages: [1, 2]
},
{
id: 'fr',
name: 'FR',
pages: [3]
},
];
App.Page.FIXTURES = [
{
id: 'page-item1',
name: 'ITEM1',
title: 'ITEM1',
extra_title: 'item1',
},
{
id: 'page-item2',
name: 'ITEM2',
title: 'ITEM2',
extra_title: 'item2',
},
{
id: 'page-item3',
name: 'ITEM3',
title: 'ITEM3',
extra_title: 'item3',
},
];
And the following markup :
<script type="text/x-handlebars" >
<nav>
<ul>
{{#each}}
<li>{{#linkTo 'lang' this currentWhen="lang" activeClass="selected" }}{{name}}{{/linkTo}}</li>
{{/each}}
</ul>
</nav>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="lang/index">
<nav>
<ul class="projects">
{{#each pages}}
<li>{{#link-to "page" activeClass="selected"}}{{name}}{{/link-to}}</li>
{{else}}
<li>Loading...</li>
{{/each}}
</ul>
</nav>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="page">
</script>
I cannot get the pages listed for the given language to be enumerated when loading the lang.index template.
How could I do that, or would there be a better way to manage language with ember ?
I think my mistake (or misunderstanding of the framework) is either in the model hook or in the iterator of #each...
I unblock the situation by modifying the route, model and template as below.
One of the problem was due to the need of declaring the hasmany relationship as async. (using FIXTURES), the other were related to the linkTo in the template.
However I still don't have exactly the behavior I want in the pages/index template. All pages are rendered, instead of only the one of the given language.
App.Router.map(function () {
this.resource('pages', { path: '/:lang_id' }, function() {
this.route('page', { path: '/:page_id' });
});
App.ApplicationRoute = Em.Route.extend({
model: function() {
return this.store.find('lang');
}
});
App.PagesIndexRoute = Em.Route.extend({
model: function(params) {
console.log(params.lang_id);
return this.store.find('page', params.lang_id);
}
});
App.Lang = DS.Model.extend({
name: DS.attr('string'),
pages: DS.hasMany('page',{async:true})
});
<script type="text/x-handlebars" >
<nav>
<ul>
{{#each}}
<li>{{#linkTo 'pages' this currentWhen="pages" activeClass="selected" }}{{name}}{{/linkTo}}</li>
{{/each}}
</ul>
</nav>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="lang/index">
<nav>
<ul class="projects">
{{#each pages}}
<li>{{#link-to "pages.page" this activeClass="selected"}}{{name}}{{/link-to}}</li>
{{else}}
<li>Loading...</li>
{{/each}}
</ul>
</nav>
{{outlet}}
</script>
Note really sure what to do. I'm trying to use a slug instead of ID but when I try to go directly to a link (/categories/source), I get the error. I've tried adding mappings in the RESTadapter but it hasn't worked. I ha
I've a feeling that my problem is in my CategoryRoute/model code but I can't see to get the right combo. Any help is appreciated.
To be honest, I don't know why it has to make two REST calls when it's already got the model info available. Any help is appreciated, thanks!
Json responses
{"categories":[{"id":1,"name":"Misc","slug":"misc"},{"id":2,"name":"Technology","slug":"technology"},{"id":3,"name":"Ecommerce","slug":"ecommerce"},{"id":4,"name":"Visitor","slug":"visitor"},{"id":5,"name":"Content","slug":"content"},{"id":6,"name":"evars","slug":"evars"},{"id":7,"name":"Marketing","slug":"marketing"},{"id":8,"name":"Props","slug":"props"},{"id":9,"name":"Source","slug":"source"}]}
{"category":{"id":2,"name":"Technology","slug":"technology"}}
Html file
<script type="text/x-handlebars">
<div class="container">
<div class="navbar navbar-inverse">
<a class="navbar-brand" href="#">LayerSpark</a>
<ul class="nav navbar-nav">
<li>{{#linkTo 'categories'}}Categories{{/linkTo}}</li>
<li>{{#linkTo 'help'}}Help{{/linkTo}}</li>
<li>{{#linkTo 'account'}}Account{{/linkTo}}</li>
</ul>
</div>
</div>
<div class="container">
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" id="categories">
<div {{bindAttr class=":row"}}>
<div {{bindAttr class=":col-lg-4"}}>
<ul>
{{#each model}}
<li>{{#linkTo 'category' this}}{{name}}{{/linkTo}}</li>
{{/each}}
</ul>
</div>
<div {{bindAttr class=":col-lg-8"}}>
{{outlet}}
</div>
</div>
</script>
<script type="text/x-handlebars" id="category">
Post:<br>
My name is :: {{ name }}<br>
My id is :: {{id}}<br>
My slug is :: {{slug}}<br>
</script>
<script type="text/x-handlebars" id="categories/index">
<p class="text-warning">Please select a Category</p>
</script>
App.js
App = Ember.Application.create({
LOG_TRANSITIONS:true
});
var attr = DS.attr;
App.Category = DS.Model.extend({
name: attr('string'),
slug: attr('string')
});
DS.RESTAdapter.configure("plurals", {
category: "categories"
});
App.Store = DS.Store.extend({
revision: 12,
adapter: DS.RESTAdapter.create({
url: '/api',
mappings:{
category:'App.Category'
}
})
});
App.Router.map(function() {
this.resource('about');
this.resource('categories', function() {
this.resource('category',{path:':category_slug'});
});
this.resource('help');
this.resource('account');
});
App.CategoriesRoute = Ember.Route.extend({
model: function() {
return App.Category.find();
}
});
App.CategoryRoute = Ember.Route.extend({
model: function(route,model) {
console.log(route);window.mod = model;
return App.Category.find({slug:route.category_slug});
},
serialize: function(model) {
return {
category_slug: model.get('slug')
};
}
});
Ember.Handlebars.registerBoundHelper('markdown', function(input) {
return new Handlebars.SafeString(showdown.makeHtml(input));
});
Ember.Handlebars.registerBoundHelper('date', function(date) {
return moment(date).fromNow();
});
I used the following router setup so that I could have a resource of Post corresponding to a route of /posts/:id. Also gives comments belonging to posts.
this.resource('posts', function() {
this.route('new');
});
this.resource('post', { path: '/posts/:post_id' }, function() {
this.resource('comments', function() {
this.route('new');
this.route('create');
});
this.route('comment', { path: 'comments/:comment_id'});
});
I had to define the categories resource separately and then explicitly state that post was under the /posts route in the definition of the resource. Maybe you need a router like:
this.resource('categories', function() {});
this.resource('category',{path:'/categories/:category_slug'});