I am just starting out with Ember.js and I am using ember-rails on the back end. The problem that I am having is that I am getting a list of items but no data is being rendered in my template.
router.js.coffee
App.Router.map (match)->
# match('/').to('index')
#resource "stories"
stories_route.js.coffee
App.StoriesRoute = Ember.Route.extend
model: ->
App.Story.find()
stories.handlebars
<h1>Stories</h1>
<ul>
{{#each story in controller}}
<li>{{story.title}} A</li>
{{else}}
<li>There are no stories.</li>
{{/each}}
</ul>
{{outlet}}
Here is the JSON that I am getting back from Rails:
{
"stories":[
{
"story":{
"id":1,
"title":"Test",
"description":"This is a test story"
}
}
]
}
Edit:
I am able to get the correct template to render, it is just that the data is empty.
Here is what the HTML looks like:
<div id="ember295" class="ember-view">
<h1>Stories</h1>
<ul>
<script id="metamorph-2-start" type="text/x-placeholder">
</script>
<script id="metamorph-4-start" type="text/x-placeholder">
</script>
<li>
<script id="metamorph-5-start" type="text/x-placeholder">
</script>
<script id="metamorph-5-end" type="text/x-placeholder">
</script>
A
</li>
<script id="metamorph-4-end" type="text/x-placeholder">
</script>
<script id="metamorph-2-end" type="text/x-placeholder">
</script>
</ul>
<script id="metamorph-3-start" type="text/x-placeholder">
</script>
<script id="metamorph-3-end" type="text/x-placeholder"></script>
</div>
If stories is your first route and accessible at "/" then you can define a path like:
App.Router.map () ->
#resource('stories', {path: '/'})
OR you can define an index route and redirect from there like:
App.IndexRoute = Ember.Route.extend
redirect: ->
#transitionTo('stories')
See here a working jsbin that shows the second concept.
EDIT
I guess your problem is now that if your result contains a collection of records you need to remove the additional story level in your JSON resulting in something like:
{
"stories":[
{
"id":1,
"title":"Test",
"description":"This is a test story"
}
]
}
and for a single record e.g. /stories/123 your JSON should look like:
{
"id":1,
"title":"Test",
"description":"This is a test story"
}
Hope it helps
Related
I don't understand templates and routes.
My code:
<script type="text/x-handlebars" data-template-name="application">
Hello
<nav>
{{#link-to 'index'}}Index{{/link-to}}
{{#link-to 'about'}}About{{/link-to}}
{{#link-to 'contact'}}Contact{{/link-to}}
</nav>
</script>
<script type="text/x-handlebars" data-template-name="about">
about
</script>
<script type="text/x-handlebars" data-template-name="contact">
favorites
</script>
and router.js:
App.Router.map(function () {
this.route("index", { path: "/" });
this.route("about", { path: "/about" });
this.route("contact", { path: "/contact" });
});
What is wrong? Output is blank page. There appeared a problem when I had inserted {{#link-to}} code.
I did that by an emberjs guide.
You need to define a place where your templates you are linking to should display, such a placeholder is called an outlet, so simply add {{outlet}} where in you application template you want your routes corresponding templates to be rendered into:
Also note, the linkTo helper is called linkTo and not link-to depending on the ember release you are using:
<script type="text/x-handlebars" data-template-name="application">
Hello
<nav>
{{#linkTo 'index'}}Index{{/linkTo}}
{{#linkTo 'about'}}About{{/linkTo}}
{{#linkTo 'contact'}}Contact{{/linkTo}}
</nav>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="about">
about
</script>
<script type="text/x-handlebars" data-template-name="contact">
favorites
</script>
Working jsbin.
Hope it helps.
I am modelling an administrative interface that helps manage database tables. There are two models: [DbxTables, DbxColumns]. I want to allow the user to choose a table using Boostrap's tab-menu and then be able to see the columns in that table. This mostly works. For instance, if I type http://my.domain.com/index.html#/performance where performance is the name of the table I get the following:
If I decide to go to another table by manipulating the URL -- for instance http://my.domain.com/index.html#/food-- then it will successfully switch to the food columns in the right-hand pane. The problems come in when I use my {{linkTo}} links in the left-hand tab menu. One of two things happens:
If the {{linkTo}} looks like {{linkTo 'columns' this}} then it makes the URL parameter something like <App.DbxTable:ember371:performance> rather than just performance
If the {{linkTo}} looks like {{linkTo 'columns' this.id}} then it sets the ULR parameter correctly (or at least so it appears to in the URL window) but the if I click on "meal" in the left-hand tab menu I get the following error: Object meal has no method 'addArrayObserver'. If I click on something else it follows that error message with "Object meal has no method 'removeArrayObserver' ".
In both of the above cases, after receiving an error, the column names on the right hand side do not update. The first style of {{linkTo}} is what the screencast from Tom Dale seemed to suggest was the right syntax. However, seeing that the links were off I came up with the this.id approach. Any help would be greatly appreciated.
For some additional code context (router.js):
App.Router.map(function() {
this.resource('about');
this.resource('dbx', function() {
this.resource('columns', { path: ':dbx_table'});
});
this.resource('oauth');
this.resource('postTypeMappings');
});
App.DbxRoute = Ember.Route.extend({
model: function() {
return App.DbxTable.find();
}
});
App.ColumnsRoute = Ember.Route.extend({
model: function(table) {
return App.DbxColumn.find(table);
}
});
Model: dbx_table.js
App.DbxTable = DS.Model.extend({
name: DS.attr("string"),
desc: DS.attr("string"),
db_column: DS.attr("string"),
columns: DS.attr("raw")
});
Model: dbx_column.js
App.DbxColumn = DS.Model.extend({
name: DS.attr("string"),
dbType: DS.attr("string"),
insight: DS.attr("string"),
enum: DS.attr("string"),
staticUom: DS.attr("string"),
uomContext: DS.attr("string"),
jsonStruct: DS.attr("string"),
desc: DS.attr("string")
});
Model: store.js
App.Store = DS.Store.extend({
revision: 12,
adapter: DS.RESTAdapter.reopen({
namespace: 'api/lifegadget'
})
});
DS.RESTAdapter.registerTransform('raw', {
deserialize: function(serialized) {
return serialized;
},
serialize: function(deserialized) {
return deserialized;
}
});
UPDATE (adding handlebars):
In order to provide some more detail. Here are the handlebars templates:
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Ember Starter Kit</title>
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/bootstrap.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<script type="text/x-handlebars">
<div class="navbar">
<div class="navbar-inner">
<a class="brand" href="#">Admin</a>
<ul class="nav">
<li>{{#linkTo "dbx"}}DBX{{/linkTo}}</li>
<li>{{#linkTo "postTypeMappings"}}Post Mappings{{/linkTo}}</li>
<li>{{#linkTo "oauth"}}OAuth{{/linkTo}}</li>
<li>{{#linkTo "about"}}About{{/linkTo}}</li>
</ul>
</div>
</div>
<div id="outlet-target">
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" id="about">
<div class='about'>
Admin Screen
</div>
</script>
<script type="text/x-handlebars" id="dbx">
<div class='dbx'>
<div id="dbx-table-pane" class="tabbable tabs-left">
<ul class="nav nav-tabs">
{{#each model}}
<li>
{{#linkTo "columns" this}}{{db_column}}{{/linkTo}}
</li>
{{/each}}
<li id="add-table">
<em>Add DBX Table</em>
</li>
</ul>
<div id="dbx-main" class="tab-content">
{{outlet}}
</div
</div>
</script>
<script type="text/x-handlebars" id="columns">
The columns are:
<ul>
{{#each model}}
<li>{{name}}</li>
{{/each}}
</ul>
</script>
<script src="js/libs/jquery-1.9.1.js"></script>
<script src="js/libs/handlebars-1.0.0-rc.3.js"></script>
<script src="js/libs/ember-1.0.0-rc.2.js"></script>
<script src="js/libs/ember-data-12.js"></script>
<script src="js/app.js"></script>
<script src="js/router.js"></script>
<script src="js/models/store.js"></script>
<script src="js/models/dbx_table.js"></script>
<script src="js/models/dbx_column.js"></script>
</body>
</html>
UPDATE 2:
I've now added a short video that demonstrates the problem: https://vimeo.com/63388787
This looks similar to this question: How to show the string value of a non id field for a model in an ember.js route?
I think you will need to use the serialize hook in your ColumnsRoute to define how the model is turned into the URL dynamic segment.
App.ColumnsRoute = Ember.Route.extend({
model: function(table) {
return App.DbxColumn.find(table);
},
//dbx_table matches the dynamic route name in your router, and I am assuming
// you want to use the DbxColumn.name as the URL parameter
serialize: function(model) {
return {dbx_table: model.get('name')};
}
});
The model hook handles turning a URL into a model object when the URL is directly navigated to, and the serialize hook is used to construct the URL when a route is transitioned to using an already existing object, such as when transitionTo or a {{#linkTo}} is used.
I'm possibly reading the docs wrong. Can someone please check out my gist and tell me why the invoices/index template is not rendering?
When I read the ember.js docs it states it should render
posts
↳posts/index
(invoices/index in my case). The invoices template renders however.
Handlebars:
<script type="text/x-handlebars" data-template-name="application">
<h1>Ember Committers</h1>
<nav>
{{#linkTo "index"}}Index{{/linkTo}}
{{#linkTo "about"}}About{{/linkTo}}
{{#linkTo "invoices"}}Invoices{{/linkTo}}
</nav>
{{ outlet }}
</script>
<script type="text/x-handlebars" data-template-name="invoices">
<h1>Invoices</h1>
</script>
<script type="text/x-handlebars" data-template-name="invoices/index">
<ul>
{{#each invoice in invoices }}
<li>{{#linkTo "show" invoice.id}}{{ invoice.id }}{{/linkTo }}</li>
{{/each }}
</ul>
</script>
<script type="text/x-handlebars" data-template-name="invoices/show">
<p>Invoice - {{ name }}</p>
</script>
<script type="text/x-handlebars" data-template-name="phone">
<p>Contributor - {{ title }}</p>
</script>
<script type="text/x-handlebars" data-template-name="about">
<p>About {{ title }}</p>
</script>
<script type="text/x-handlebars" data-template-name="index">
<p>Index</p>
</script>
JavaScript:
<script type="text/javascript" defer>
var App = Ember.Application.create({
LOG_TRANSITIONS: true
});
App.ApplicationView = Ember.View.extend({
templateName: 'application'
});
App.Router.map(function () {
this.route("about");
this.resource("invoices", { path: "/invoices" }, function () {
this.resource("show", { path: "/:id" });
});
});
var invoices = [
{id: 1},
{id: 2}
];
App.AboutRoute = Ember.Route.extend({
setupController: function (controller) {
// Set the IndexController's `title`
controller.set('title', "My App");
}
});
App.InvoicesIndexController = Ember.ArrayController.extend({
invoices: invoices
});
</script>
You need to include an {{outlet}} tag in your invoices template. Since index and show are nested resources of invoices, their templates get rendered inside the outlet that you specify in the invoices template.
Take a look at the nested resources part of the Ember.js guide.
I tried this very basic ember router example following the ember-router-example. But when I run it, it shows me an empty page. I checked the console window for any errors, but seems to be fine. Not really sure why this is not working and where am missing.
I am just trying to create the first level links of Home, Sections, items only.
Can somebody help me?
index.html:
<body>
<script src="js/libs/jquery-1.7.1.js"></script>
<script src="js/libs/jquery.lorem.js"></script>
<script src="js/libs/bootstrap.min.js"></script>
<script src="js/libs/handlebars-1.0.0.beta.6.js"></script>
<script src="js/libs/ember.js"></script>
<script src="js/app.js"></script>
<script type="text/x-handlebars" data-template-name="application">
<div>
<ul>
<li><a {{action "doHome"}}>Home</a></li>
<li><a {{action "doSections"}}>Sections</a></li>
<li><a {{action "doItems"}}>Items</a></li>
</ul>
</div>
<div>
{{outlets}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="home">
<h1>yeah right Home</h1>
</script>
<script type="text/x-handlebars" data-template-name="sections">
<h1>Oh v in Sections index</h1>
</script>
<script type="text/x-handlebars" data-template-name="items">
<h1>correct in Items Index Page</h1>
</script>
</body>
app.js :
$(function() {
App = Ember.Application.create()
App.ApplicationController = Ember.Controller.extend();
App.ApplicationView = Ember.View.extend({
templateName:'application'
});
App.HomeController = Ember.Controller.extend();
App.HomeView = Ember.View.extend({
templateName:'home'
});
App.SectionsController = Ember.Controller.extend();
App.SectionsView = Ember.View.extend({
templateName:'sections'
});
App.ItemsController = Ember.Controller.extend();
App.ItemsView = Ember.View.extend({
templateName:'items'
});
App.Route = Ember.Route.extend({
root: Ember.Route.extend({
doHome : function(router,event){
router.transitionTo('home');
},
doSections:function(router,event){
router.transitionTo('sections');
},
doitems:function(router,event){
router.transitionTo('items');
},
home : Ember.Route.extend({
route : '/',
connectOutlets:function(router,event){
router.get('applicationController').connectOutlet('home');
}
}),
sections : Ember.Route.extend({
route : '/sections',
connectOutlets:function(router,event){
router.get('applicationController').connectOutlet('sections');
}
}),
items : Ember.Route.extend({
route : '/items',
connectOutlets:function(router,event){
router.get('applicationController').connectOutlet('items');
}
})
})//root
}) //router
});
I created this fiddle with your code. It seems to be working, just use latest ember and handlebars. And maybe you should change {{outlets}} with {{outlet}}.
EDIT
The above fiddle is not working, see the updated fiddle.
I rewrote the routing code using the new routing API, now it is working as expected.
I believe you are supposed to be using "template" as opposed to templateName when you are defining your templates in your main html file. If you were to create those templates as separate handlebars files and use a build step, you would then use templateName to refer to them (by file name).
Steve
i have 3 tabs navigation and the content of each tab is different obviously.
i'm thinking about using StateManager in Emberjs to manager my tab views.
http://docs.emberjs.com/#doc=Ember.StateManager&src=false
is that a good idea? or is there a better router out there? i've looked at
sproutcore-routing
ember-routemanager
are those better than the statemanager? what's the reason not to use statemanager?
You can use something along this lines, see http://jsfiddle.net/pangratz666/e3wM7/:
Handlebars:
<script type="text/x-handlebars" >
<ul>
<li {{action "showFirst" target="App.stateManager"}} >First tab</li>
<li {{action "showSecond" target="App.stateManager"}} >Second tab</li>
</ul>
<div class="tab-content" ></div>
</script>
<script type="text/x-handlebars" data-template-name="first" >
first
</script>
<script type="text/x-handlebars" data-template-name="second" >
second
</script>
JavaScript:
App.stateManager = Ember.StateManager.create({
rootElement: '.tab-content',
initialState: 'firstTab',
showFirst: function(manager) {
manager.goToState('firstTab');
},
showSecond: function(manager) {
manager.goToState('secondTab');
},
firstTab: Ember.ViewState.create({
view: Ember.View.extend({ templateName: 'first' })
}),
secondTab: Ember.ViewState.create({
view: Ember.View.extend({ templateName: 'second' })
})
});
Also take a look at the blog post Anatomy of an Ember.js App Part I Redux: Routing and Outlets.