Use "subcontrollers" in EmberJS - ember.js

i'm having some trouble designing an EmberJS layout. I have a view divided in two parts :
a content library on the left
a playlist editor on the right
Currently, those two elements share the same controller.
I can't figure how to use two different controllers for those two sides to be able to re-use the content library in other views or even having a view with two playlist editors.
My root view looks like this so far :
<script type="text/x-handlebars" data-template-name="playlists">
<div id="library">{{template library}}</div>
<div id="playlistEditor">{{template playlisteditor}}</div>
</script>
I saw docs about the {{control}} helper, but it is unstable and i'm not sure this is what i'm looking for.
Thanks !

Okay, i found the answer, i had to use the {{render}} helper, like that :
<script type="text/x-handlebars" data-template-name="playlists">
<div id="library">{{render "library" library}}</div>
<div id="playlistEditor">{{render "playlisteditor" playlist}}</div>
</script>
Then, in my route :
App.PlaylistsRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set('playlist', playlist);
controller.set('library', library);
}
});
Then, this EmberJS will automatically wire the App.PlaylisteditorController, the App.LibraryController and the views playlisteditor and library. Awesome.

Related

How to append Ember.View Properly

I have recently decided to do a major upgrade with my javascript libraries and have ran into a perplexing issue with appending Ember.Views. I have been researching this issue for several hours now and have tried many things but nothing has worked.
What I want to do is quite simple: Extend Ember.View, manually create a new instance of this extended view and then append it to a div. In a much earlier version (ember.js 1.5) this was extremely straightforward. Now (ember.js 1.9) attempting the same thing results in an error.
Container was not found when looking up a views template. This is most
likely due to manually instantiating an Ember.View. See:
http://git.io/EKPpnA
Here is a very simple example that demonstrates this: http://jsfiddle.net/81dhm3ta/
html
<body>
<script data-template-name="main" type="text/x-handlebars">
Main
</script>
<div id="main" style="text-align: center;"></div>
</body>
javascript
$(document).ready(function () {
App = Ember.Application.create();
App.MainView = Ember.View.extend({
templateName: 'main',
});
App.view = App.MainView.create();
App.view.appendTo("#main");
});
Can someone show me the simplest way to do this properly?
App.view is neither a D0M element or jQuery object that you can simply append to a div. It is an Ember object of type View.
In the link given by the error, you are clearly told that you can't create views like you did in your snippet. Dynamic views must be instantiated within a parent view or directly through the container (not recommended).
Your life will be much easier if you add views within a template by just using the view helper:
<script type="text/x-handlebars" data-template-name="index">
{{view 'main'}}
</script>

can you run an ember.js app inside an ember.js app

We have a theoretical need to run an ember widget inside of another ember widget. Is this possible to do? Would scoping the nested ember widget to a different dom element than its parent work?
The idea is that we might need to embed our ember widgets on customer websites that also run ember.
Thanks!
I'm not sure to understand you correctly but If your need is to have separate components that you can distribute and reuse across application, you sure can have them. Although I'm not sure I got you right as you seem to speak of 2 different problems (nesting widgets and distributing ember widgets as third parties for other ember applications...)
Here is a fiddle on how to make an external component and reuse it if you want more details. Let me know if this helps.
The component :
var GravatarImageComponent = Ember.Component.extend({
size: 200,
email: '',
gravatarUrl: function () {
var email = this.get('email'),
size = this.get('size');
return 'http://www.gravatar.com/avatar/' + CryptoJS.MD5(email) + '?s=' + size;
}.property('email', 'size')
});
Ember.Application.initializer({
name: "gravatar-image-component",
initialize: function(container, application) {
container.register('component:gravatar-image', GravatarImageComponent);
}
});
The HTML to bring it to life :
<script type="text/x-handlebars">
<ul class="example-gravatar">
<li>{{gravatar-image email="tomster#emberjs.com" size="200"}}</li>
<li>{{gravatar-image size="200"}}</li>
</ul>
</script>
<script type="text/x-handlebars" id="components/gravatar-image">
<img {{bind-attr src=gravatarUrl}}>
<div class="email-input">
{{input type="email" value=email placeholder="tomster#emberjs.com for instance"}}
</div>
</script>

Nested routes and outlets within outlets

This could be a rather trivial question, but as an Ember beginner, I am struggling with it a bit.
The site I'm building has a parent navigation, but some of the templates inside its outlet may have their own navigation and their own outlet (at least that's what I'm intending). In other words, I might have something like (skipping a lot of HTML):
<script type="text/x-handlebars" data-template-name="application">
<nav>
<ul class="nav">
<li>{{#link-to 'index'}}Home{{/link-to}}</li>
<li>{{#link-to 'testing'}}Testing{{/link-to}}</li>
</ul>
</nav>
<div>{{outlet}}{/div>
</script>
<script type="text/x-handlebars" data-template-name="testing">
<ul class="nav">
<li>{{#link-to 'testing.encoding'}}Encoding{{/link-to}}</li>
<li>{{#link-to 'testing.user'}}User Admin{{/link-to}}</li>
</ul>
<div>{{outlet}}{/div>
</script>
<script type="text/x-handlebars" data-template-name="testing/encoding">
<h3>Encoding</h3>
</script>
<script type="text/x-handlebars" data-template-name="testing/user">
<h3>User Admin</h3>
</script>
The application template wires great. Click on "Home", you get the index template; click on "Testing", you get the testing template. Super. What I want is for when they click "Encoding", the route is then /testing/encoding and the testing/encoding template is rendered in the outlet inside of testing. My Router looks like this:
App.Router.map(function() {
this.route('testing', function() {
this.route('encoding');
this.route('users');
});
});
However, the page won't load at all, giving me: Uncaught Error: There is no route named encoding.index. I suspect I named my templates poorly, or configured my Router incorrectly, or perhaps need to name the outlet in the testing template... and I've attacked those potential issues, but have yet to come up with a resolution.
Ideas? This is probably a typical pattern and likely has a clean, easy solution with minimal javascript. I'm just not seeing it, I suppose.
You want your router to look like this.
App.Router.map(function() {
this.resource('testing', function() {
this.route('encoding');
this.route('users');
});
});
You can't nest a route under a route. What you get with the resource is the leaf routes of index, loading and error.
There is not route encoding.index in this router.
The routing guide here is really helpful.
Cheers
For one you didn't name your route correctly (it should be this.route('encoding'); instead of this.route('encode');. But the bigger issue is that Ember doesn't allow for nested routes, only nested resources (and routes nested in resources).
The Ember docs say: "You cannot nest routes, but you can nest resources."

EmberJS - adding some template in separated file

I'm a newbie yet on EmberJS, started to learn a week ago. Well, I have some .html file named contactsTemplate.html that is a template what I want to use. Something like this below:
<script type="text/x-handlebars" data-template-name="contacts">
<h2>My Contact List</h2>
{{#each contact in contactList}}
{{contact.name}}
{{/each}}
</script>
Great. I have a index.html file that contains an {{outlet}} expression. It means that every new content will be loaded into this space, right?
<script type="text/x-handlebars" data-template-name="application">
<h1>My Application</h1>
{{outlet}}
</script>
Ok... To manage this template named application, I've created a Controller object.
App.ApplicationController = Ember.ObjectController.extend({
...
});
Same to contacts template:
App.ContactsController = Ember.Controller.extend({
contactList: []
});
I've created two routes to manage this transition between pages:
App.Router.map(function() {
this.route("index", "/");
this.route("contacts", "/contacts");
});
My doubt is:
How can I associate this separated files to a route? I mean, when I call on browser http://mysite.com/ the index.html file should be loaded. When I call http://mysite.com/#/contacts the contactsTemplate.html should be loaded.
Sorry for the long text, and thanks for any help!
By default each declared this.route(routeName) in Router map, will have a [routeName]Controller, [routeName]Route, and expect a [routeName] template, following these conventions described in http://emberjs.com/guides/concepts/naming-conventions/.
To change from one route to other, you can use:
Inside of a controller this.transitionToRoute(routeName)
Inside of a route this.transitionTo(routeName)
Inside of a template {{#link-to "routeName" }}My route{{/link-to}}
You can find more information in the routing guide http://emberjs.com/guides/routing
I hope it helps

How to nest views in the new Ember.js router API?

I have a setup screen, it consists of a sidebar and a body. The body can have a form to update the user's profile or password.
The routing looks like this:
App.Router.map(function(match) {
(match("/")).to("index");
(match("/user")).to("user", function(match) {
(match("/")).to("userIdx");
(match("/settings")).to("userSetup", function(match) {
(match("/")).to("userSetupIdx");
(match("/profile")).to("userSetupProfile");
(match("/password")).to("userSetupPassword");
});
});
});
and the wrapping setup template like this:
<script type="text/x-handlebars" data-template-name="userSetup">
<div class='sidebar'>
Sidebar
</div>
<div class='main'>
Setup <br/>
{{outlet}}
</div>
</script>
A complete example can be found here:
http://jsfiddle.net/stephanos/mgp7F/6/
What's the right approach to do this in Ember.js?
EDIT
With the help of sly7_7 I managed to make the fiddle above work: http://jsfiddle.net/ygvsS/9/. All I did was rename everything from userSetup (template, view, route) to setup. BUT obviously this is not a solution (since I have appSetup, too).
I think I have done what you are looking for, based on your comment example: http://jsfiddle.net/rt8fv/
router code:
App.Router.map(function(match){
match('/').to('home');
match('/about').to('about');
match('/contributors').to('contributors', function(match){
match('/').to('contributorsIndex');
match('/:contributor_id').to('contributor', function(match){
match('/').to('contributorIndex');
match('/details').to('contributorDetail');
match('/repos').to('contributorRepos');
});
});
});
Maybe related question: Best approach to fetch data in every state of app