Ember.js - Application <div/> is rendered twice? - javascript

I'm using the following Ember.js stack:
DEBUG: -------------------------------
DEBUG: Ember : 1.1.2
DEBUG: Handlebars : 1.0.0
DEBUG: jQuery : 2.0.2
DEBUG: -------------------------------
I declared an application.hbs Handlebars template which renders my App.ApplicationView
{{#view App.ApplicationView}}
{{outlet 'modal'}} {{outlet 'notificationCollection'}}
{{#if isUserAuthenticated}}
{{render sidemenu authenticationState=isAuthenticated}}
{{outlet 'upperNotification'}}
<div id="main" class="main">
{{outlet}}
</div>
{{else}}
{{outlet}}
{{/if}}
{{/view}}
and for debugging purposes I added the gotcha to the classNames array of App.ApplicationView. When I now inspect the DOM, I can see that App.ApplicationView is rendered twice (and also boxed):
...
<div id="appRoot" class="ember-application">
<div id="ember444" class="ember-view gotcha">
<div id="ember445" class="ember-view gotcha">
...more content..
</div>
</div>
</div>
...
EDIT:
I should have tried it first, before posting it here at stackoverflow... if I remove the {{#view App.ApplicationView}}{{/view}} declaration, it get's only rendered once, as expected ;)
So, the question which remains a miracle to me is is Ember.js really generating an enclosing <div id="ember666" class="ember-view"></div> for every {{outlet}}??
Why would Ember.js handle it this way? How can I prevent it from rendering App.ApplicationView twice? And, besides that, is Ember.js really generating an enclosing <div id="ember666" class="ember-view"></div> for every {{outlet}}? (I'm seeing this behaviour within my application)

By default, yes {{outlet}} will enclose your template in a <div>. However, you can change that behavior by specifying a view class on the outlet and defining the view class' tagName property to whatever you want.
For example, the outlet
{{outlet viewClass=App.HeaderContainer}}
With view
App.HeaderContainer = Ember.ContainerView.extend({
tagName: 'header'
});
will wrap the outlet in a <header> tag.

Related

Ember Documentation understanding - Model linked to Template or not?

I'm learning Ember right now and i'm beeing a bit confused because of the Docu of Ember and the getting started example.
In the Documentation it says:
In Ember.js, templates get their properties from controllers, which decorate a model.
And
Templates are always connected to controllers, not models.
But after doing the getting started guide i'm not sure if this is correct.
I've uploaded the finished TodoMVC app here: https://github.com/Yannic92/stackOverflowExamples/tree/master/Ember/TodoMVC
In the Index.html you'll find this template:
<script type="text/x-handlebars" data-template-name="todos/index">
<ul id="todo-list">
{{#each todo in model itemController="todo"}}
<li {{bind-attr class="todo.isCompleted:completed todo.isEditing:editing" }}>
{{#if todo.isEditing}}
{{edit-todo class="edit" value=todo.title focus-out="acceptChanges" insert-newline="acceptChanges"}}
{{else}}
{{input type="checkbox" checked=todo.isCompleted class="toggle"}}
<label {{action "editTodo" on="doubleClick"}}>{{todo.title}}</label>
<button {{action "removeTodo"}} class="destroy"></button>
{{/if}}
</li>
{{/each}}
</ul>
</script>
My question refers to the 3rd Line:
{{#each todo in model itemController="todo"}}
The Controller todo is only needed to provide the actions for the todos. The data is accessable even without this controller.
In my opinion there is the model directly connected with the template isn't it?
Or is there a default Controller like the docu mentioned here?
For convenience, Ember.js provides controllers that proxy properties from their models so that you can say {{name}} in your template rather than {{model.name}}.
As you can see in this line: <script type="text/x-handlebars" data-template-name="todos/index"> this is the template for / because the router has this line: this.route('todos', { path: '/'}). Which will have a controller named TodosController, even if you didn't write one ember will generate one for you. So when you delete it that's what happens.
In this template you loop through the todo's list. Each of these Todo models are decorated with a controller the TodoController. And with this line: {{#each todo in model itemController="todo"}} you tell ember to use this TodoController for every element in the list.
If you leave out the itemController ember assumes the todo's are part of the model for the IndexController provided by the IndexRoute.
By default ember has an empty controller which proxies everything to the underlying model. (Note: I believe this will change in ember 2.0). So it may look like it's directly coupled to the model. But you could write a controller that changes everything without changing the model.

MeteorJS template placeholder

Iam getting started with MeteorJS/Iron Router/Blaze and I'm trying to figure out how to set placeholder for template.
I have a menu and a footer, which will change only partialy, but between them is the main content which should be based on current route. Point is that i need some sort of pointer, like in angular "ng-view".
Eg.
<menu></menu>
{{some sort of placeholder}}
<footer></footer>
and in router:
Router.route('/', function () {
//render some template exactly into placeholder, dont append it to the bottom
});
Maybe there is something wrong with my understanding of meteorjs templating, I just base my way of solving this problem on angular templating.
not sure I got your question but here is an answer:
You can do that with the {{> yield}} tag. It will define an dynamic area which will show the view corresponding to the current route.
You can also "design" a layout for your entire app, like you did, for example layout.html :
<template name="layout">
<div class="container">
<header class="navbar">
<div class="navbar-inner">
<a class="brand" href="{{pathFor 'home'}}">My app</a>
</div>
</header>
<div id="main" class="row-fluid">
{{> yield}}
</div>
</div>
</template>
And tell Iron-Router that your app has to fit this layout :
Router.configure({
layoutTemplate: 'layout'
});
// Then just define your routes
Router.map(function() {
this.route('home', {path: '/'});
});
You may notice I used {{pathFor 'home'}} in the layout. Iron Router let you use route "names" so it won't do anything if you change the URL.
I suggest you read an awesome book called Discover Meteor !

Making divs clickable - Ember view for action on multiple elements

I am developing a Cordova application with help from Ember. I have many dynamic elements in my application. These are Bootstrap thumbnails that link to other routes when clicked.
I want to make these thumbnails clickable. If I use Views, I will have to write unique views for all the thumbnails.
I have heard about mixins. Can a general View be defined that will :
Pass a model
Render a template for a route with the model
In other words, since each view semantically performs the same action, I want to be able to do something similar to
{{#each}}
{{#view App.AllView this}}
.
{{/view}}
{{/each}}
in the template and in the view :
App.AllView = Ember.View.extend({
click: function(evt, model){
this.controllerFor('route').set('content', model);
this.transitionTo('route');
}
});
UPDATE
Following #givanse's answer, I made the following component
<script type="text/x-handlebars" data-template-name="components/thumbnail-view">
<div {{bind-attr class=class}}>
<div class="thumbnail">
<div class="caption">
{{name}}
</div>
<img {{bind-attr src=image }}>
</div>
</div>
</script>
and used it in my template :
<script type="text/x-handlebars" data-template-name="types">
<div class="row">
{{#each model}}
{{thumbnail-view action="goToCategory" class="col-xs-12" param=this name=name image=image}}
{{/each}}
</div>
</script>
with an Ember component :
Pioneer.ThumbnailViewComponent = Ember.Component.extend({
click: function(){
this.sendAction('action', this.get('param'));
}
});
The action goToCategory is defined in my ApplicationRoute
Hope this helps someone!
What you need is Components, something like:
<script data-template-name="index">
{{#each}}
{{img-thumbnail imgId="id/path/name"}}
{{/each}}
</script>
<script data-template-name="components/img-thumbnail">
{{! whatever you need to make your thumbnail }}
</script>
App.ImgThumbnailComponent = Ember.Component.extend({
// handle events, classes, etc.
});
See:
http://emberjs.com/guides/components/
http://emberjs.com/api/classes/Ember.Component.html

Ember JS Index routes

Can someone better explain with is going on with the implied index route and controllers in Ember JS?
See this example, why is the behavior different in these two examples?
Index route explicitly defined
http://jsbin.com/ILAP/1/
The index route is implied
http://jsbin.com/ILAP/2/
What is confusing to me is why the nesting behavior works in the second example but not the first.
This is the students/student route structure:
students
----index
----student
--------index
First case
Index route explicitly defined
Templates:
<script type="text/x-handlebars" data-template-name="students">
{{ outlet }}
</script>
<script type="text/x-handlebars" data-template-name="students/index">
... omitted ...
<div class="well">
Expecting to render student template here:
<br />
{{ outlet }}
</div>
</script>
<script type="text/x-handlebars" data-template-name="student">
<h2>Student</h2>
<h3>{{name}}</h3>
<h4>{{grade}}</h4>
<h4>{{gpa}}</h4>
</script>
When you make a transition to student.index, first is appended the student template and after student/index. Because you dont have override the default conventions, via renderTemplate. The place where the template is rendered, is into the main outlet (an outlet without name) aka {{outlet}}, of the parent route template. So student template will be inserted in the students main outlet. Not students/index, because it's the sibling. This is the reason why all your content is replaced. And the student/index will be inserted in student
Second case
The index route is implied
Templates:
<script type="text/x-handlebars" data-template-name="students">
... omitted ...
<div class="well">
Expecting to render student template here:
<br />
{{ outlet }}
</div>
</script>
<script type="text/x-handlebars" data-template-name="student">
<h2>Student</h2>
<h3>{{name}}</h3>
<h4>{{grade}}</h4>
<h4>{{gpa}}</h4>
</script>
This time, like the previous sample, the resolution of the templates don't change. But this time we don't have the student/index. So first is rendered the student in students outlet, after because the student/index is missing, it's is ignored. The final result is the template where you expect.
Summary
Using the default conventions. Templates will be rendered in the parent, not sibling, parent route template.

Creating complex static Markup with ember.js

I am trying to render my application template, which is getting very complicated, so I want to split it up into separate <script type="text/x-handlebars">'s
I think I want to use the {{view}} helper, but I don't know. Let's say I have this:
<script type="text/x-handlebars" data-template-name="application">
<div id="wrapper" class="clearfix">
<hgroup>
<header>
<div class="logo"></div>
<h1 id="facilityName">{{facilityName}}</h1>
<div id="sessionInfo">
<a id="userName">{{user}}</a>
<a id="logOut" href="../logout">log out</a>
</div>
</header>
</hgroup>
{{view App.breadcrumbsView}}
</div>
</script>
And I want to load this next template inside of the one above:
<script type="text/x-handlebars" id="breadcrumbs">
<div id="breadcrumbs">
<p>
Network
{{#each breadcrumbObj}}
<span>></span><a {{bindAttr href="link"}}>{{name}}</a>
{{/each}}
</p>
</div>
</script>
Right now I am trying to do this with this code from my app.js
App.breadcrumbsView = Ember.View.create({
templateName: 'breadcrumbs',
breadcrumbObj: Util.breadcrumbs()
});
This is not working and I am getting Uncaught Error: assertion failed: Unable to find view at path 'App.breadcrumbsView'
Thanks
I think that you declared your App using var keyword. So it's not visible in handlebars template.
Change this
var App = Ember.Application.create();
To this
App = Ember.Application.create();
And you have to use extend instead of create when creating your views. Because ember will handle the object lifecycle like: create, destroy, add and remove binding etc.
#Marcio is right, you should .extend() and let the framework create it for you automatically by request. Furthermore when you extend the best practice is to use capitalized names like App.BreadcrumbsView.
See here a demo how it renders correctly doing it this way.
Hope it helps.

Categories

Resources