Remove the rendered application template - ember.js

I have quite many templates that I render into the application template. The application template, however, has only the {{outlet}} and nothing else.
The home template, must render directly into the application template. But all other templates must be rendered along with the navbar and sidebar.
Currently, I am using partial to render the common data in all the other templates (except 'home')
How can I solve this scenario? All I need is that home should render directly in the body, while all the other templates must render along with the navbar and sidebar.
I might be missing something very obvious here. What should I do to render home in one template and the rest in another?
UPDATE 1
Application Template
{{#unless renderNav}}
{{outlet home}}
{{else}}
{{partial 'navbar'}}
<div class="container">
<div class="row row-offcanvas row-offcanvas-right">
<div class="col-xs-12 col-sm-9">
{{outlet}}
</div>
<div class="col-xs-6 col-sm-3 sidebar-offcanvas" id="sidebar" role="navigation">
<div class="list-group">
Link
Link
</div>
</div><!--/span-->
</div><!--/row-->
</div><!--/.container-->
{{/unless}}
UPDATE 2
The above code causes rendering problems. Navigating to the home template causes no issue. But in all other templates, the first page rendered stays on the top while the next pages are rendered below it.
For example, if after 'home', I transition to 'first', 'first' renders two elements A and B.
If I next transition to 'second', which renders C, what I get is A and B and C, instead of C.
UPDATE 3
Solved the error in the previous UPDATE by observing the currentPath property in the application controller. But now in the 'home' route, the 'home' template is not displayed. Instead the navbar is rendered with an empty outlet.
I renamed my outlets and forced HomeRoute to render into outlet 'home'. But still there is no change. All other templates are rendered seamlessly, but 'home' is not rendered at all.
I confirmed that the boolean was false in the HomeRoute, but still the navbar template is being rendered.

You can create a template where navbar and sidebar can be rendered in and all templates except home are nested routes of this new template.
This of course can give you trouble with url, so another way to go is to use a boolean computed property in the application controller based on currentPath that renders or not your partials
e.g.
App.ApplicationController = Ember.Controller.extend({
showPartials: (function() {
this.get('currentPath') != 'home'
}).property('currentPath')
});
Then in your application template do something like
{{#if showPartials}}
{{partial "navbar"}}
{{partial "sidebar"}}
{{/if}}

Related

Ember Binding Component Template to Models

Hi I have the following Component Template:
test-component.hbs: (produces img tag per model)
{{#each titleModels}}
<div class="item">
<img {{action "owlItemClicked" id index on="click" }} {{bind-attr src=img}}></img>
</div>
{{/each}}
Its used in parent template
parent.hbs:
{{test-component action="titleClicked" parentController=controller titleModels=model}}
On titleClicked action it is suppose to remove the clickedModel and refresh the template to show the removed view.
parent-controller.js:
modelChanged: false,
actions: {
titleClicked: function(){
self.get('model').removeObject(aSelectedModel);
self.set('modelChanged',true);
}
}
The test-component observes changes to titlesModel and rerenders the template:
test-component.js:
titleModelsChanged: function(){
this.rerender();
}.observes('parentController.modelChanged'),
this.rerender methos is called successfully and the specific html tag (e.g the one defined below) for the removed model is no longer present in the DOM for html page generated from test-component.hbs as expected.
<img {{action "owlItemClicked" id index on="click" }} {{bind-attr src=img}}></img>
The img tags for the remaining models are present when inspecting the dom. However they are not displayed out the actual html page ( i dont see the actual imgs), even though the are present in the DOM when I inspect the elements.
How do I display the img tags of the remaining models after rerender on the html page ?
First, two small notes. The <img> tag must not have a closing tag. So no <img></img> but simply <img> (or <img /> alternatively).
The context-changing {{each}} as you use it is deprecated in current and future versions of Ember.js. So you should rewrite your component as
{{#each titleModels as |titleModel|}}
<div class="item">
<img {{action "owlItemClicked" titleModel.id titleModel.index on="click" }} {{bind-attr src=titleModel.img}}>
</div>
{{/each}}
Now to your question. Given that the <img> tags are in the DOM but the actual image is not visible, the problem must be in the src attribute of the images. If you open the URL in the src in a separate tab, do you see the image you're supposed to see?
The JSBin http://emberjs.jsbin.com/mitadovero/edit?html,js,output solves the problem.

Display dynamic content in Ember application template

I am creating an Ember app that manages a list projects and tasks for each project. In the app's navigation, I want to display the name of the selected project. If someone navigates to /projects/1/tasks, I want the page to display project 1's title, along with links to pages specific to that project. Here is what I have started for my application.hbs file of how I expected it to work, however the project title is blank and the links don't work:
<nav id="nav-menu">
<ul>
<li class='menu-project-title'>
{{#link-to 'projects'}}{{project.title}}{{/link-to}}
</li>
<li class='menu-separator'> </li>
<li>{{#link-to 'projects.tasks' project}}Tasks{{/link-to}}</li>
<li>{{#link-to 'projects.people' project}}People{{/link-to}}</li>
</ul>
</nav>
<div class="container" id='main-outlet'>
{{outlet}}
</div>
If I know every route will always have a project returned, what is the best way to pass that data into the application template?
You could use an Ember.computed.readOnly property in your application controller.
App.ApplicationController = Ember.Controller.extend({
needs: ['project'],
activeProject: Ember.computed.readOnly('controllers.project.model')
...
});
But maybe this isn't the best solution. As far as I understand it, the project route/template is always used? So why not move everything to that template.

Ember.js - default template to render into an outlet?

So I have a page which looks like the following
[ Nav Bar ]
| |
| Content |
| |
The nav bar I want to be constant across all pages. So the approach I used was to set my page up as follows:
[ Nav Bar ]
{{outlet}}
This is great, I can now render different pages into my outlet for different routes.
But what if I want a default template to be rendered into the outlet for my home page?
I've managed to achieve this by redirecting / to /home, but there must be a better way to do this which allows me to render a default home page at / without re-routing?
Any advice appreciated,
Thanks,
Daniel
To render stuff in the {{outlet}} at the root page /, you have to define a handlerbar script for index:
Your navbar code probably look like this:
<script type="text/x-handlebars">
<div class="navbar ...">
...
</div>
{{outlet}}
</script>
The root page that will be place inside {{outlet}} is the fallowing:
<script type="text/x-handlebars" id="index">
<div class="container">
<h1>Root page!!</h1>
</div>
</script>
In other words, you have to create a handlebar script that will have an id="index".
Should work. It doesn't need any js code to work.
I must admit this property is not well documented and buried in the docs for Ember.View but you could try setting the defaultTemplate property on your ApplicationView. See here for more info on that (search in the page for 'defaultTemplate').
Hope it helps.
The following statement in docs helped me to solve exactly the same problem I was having which is stated in the question:
Ember routing docs
The index template will be rendered into the {{outlet}} in the application template. If the user navigates to /favorites, Ember will replace the index template with the favorites template.
As I am using pod structure in my project, I created an index route having my default template and I placed nav-bar component in my application/template.hbs file.
app/application/template.hbs:
<div id="pageWrapper">
<div id="navbarfixed">{{nav-bar options=options}}</div>
<div id="pageContent">
{{outlet}}
</div>
</div>
app/index/template.hbs
<div id="homeWrapper"> <!--This gets rendered by default in outlet above-->
Some default content of outlet
</div>

Change Navbar based on login state

I’ve been trying, using Rails/Ember pre-4, to do a fairly typical thing, that is have a page with a navbar and a content section. The navbar only changes on login (shows logout button when logged in and login and register buttons when logged out), not on every page change.
At first thought i could do something in the application.hbs template such as:
{{view navbar}}
{{outlet}}
where i set up navbar to respond to login state changes (managed by a state manager). This didn’t seem to work.
Then i tried something like (also in application.hbs):
{{outlet navbar}}
{{outlet}}
and tried setting navbar in each route, which results in lots of duplication and also didn’t ultimately work.
Before posting code, wanted to know if anyone already has a good solution to this common situation where certain parts of your page such as a navbar or sidebar only change upon some change in app state, not on every page change.
There are lots of ways to get this done. The first approach you described is closest to what we are doing. In past ember versions we used view helper for this, today we use {{render}} but it's the same basic concept. For example, application.hbs might look like this:
{{render navbar}} {{outlet}}
Now navbar.hbs can use a simple {{#if}} helper to swap links based on login state.
<div class="navbar">
<div class="navbar-inner">
{{#linkTo index class="brand"}}My App{{/linkTo}}
<ul class="nav">
<li>{{#linkTo index}}Home{{/linkTo}}</li>
<li>{{#linkTo about}}About{{/linkTo}}</a></li>
</ul>
<ul class="nav pull-right">
{{#if isAuthenticated}}
<li><a {{action logout}} href="#">Logout</a></li>
{{else}}
<li><a {{action login}} href="#">Login</a></li>
{{/if}}
</ul>
</div>
</div>
Now we add logic to NavbarController that tracks and manages login state.
App.NavbarController = Ember.ArrayController.extend({
isAuthenticated: false,
login: function() {
this.set('isAuthenticated', true);
},
logout: function() {
this.set('isAuthenticated', false);
}
});
In a real app NavbarController would proxy these requests to another controller, perhaps currentUserController. I've created a working sample here: http://jsbin.com/iyijaf/6/edit

Ember.js and handlebars each helper, with subviews

I'm triyng to use the view helper inside my {{#each}} template blocks without using global paths (my controllers create and destroy their own views).
Examples. Given a view with a myList array property, and an itemButton child view:
This will work
<script type="text/x-handlebars" name="my-list-view">
{{#each myList}} <!-- App.myListView.myList -->
{{view App.myListView.itemButton}} {{title}}
{{/each}}
</script>
This will not:
<script type="text/x-handlebars" name="my-list-view">
{{itemButton}} <!-- works fine outside the each -->
{{#each myList}}
{{view itemButton}} {{title}} <!-- itemButton view not found -->
{{/each}}
</script>
I do not appear to be able to access the parent view from the each view helper (or in fact access anything other than the properties of the objects being iterated).
The hacky workarounds I've come up with are:
Add the view I want to use to the items I'm iterating over.
or
Creating a collectionView in App.myListView
Create an itemViewClass view in that collection view class
Move the itemButton view inside the itemViewClass
Replace {{#each}} with {{#collection}}
or
Create a custom handlebars helper for iteration.
Both of these options seem horrible.
Surely there's a better alternative than creating 2 new classes (and nesting 4 views deep) just to iterate over a list, though. Is there a replacement handlebars helper I can use instead?
Workaround implementations
Option #1 : Modifing the content array
http://jsfiddle.net/FQEZq/3/
Disadvantages: Having to add the view to each model instance just for iteration.
Option #2 : Custom collection view
http://jsfiddle.net/ST24Y/1/
Disadvantages: Now you have two additional views that you do not need / want, and less control of markup. References from the child view to the parent instance now requires parentView.parentView.parentView.
#each is too limited for your requirements. You can make it work if you're willing to use a global path to the view you want to nest within the #each. Otherwise, your collection view approach is best. Adding the view to the model instance is likely to muddy your app design something fierce, so I would avoid that.
One idea to keep your templates clean is to take advantage of Ember.View properties like:
collectionView - Return the nearest ancestor that is an Ember.CollectionView
itemView - Return the nearest ancestor that is a direct child of an Ember.CollectionView
contentView - Return the nearest ancestor that has the property content.
The big thing here - options.
Hooks for how you wish to use a template are available. These are:
<-- render templates/name.js -->
{{partial 'name'}}
<-- render views/name.js -->
{{view 'name'}}
<-- render views/name1.js with controllers/name2.js -->
{{render 'name1' 'name2'}}
<!-- see also: -->
{{output}}
{{output 'named'}}
{{yield}}
An example variant of your initial template showing 4 different options:
<script type='text/x-handlebars' data-template-name='my-list-view'>
<h2>Option 1</h2>
{{#each myList}}
{{! the 2nd parameter will look for itemButtonController }}
{{render 'itembutton' itemButton}}
{{/each}}
<h2>Option 2</h2>
{{#each myList}}
{{! using an Ember Component }}
{{#item-button }}
some static text OR {{dynamic}}
{{/item-button}}
<!-- in component/item-button.hbs add {{yield}} for where you want the static content to output -->
{{/each}}
<h2>Option 3</h2>
{{#each myList}}
{{! if the button is to be a link }}
{{#link-to 'route' parameter tagName='button' classNames='btn'}}
{{title}}
{{/link-to}}
{{/each}}
<h2>Option 4</h2>
<p>Ludicrous example showing almost every reference option!</p>
{{! focus the context on subview data }}
{{#with someArrayOrCollectionOfView}}
{{! prepend type to add context - here returning back up to this view's properties }}
{{#each view.myList}}
{{! this is equivalent to someArrayOrCollectionOfView[x].name }}
{{name}}
{{! a button that hooks in route, model, and 2 controllers, and applies a target for the output when clicked }}
{{#link-to 'page' controllers.page.nextPage target='outlet' tagName='button' disabledWhen=controller.disableNext }}
{{model.buttonName}}
{{/link-to}}
{{/each}}
{{/with}}
{{! generic default target (automatic) }}
{{outlet}}
{{! example of a named target }}
{{outlet 'footerlinks'}}
</script>
Mmmm... reference for further reading:
Ember.Handlebars.helpers