Ember js using name for URL slug - ember.js

Is it possible to use another field in the URL? I would like to use the name but I have apply toLowerCase() first which I'm doing in the specific object. Here's my code. Everything works but the object data doesn't show up in the view... Any ideas? Thanks in advance!
<body>
<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 class="active">{{#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' slug}}{{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 :: {{ categories.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>
<script type="text/x-handlebars" id="help">
<p class="text-warning">Help me</p>
</script>
<script type="text/x-handlebars" id="account">
<p class="text-warning">Your bank account is ...</p>
</script>
app.js
App = Ember.Application.create({
LOG_TRANSITIONS:true
});
DS.RESTAdapter.configure("plurals", {
category: "categories"
});
App.Store = DS.Store.extend({
revision: 12,
adapter: DS.RESTAdapter.extend({
url: '/api'
})
});
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({
setupController: function(controller, category) {
controller.set('model', category);
}
});
var attr = DS.attr;
App.Category = DS.Model.extend({
name: attr('string'),
slug: function(){
return this.get('name').toLowerCase();
}.property('name')
});
Ember.Handlebars.registerBoundHelper('markdown', function(input) {
return new Handlebars.SafeString(showdown.makeHtml(input));
});
Ember.Handlebars.registerBoundHelper('date', function(date) {
return moment(date).fromNow();
});

What you can do is to hook into the serialize hook of your CategoryRoute and provide there the slug.
Example:
App.CategoryRoute = Ember.Route.extend({
setupController: function(controller, category) {
controller.set('model', category);
},
serialize: function(model) {
return {
category_slug: model.get("name").toLowerCase()
};
}
});
This way you can remove also the slug computed property in your model, and in your links you then do:
{{#each model}}
{{#linkTo 'category' this}}{{name}}{{/linkTo}}
{{/each}}
Hope it helps.

Related

Assertion failed: Your server returned a hash with the key category but you have no mapping for it

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'});

How do I pass model information to this each statement in a nested template?

I have an index route where I need to populate a menu in one outlet based on a list of models. However I cannot get the models to be represented in the each statement.
Here is the Category Model:
App.Category = DS.Model.extend({
title: DS.attr('string'),
parent: DS.belongsTo('App.Category')
})
And here is the indexRoute where I render it
App.IndexRoute = Em.Route.extend({
renderTemplate: function(){
this.render('index')
this.render('categoryMenu',
{
outlet: 'sidebar',
into: 'index',
model: function() {
return App.Category.find()
},
controller: App.CategoriesController
})
this.render('badgesList',{
outlet: 'badgesList',
into: 'index'
})
}
})
Index Template:
<script type="text/x-handlebars" data-template-name="index">
<div class="span3">
{{outlet sidebar}}
</div>
<div class="span8">
{{outlet badgesList}}
</div>
</script>
Nested Category Template
<script type="text/x-handlebars" data-template-name="categoryMenu">
<ul>
{{#each model}}
{{title}}
{{/each}}
</ul>
</script>
I have tried to change the each statement to several different things like controller or item in model but nothing is displayed.
Thank you for any help!
Make yourself CategoriesController first like this:
App.CategoriesController = Ember.ArrayController.extend({
content: function () {
return App.Category.find()
}.property()
});
rename your template just to categories
<script type="text/x-handlebars" data-template-name="categories">
<ul>
{{#each model}}
{{title}}
{{/each}}
</ul>
</script>
in your index template replace {{outlet}} with {{render 'categoies'}}
<script type="text/x-handlebars" data-template-name="index">
<div class="span3">
{{render 'categoies'}}
</div>
<div class="span8">
{{outlet badgesList}}
</div>
</script>
as last thing remove the call rendering categoryMenu.

Controller.set in IndexRoute

I have following js code:
App = Ember.Application.create({
LOG_TRANSITIONS: true
});
App.Router.map(function() {
this.resource('posts');
this.resource('about');
});
App.IndexRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set('title', "test");
}
});
App.PostsRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set('title', 'test');
}
});
And following html page:
<script type="text/x-handlebars">
<div class="container">
<div class="navbar">
<div class="navbar-inner">
<ul class="nav">
<li>{{#linkTo index}}Home{{/linkTo}}</li>
<li>{{#linkTo posts}}Posts{{/linkTo}}</li>
<li>{{#linkTo about}}About{{/linkTo}}</li>
</ul>
</div>
</div>
{{title}} // <--- no title here
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" id="about">
About template
</script>
<script type="text/x-handlebars" id="posts">
<h1>{{title}}</h1> // <--- works here
Recent posts
</script>
I got rendered {{title}} variable only at posts route. It doesn't work at index route though. I was reading manual and tried to do exactly as is mentioned there: http://emberjs.com/guides/routing/defining-your-routes/

Mark the current detail entry in a master list

I have a list of users which are displayed in a master view on the left side (Twitter Bootstrap CSS). Details of each user can be shown by clicking the show button. They will be displayed on the right side (detail).
How can I remove the show button for the currently displayed user? e.g. #/users/1 shouldn't render the show button for the first user.
index.html
<script type="text/x-handlebars" data-template-name="users">
<div class='row'>
<div class='span4'>
<table class='table table-striped'>
{{#each model}}
<tr>
<td>{{lastName}}</td>
<td>{{#linkTo 'user' this}}<button class="btn" type="button">show</button>{{/linkTo}}</td>
</tr>
{{/each}}
</table>
</div>
<div class='span8'>
{{outlet}}
</div>
</div>
</script>
<script type="text/x-handlebars" data-template-name="user">
<h1>{{firstName}} {{lastName}}</h1>
</script>
app.js
App = Ember.Application.create();
App.Store = DS.Store.extend({
revision: 12,
adapter: 'DS.FixtureAdapter'
})
App.Router.map(function() {
this.resource('users', function() {
this.resource('user', { path: ':user_id' })
})
});
App.UsersRoute = Ember.Route.extend({
model: function() {
return App.User.find();
}
});
App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string')
})
App.User.FIXTURES = [{
id: 1,
firstName: "Bill",
lastName: "Clinton"
}, {
id: 2,
firstName: "Barack",
lastName: "Obama"
}]
Ember provides some support for doing what you want. By default it sets the "active" css class on the selected element. You can find more information about that here: http://emberjs.com/api/classes/Ember.LinkView.html (note that the {{#linkTo}} is just a helper based on the LinkView).
The simplest way to override this behavior, since instead of "active" you want to hide the button, would be to make use of the hide class that comes with Twitter Bootstrap. So your users template would look like:
<script type="text/x-handlebars" data-template-name="users">
<div class='row'>
<div class='span4'>
<table class='table table-striped'>
{{#each model}}
<tr>
<td>{{lastName}}</td>
<td>{{#linkTo 'user' this activeClass="hide"}}<button class="btn" type="button">show</button>{{/linkTo}}</td>
</tr>
{{/each}}
</table>
</div>
<div class='span8'>
{{outlet}}
</div>
</div>
</script>
<script type="text/x-handlebars" data-template-name="user">
<h1>{{firstName}} {{lastName}}</h1>
</script>

Emberjs rendering wrong template

I am working with EmberJs and can't figure out why the following code won't render the 'new' template. When I navigate to /shops, I get a list of shops and a create button linking to '/shops/new', but when I click create, the 'new' template isn't rendered and instead stays the same as 'shops'. I can navigate to each individual shop fine, just not new.
App.js
window.App = Ember.Application.create();
App.Router.reopen({
location: 'history'
});
// Router
App.Router.map(function() {
this.resource('shops', function() {
this.route('new');
});
this.resource('shop', { path: '/shops/:shop_id' });
});
App.ShopsRoute = Ember.Route.extend({
model: function() {
return App.Shop.find();
}
});
App.ShopsNewRoute = App.ShopsRoute.extend({
model: function() {
return App.Shop.createRecord();
},
setupController: function( controller, model ) {
return this._super(),
controller.set( 'content', model )
}
});
App.ShopsNewController = Ember.ObjectController.extend();
// Models
App.Store = DS.Store.extend({
revision: 11,
adapter: DS.RESTAdapter
});
App.Shop = DS.Model.extend({
name: DS.attr('string'),
body: DS.attr('string'),
});
Index.html
<!DOCTYPE html>
<html>
<head>
<title>Ember/Rails App</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<script type="text/x-handlebars" data-template-name="application">
<div class="row">
<div class="twelve columns">
<h1>Ordr</h1>
<hr>
{{outlet}}
</div>
</div>
</script>
<script type="text/x-handlebars" data-template-name="shops/new">
<h2>New Shop</h2>
</script>
<script type="text/x-handlebars" data-template-name="shops">
{{#each shop in controller}}
{{#linkTo "shop" shop}} {{ shop.id }}{{/linkTo}}
{{/each}}
{{#linkTo 'shops.new'}}Create{{/linkTo}}
</script>
<script type="text/x-handlebars" data-template-name="shop">
<h2>{{name}}</h2>
<p>{{body}}</p>
</script>
</body>
</html>
The way you have set up your routes and templates, you are telling Ember that you want to navigate to shops.new and keep all the list of shops showing even while you are in shops.new.
If that is in fact the scenario that you want, all you need to do is add an {{outlet}} inside the shops template:
<script type="text/x-handlebars" data-template-name="shops">
{{#each shop in controller}}
{{#linkTo "shop" shop}} {{ shop.id }}{{/linkTo}}
{{/each}}
{{#linkTo 'shops.new'}}Create{{/linkTo}}
{{outlet}}
</script>
However, if that is not what you really intend, and you actually want the list of shops to be hidden when you transition to shops.new, then you will need to change a couple of things.
change your App.ShopsRoute to App.ShopsIndexRoute :
App.ShopsIndexRoute = Ember.Route.extend({
model: function() {
return this.store.find('shop');
}
});
and your shops template to shops/index template:
<script type="text/x-handlebars" data-template-name="shops/index">
{{#each shop in controller}}
{{#linkTo "shop" shop}} {{ shop.id }}{{/linkTo}}
{{/each}}
{{#linkTo 'shops.new'}}Create{{/linkTo}}
</script>
Any of those 2 methods should fix your problem, depending on what your intentions are.