data-template-name issue in emberjs - ember.js

There is a strange issue am facing with ember.js, i.e when I add "data-template-name" attribute to the script tag, nothing is working. If data-template-name name is removed, things are working fine.
This is NOT WORKING
<script data-template-name="my-template" type="text/x-handlebars">
Input:
{{#view App.MyView}}
{{view Ember.TextField
valueBinding="view.theValue"
placeholder="input ..." }}
{{/view}}
</script>
Now if **data-template-name="my-template"** is removed it works fine.
I mean, In UI TextField is visible.
<script type="text/x-handlebars">
Input:
{{#view App.MyView}}
{{view Ember.TextField
valueBinding="view.theValue"
placeholder="input ..." }}
{{/view}}
</script>
App.MyView = Ember.View.extend({
templateName: 'my-template',
theValue: null,
init: function(){
this._super();
this.set('theValue','asdf');
},
keyDown: function(e){
if(e.keyCode === 13){
alert(this.get('theValue'));
}
}
});

Ok, don't worry about the jsfiddle, it's a good start :). There is a link on the ember.js site, where you can find a starting point, including Ember.js related sources: http://emberjs.com/community/
That beeing said, when creating an Ember.js application like this, there is an implicit default anonymous template, in wich you can then define yours.
<!-- default template, introducing the view App.MyView -->
<script type="text/x-handlebars">
{{view App.MyView}}
</script>
<!-- template of App.View -->
<script data-template-name="my-template" type="text/x-handlebars">
Input:
{{view Ember.TextField
valueBinding="view.theValue"
placeholder="input ..."}}
</script>​
javacript:
App.MyView = Ember.View.extend({
templateName: 'my-template',
theValue: null,
init: function(){
this._super();
this.set('theValue','asdf');
}
});​
Here is a working example of your sample:
http://jsfiddle.net/6p6XJ/171/

Related

How to render template other than application.hbs in EmberJS?

In EmberJS, the main template file is the application.hbs. Any template rendered from the routes goes the the {{outlet}} of this main template file.
Now, I have another main template file, say print.hbs wherein the template design is very different from the application.hbs. How do I do this?
In the router file, I have:
App.Router.map(function() {
this.resource('print', function() {
this.route('display1');
this.route('display2');
});
this.route('dashboard', {path: '/'});
this.route('anything');
});
The routes dashboard and anything uses the application.hbs.
What should I do to use print.hbs on the print route? Please help.
You can't easily change application template. Ember doesn't listen on templateName property changes and responds poorly when you try to re-render the template yourself.
A nice way to do this would be to use different partials within your application template, based on whether you are in the 'screen' or 'print' mode.
<script type="text/x-handlebars">
{{#if isPrint}}
{{partial "application-print"}}
{{else}}
{{partial "application-normal"}}
{{/if}}
</script>
<script type="text/x-handlebars" data-template-name="application-normal">
<div id="app-normal">
<h2>Normal template</h2>
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="application-print">
<div id="app-print">
<h2>Print template</h2>
{{outlet}}
</div>
</script>
App.ApplicationController = Ember.Controller.extend({
isPrint: false,
currentPathChange: function () {
var currentPath = this.get("currentPath");
var isPrint = currentPath ? currentPath.indexOf("print") === 0 : false;
this.set("isPrint", isPrint);
}.observes('currentPath').on("init")
});
This JSBin will demonstrate why this, unfortunately, doesn't work either. According to this bug report, Ember's handlebars gets confused when there are multiple outlet directives in the same page, even if they are in different #if scopes.
Until this gets fixed, I propose the following, slightly modified, solution.
Application template is empty. One template each for normal and print section.
<script type="text/x-handlebars">
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="normal">
<div id="app-normal">
<h2>Normal template</h2>
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="print">
<div id="app-print">
<h2>Print template</h2>
{{outlet}}
</div>
</script>
In router, everything goes into normal and print resources. Normal resources are placed at /, so that all the links remain the same. No need for special coding in ApplicationController.
App.Router.map(function() {
this.resource("print", function () {
this.route("a");
this.route("b");
});
this.resource("normal", {path: "/"}, function () {
this.route("a");
this.route("b");
});
});
Working jsbin here.

Is "basic" a reserved route name in Ember?

I have a route in an Ember app called "basic" corresponding to the name of an API endpoint.
This route doesn't work - links to it don't render its template.
Here's a JSBin demonstrating the failure: http://emberjs.jsbin.com/hisoxadi/1
JS:
App = Ember.Application.create();
App.Router.map(function() {
this.route('basic');
this.route('test');
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return ['red', 'yellow', 'blue'];
}
});
Templates:
<script type="text/x-handlebars">
<h2> Welcome to Ember.js</h2>
{{#link-to 'index'}}Index{{/link-to}}
{{#link-to 'basic'}}Basic Route{{/link-to}}
{{#link-to 'test'}}Test Route{{/link-to}}
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="basic">
basic route is here
</script>
<script type="text/x-handlebars" data-template-name="test">
test route is here
</script>
<script type="text/x-handlebars" data-template-name="index">
<ul>
{{#each item in model}}
<li>{{item}}</li>
{{/each}}
</ul>
</script>
To expand on your comment a bit, basic is indeed a reserved word. Specifically, it's a reserved word for the resolver. You can see the source here.
useRouterNaming: function(parsedName) {
parsedName.name = parsedName.name.replace(/\./g, '_');
if (parsedName.name === 'basic') {
parsedName.name = '';
}
},
And because of the way that Ember.js sometimes looks up routes and controllers in the container, it's a fair bet to say that there's no way around this without major code changes. There should probably be a documentation issue filed for this.
EDIT: I created an issue for this here.

where to define a bound attribute in ember

I am trying to have an input text field be disabled by default and then be updatable to being able to be edited.
I have
{{input value=name disabled=entryNotAllowed }} <br /> <button {{action "canEdit"}}>Contract</button>
but where do I define entryNotAllowed where I set it to true. I tried on the model, the route, and the controller but none of them seemed to work.
I thought the controller most likely so I added this:
Hex.MenuController = Ember.Controller.extend({
entryNotAllowed: true
});
or in Route
Hex.MenuRoute = Ember.Route.extend({
entryNotAllowed: true,
actions: {
canEdit: function() {
but no dice. Any ideas on how to get this to work?
The context of your template defaults to the controller, so you can define/modify entryNotAllowed from there.
App
App = Ember.Application.create();
App.IndexController = Ember.Controller.extend({
entryNotAllowed: true,
actions: {
canEdit: function() {
this.set('entryNotAllowed', !this.get('entryNotAllowed'));
}
}
});
Template
<script type="text/x-handlebars">
<h2>Welcome to Ember.js</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
{{input value=name disabled=entryNotAllowed }}<br />
<button {{action "canEdit"}}>Contract</button>
</script>
JSBin Example

very Basic ember router example unsolved

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

Break up my application.handlebars into separate templates using Ember.js and Ember.Router

I'm building a front-end (on top of Ruby on Rails) using ember.js and the ember-rails gem.
My (ember) application consists of Models, Views, Controllers and an application.handlebars template which describes my UI.
Whats the best practice to break up this application.handlebars file so that I can manage the UI? For example, I'd like to have Navigation at the top of the page.
I've tried using the Ember.Router, a separate navigation.handlebars (with NavigationView and NavigationController) the {{outlet}} helper to no avail. Here's what the Router looks like:
App.Router = Ember.Router.extend(
enableLogging: true
root: Ember.Route.extend(
index:
route: '/'
connectOutlets: (router, context) =>
router.get('applicationController').connectOutlet('navigation')
)
and the application.handlebars
<h1>Lots of HTML that I want to break up</h1>
{{outlet}}
Let me know if you need more info...thanks.
As per my Understanding, Let's suppose you want 3 sections(can be any number) Header, Content & Footer, You can do something as follows
<script type="text/x-handlebars" data-template-name="application">
{{view MyApp.HeaderView}}
{{#view MyApp.ContentView}}
{{outlet}}
{{/view}}
{{view MyApp.FooterView}}
</script>
<script type="text/x-handlebars" data-template-name="app-header">
All your Header related HTML
</script>
<script type="text/x-handlebars" data-template-name="app-content">
HTML related to content
{{yield}} //this will be explained at the end
More HTML if you want
</script>
<script type="text/x-handlebars" data-template-name="app-footer">
HTML related to footer
</script>
MyApp.HeaderView = Ember.View.extend({
templateName: 'app-header'
})
MyApp.ContentView = Ember.View.extend({
templateName: 'app-content'
})
MyApp.FooterView = Ember.View.extend({
templateName: 'app-footer'
})
MyApp.ApplicationView = Ember.View.extend({
templateName: 'application'
})
explaining {{yield}} In a nutshell, whatever is between in the block helper of a given view goes in there, In the above example for the MyApp.ContentView, the {{outlet}} defined in the {{#view MyApp.ContentView}} handlebars gets inserted at the {{yield}}
On the similar lines let me show the difference between layoutName property & templateName property,
App.someView = Ember.View.extend({
tagName: 'a',
templateName: 'a-template',
layoutName: 'a-container'
})
<script type="text/x-handlebars" data-template-name="a-template">
Hi There
</script>
<script type="text/x-handlebars" data-template-name="a-container">
<span class="container">
{{yield}}
</span>
</script>
Will result in following HTML
<a class="ember-view" id="ember235">
<span class="container ember-view" id="ember234">
Hi There
</span>
</a>
Use these concepts to split the application handlebars in your case it would be something like
{{view App.NavigationView}}
{{outlet}}
Update as per latest ember
The new ember supports partials similar to rails, now we can modify the above to use {{partial}} as follows:
{{partial "header"}}
{{outlet}}
{{partial "footer"}}
Ember when encountered this template will look for the template whose name is _header(similar to rails) and inserts the template(same goes for footer)
And If want to associate a controller we can use {{render}} helper
{{render "sidebar"}}
inserts the template whose name is sidebar at specified location in handlebars besides it also associates App.SidebarController to it,
Note: we cannot use {{render 'sidebar'}} more than once in same handlebars file.
But again if you want to use a widget like view multiple places in a given page then use {{view}} helper
For this problem, what you need to do is think about what views change and where that changes happen. If for example you have a navigation section and a main section, then think about how each of these sections change with the state of your application. Be sure to only create an {{outlet}} for dynamic content, otherwise things will get messy and the application will be slower. Then setup your templates and your router similar to the example below.
Templates:
<script type="text/x-handlebars" data-template-name="application">
<!--Your application template goes here-->
{{outlet navigation}}
{{outlet body}}
</script>
<script type="text/x-handlebars" data-template-name="navigation">
<!--Your navigation template goes here-->
</script>
<script type="text/x-handlebars" data-template-name="main-one">
<!--Your mainOne template goes here-->
</script>
<script type="text/x-handlebars" data-template-name="main-two">
<!--Your mainTwo template goes here-->
</script>
Note: You can have {{outlet}} in any of your view templates to change in more sub-states
Javascript:
window.App = Em.Application.create({
ApplicationView: Em.View.extend({
templateName: "application"
}),
ApplicationController: Em.Controller.extend({
}),
NavView: Em.View.extend({
templateName: "navigation"
}),
NavController: Em.Controller.extend({
}),
MainOneView: Em.View.extend({
templateName: "main-one"
}),
MainOneController: Em.Controller.extend({
}),
MainTwoView: Em.View.extend({
templateName: "main-two"
}),
MainTwoController: Em.Controller.extend({
})
Router: Em.Router.extend({
root: Em.Route.extend({
index: Em.Route.extend({
route: '/',
connectOutlets: function(router,context) {
router.get("applicationController").connectOutlet("navigation","nav");
router.get("applicationController").connectOutlet("body","mainOne");
}
}),
otherState: Em.Route.extend({
route: '/other-state',
connectOutlets: function(router,context) {
router.get("applicationController").connectOutlet("navigation","nav");
router.get("applicationController").connectOutlet("body","mainTwo");
}
}),
})
})
});
App.initialize();
Note: The applicationController must extend Controller and not ObjectController or ArrayController