How can I bind the element ID for an Ember View? - ember.js

My model "content.id" contains a string, e,g "123":
{{view Em.TextArea idBinding="content.id"}}
Instead of just setting the id of this view to "123", I'd like it to be "message-123", basically customizing the string being used. Sadly, Ember does not allow bindings to be functions, which would solve my problem (I could define such a function on the controller).
What's the best way to achieve this?

You could define a computed property in the controller (or elsewhere):
The controller
MyApp.ApplicationController = Ember.Controller.extend({
content: "a-content",
editedContent: function() {
return "message-" + this.get('content');
}.property('content')
});
The view
MyApp.FooView = Ember.View.extend({
    tagName: 'p'
});
The template (where content is a String, here)
{{#view MyApp.FooView elementIdBinding="editedContent"}}
{{content}}
{{/view}}
And the JSFiddle is here.
EDIT
How can the view see the property editedContent since it belongs on the ApplicationController controller?
The router, after started, automatically render the ApplicationView, or its template when there is no ApplicationView defined. If you want more detail, I suggest you to read the Ember guide: Understanding the Ember.js Router: A Primer.
And {{editedContent}} directly get the controller editedContent property, because the default view context is its controller, as you can read in Ember Blog - 1.0 Prerelease:
The {{#view}} helper no longer changes the context, instead maintaining the parent context by default. Alternatively, we will use the controller property if provided. You may also choose to directly override the context property. The order is as follows:
Specified controller
Supplied context (usually by Handlebars)
parentView's context (for a child of a ContainerView)

Related

How to use itemControllerClass to achieve a singleton like experience with ember.js

I've got a fairly simple form but it should never carry any state with it. I started reading an older discussion about how you can use itemControllerClass to get a "singleton" class created each time you enter the route.
If I want to use this how would I plug this into the template and wire it up from the parent controller?
Here is what I'm guessing you would do from the javascript side
App.FooController = Ember.Controller.extend({
itemControllerClass: 'someclass_name'
});
The only "must have" is that I need to have access to the parent route params from the child singleton controller.
Any guidance would be excellent -thank you in advance!
Update
Just to be clear about my use case -this is not an ArrayController. I actually just have a Controller (as shown above). I don't need to proxy a model or Array of models. I'm looking for a way to point at a url (with a few params) and generate a new instance when the route is loaded (or the parent controller is shown).
I'm doing this because the template is a simple "blank form" that doesn't and shouldn't carry state with it. when the user saves the form and I transition to the index route everything that happened in that form can die with it (as I've cached the data in ember-data or finished my $.ajax / etc)
Anyone know how to accomplish this stateless behavior with a controller?
I'm betting you're talking about this discussion. It's one of my personal favorite discoveries related to Ember. The outcome of it was the itemController property of an ArrayController; I use it all the time. The basic gist of it is, when you're iterating over an array controller, you can change the backing controller within the loop. So, each iterating of the loop, it will provide a new controller of the type you specify. You can specify the itemController as either a property on the ArrayController, or as an option on the {{#each}} handlebars helper. So, you could do it like this:
App.FooController = Ember.ArrayController.extend({
itemController: 'someclass'
});
App.SomeclassController = Ember.ObjectController.extend({});
Or, like this:
{{#each something in controller itemController='someclass'}}
...
{{/each}}
Within the itemController, you can access the parent controller (FooController, in this case), like:
this.get('parentController');
Or, you can specify the dependency using needs, like you ordinarily would in a controller. So, as long as the params are available to the parentController, you should be able to access them on the child controller as well.
Update
After hearing more about the use case, where a controller's state needs to reset every time a transition happens to a particular route, It sounds like the right approach is to have a backing model for the controller. Then, you can create a new instance of the model on one of the route's hooks; likely either model or setupController.
From http://emberjs.com/api/classes/Ember.ArrayController.html
Sometimes you want to display computed properties within the body of an #each helper that depend on the underlying items in content, but are not present on those items. To do this, set itemController to the name of a controller (probably an ObjectController) that will wrap each individual item.
For example:
{{#each post in controller}}
<li>{{title}} ({{titleLength}} characters)</li>
{{/each}}
App.PostsController = Ember.ArrayController.extend({
itemController: 'post'
});
App.PostController = Ember.ObjectController.extend({
// the `title` property will be proxied to the underlying post.
titleLength: function() {
return this.get('title').length;
}.property('title')
});
In some cases it is helpful to return a different itemController depending on the particular item. Subclasses can do this by overriding lookupItemController.
For example:
App.MyArrayController = Ember.ArrayController.extend({
lookupItemController: function( object ) {
if (object.get('isSpecial')) {
return "special"; // use App.SpecialController
} else {
return "regular"; // use App.RegularController
}
}
});
The itemController instances will have a parentController property set to either the the parentController property of the ArrayController or to the ArrayController instance itself.

Ember.js - How do I insert a controller?

So my understanding from the Ember docs is that the pattern for views/controllers/models is as follows:
[view] <- [controller] <- [model]
(with views consuming controllers consuming models)
In my previous experience using Ember, I'd set up a view to consume a model, like so:
{{#with blogpost}}
{{#view MyApp.BlogPostView contentBinding="this"}}
<h1>{{title}}</h1>
<p>{{content}}</p>
{{/view}}
{{/with}}
Now say I create a controller:
MyApp.BlogPostController = Ember.BlogPostController.extend()
Where do I initialize this controller?
Looking at the Ember docs, it seems like this happens automatically if the controller is associated with a route, but what if I just want an ad-hoc controller which ties together a view and a model? This could be for an arbitrary component on my page.
Am I responsible for instanciating the controller? Should I use some kind of controllerBinding attribute? Will it be instantiated automatically with my model, or with my view?
Any advice appreciated; I'm comfortable with the model/view pattern in Ember, but I'm having some difficulty working out where controllers fit in.
Looking at the Ember docs, it seems like this happens automatically if the controller is associated with a route
This is correct, a controller associated with a route will be automatically instantiated by ember when needed.
but what if I just want an ad-hoc controller which ties together a view and a model? This could be for an arbitrary component on my page. Am I responsible for instanciating the controller? Should I use some kind of controllerBinding attribute? Will it be instantiated automatically with my model, or with my view?
There are different way's to get your arbitrary controller instantiated automatically by ember without the needs of doing it yourself.
For the examples, let's assume you have a controller which is not associated with any routes called LonelyController,
App.LonelyController = Ember.ArrayController.extend({
content: ['foo', 'bar', 'baz']
});
Approach 1
Let's assume you have a route and you hook into setupController, if you try here to request you LonelyController with this.controllerFor('lonely'); this will make ember instantiate it for you:
App.IndexRoute = Ember.Route.extend({
setupController: function(controller, model) {
this.controllerFor('lonely').get('content');
// the above line will retrive successfully
// your `LonelyController`'s `content` property
}
});
Approach 2
Another possible way to get your LonelyController automatically instantiated by ember would be by defining a dependence with the needs API in another controller:
App.IndexController = Ember.ObjectController.extend({
needs: 'lonely',
someAction: function() {
this.get('controllers.lonely').get('content');
// the above line will retrive successfully
// your `LonelyController`'s `content` property
}
});
Using the needs API you could also doing something like this:
App.IndexController = Ember.ObjectController.extend({
needs: 'lonely',
lonelysContentBinding: 'controllers.lonely.content',
someAction: function() {
this.get('lonelysContent');
// the above line will retrive successfully
// your `LonelyController`'s `content` property
}
});
There are also some other combinations of the mentioned methods to get your LonelyController automatically instantiated, but I guess this should be more clear by now.
One last tip: to get a clue of what ember creates automatically under the hood you could also enable the generation logging to observe this in your console, which is very helpful, by doing:
var App = Ember.Application.create({
LOG_ACTIVE_GENERATION: true
});
Hope it helps.

ItemController does not work when we have a seperate controller for View

Part of learning Ember.js I am trying to create a Table View in Ember, based on example by Adam.
The issue I am facing is that if I create a seperate controller for the View and include an itemController for the Rows, ember gives following error: Uncaught TypeError: Cannot call method 'lookup' of null ember-1.0.0-rc.6.js:13933
When I debug this I find that in the following code :
controllerAt: function(idx, object, controllerClass) {
var container = get(this, 'container'),
subControllers = get(this, '_subControllers'),
subController = subControllers[idx];
if (!subController) {
subController = container.lookup("controller:" + controllerClass, { singleton: false });
The container is retrieved as null.
Whereas when it is run through ApplicationController, no such issue is there.
JS Fiddle Using ApplicationController for the View and another controller for itemController - Works Fine
JS Bin
in this the item Controller is specified as {{#each controller itemController="tableRow"}} and the controller is App.TableRowController
Here is a very similar JS Bin, JS Fiddle using a seperate TableViewController :
The item controller is similarly specified as {{#each controller itemController='tableRow'}.
A seperate Controller for Table View is binded using : {{view App.TableView controllerBinding="tableViewController"}} and this tableViewController is specified as a property in ApplicationController as :
App.ApplicationController = Ember.ArrayController.extend({
tableViewController: function() {
var tc = Ember.get('App.TableViewController').create();
tc.set('content',Ember.ArrayProxy.create({
content: Ember.A(tableData)})
);
return tc;
}.property()
});
But for some reason, the itemController does not work here.
Here is the JS Fiddle Using seperate Controller for View, but without any itemController - this works fine
Is there anything I am missing in the controller ?
Please help. Thanks.
With Ember most of the time you don't create objects directly, you declare the classes for things like controller, model, etc. And ember creates these objects using an IOC container. Avoid things like Controller.create. Similarly avoid directly controllerBinding instead use needs.
So, instead of providing a controllerBinding pass the content to be rendered by the App.TableView.
{{view App.TableView contentBinding=content}}
The setup of the tableData also belongs in a model() hook. It works in the sample because tableData variable is in scope.
Here's the updated jsfiddle.

How do I bind a controller to the view when the controller is create by Ember.js

this question is slightly related to How to display the “content” of an ObjectController?
However, in the provided solution and all other examples I can find the controllers are always created explicitly. The nice thing about Ember.js is that the Route takes care of mostly everything. So I don't want to create the controller but want to bind it to a view:
{{view App.myview controllerBinding="App.applicationController"}}
You can see the complete example in this fiddle. The example is not that great because Ember usually sets the controller of a child view to its parent view.
In the end I need to know, how I can access a controller which is created by Ember from a view.
Thanks for any help!
Update:
I provided the wrong fiddle or it did not save my changes. Here is the link to the right version: http://jsfiddle.net/ncaZz/1/
What should I provide in line 9 in the templates?
From the view you can access the controller with
this.controller
If you need other controllers than your view controller you can use the needs in the viewcontroller:
App.DatasetEditController = Ember.ObjectController.extend({
needs: ['mappingIndex']
});
and then use:
this.controller.mappingIndex
You don't really need to bind to it. You can access the controller from the view by calling it like this.
this.get('controller');
Updated Answer:
You really should not have your click event inside your view. Your actions should either be in your controller or your router.
Your template should become
<span style="background-color: green" {{action doStuff}}>
Click
</span>
and you should have a controller that should have this
App.MyController = Em.Controller.extend({
needs: ['application'],
doStuff: function(){
this.get('controllers.application').foo();
}
});
Also, the MyView and MyController should be capitalized, because when extending these items from ember that are not instances, and the capitalization is required. The view should only really have stuff in the didInsertElement that handles special things like any kind of jquery animations or initializing a date picker. But, the "ember way" is to have action in the router or controller.

{{outlet}}, {{view}}, {{render}}, and {{control}} helpers

I am trying to put together a simple master-details Ember app. Directory tree on one side and file list on another.
Ember offers few helpers to render context into a view. Which of them I can use for:
Subtrees of the directory tree.
Details list.
In fact, would be very helpful if someone can point me to any docs I can read about the difference between {{render view}}, {{view view}} and {{control view}} helpers and how to use them properly.
Thanks a lot!
{{view "directory"}} renders the view within the context of the current controller.
{{render "directory"}} renders the view App.DirectoryView with template directory within the context of the singleton App.DirectoryController
{{control directory}} behaves the same way as render only it creates a new instance of App.DirectoryController every time it renders (unlike render which uses the same controller instance every time).
Update 18 Feb 2014: {{control}} has been removed.
The last two helpers are relatively new, so there isn't much documentation about them. You can find {{view}} documentation here.
Now looking at your use case, I don't think you need any of these helpers. Just use nested routes and the {{outlet}} helper and it should just work.
App.Router.map(function(){
this.resource('directories', function() {
this.resource('directory', { path: '/:directory_id'}, function() {
this.route('files');
});
});
});
You can build on that following this guide.
UPDATE: {{render}} now creates a new instance every time if you pass a model.
For a very good explanation of the helpers render, partial, outlet and template have a look at this question.
Just as a rough a summary, how one might use those helpers:
{{render "navigation"}} -> Renders the NavigationController and NavigationView at this place. This is helper is good for places, where the Controller and View do not change, e.g. a navigation.
{{outlet "detailsOutlet"}} -> This will provide a stub/hook/point into which you can render Components(Controller + View). One would use this with the render method of routes. In your case you will likely have a details route which could look like this. This would render the DetailsController with DetailsView into the outlet 'detailsOutlet' of the index template.
App.DetailsRoute = Ember.Route.extend({
renderTemplate: function() {
this.render('details', { // the template/view to render -> results in App.DetailsView
into: 'index', // the template to render into -> where the outlet is defined
outlet: 'detailsOutlet', // the name of the outlet in that template -> see above
});
}
});
{{view App.DetailsView}} -> This will render the given view, while preserving the current context/controller. One might change the context, e.g. using your master entity and pass its details to a view like this:
{{view App.DetailsView contextBinding="masterEntity.details"}}
This is helper is useful, when you want to encapsulate certain parts of a component in subviews, that have own custom logic like handling of actions/events.
{{control}} I know that control instantiates a new controller every time it is used, but I cannot see a good fit for your, nor have i a good example for using it.
To Understand the difference between ember {{render}},{{template}},{{view}},{{control}}
you can refer this article
http://darthdeus.github.io/blog/2013/02/10/render-control-partial-view/