Ember - Extending {{component}} helper - ember.js

What I want to do is to pass a string to {{component}} helper, but I want more control over what string it gets passed in at runtime.
e.g.
// getComponentToRender will get the current UI theme in the app,
// determine whether it's running on the mobile mode, then fetches the
// appropriate name of a component to render based on the type of the
// component. Just an example.
{{component getComponentToRender(ComponentType.Button)}}
I investigated this, it turns out this isn't possible (Otherwise, please correct me). Of course, there's computed property, but it doesn't take an argument.
Next, I looked into extending the helper. This stackoverflow question shows you can extend one, but I couldn't locate where the component helper is located in Ember. There doesn't seem to be any questions/documentation regarding extending existing helpers, either. This is what I would do with this approach.
// I can't find where the {{component}} helper is located.
import Component from './???'
export default Component.extend({
compute(componentType, hash) {
let componentName = getComponentToRender(componentType);
this._super(componentName, hash)
}
})
What did I miss? It'd be great if someone can put me into the right direction.

The only way of calling a function from a template is writing an helper. Actually your reference StackOverflow question is also mentioning about helpers. Writing an helper will solve your problem.
You don't need to extend the component helper. You need to compose it. As following:
{{component (getComponentToRender ComponentType.Button)}}
Here is the working twiddle.

Related

How to pass an object to link-to + queryParams in Ember?

I'm currently in a situation that I need to pass one object to {{link-to}}, but queryParams does not accept objects {key:value}. I need this feature because I'm using this component in different templates. The reason for doing that is that one template uses some keywords to use as a filter that the other template does not use and vice-versa.
I started using my own helper to generate the link, but I realize that the anchor my helper was generating was reloading the whole page and link-to does not do that. I'd like to reproduce that behavior, because there are other variables set on the view which I'm using and they all get reset to their default values whenever I reload the page
Is there a smart way to create a link using objects now? I saw some answers but they were all related to ember 1.+ and canary. In all of the answers they were saying it was not possible. I wonder if people have implemented this now or if a solution for this problem is being used currently and I could not find...
Thanks!
So I really could not find a way to do this. What I've done instead was creating {{actions}} inside my anchors and then I used transitionTo() to simulate the behavior of {{link-to}}.
A nice way of doing that can be seen here
Ember transitionToRoute cleanly in a component without sendAction

Ember 2.0 Controllers or Just Components...?

I have read that Ember2 is attempting to remove controllers. I was even linked to this RFC https://github.com/ef4/rfcs/blob/routeable-components/active/0000-routeable-components.md. However, I have been following the tutorial, and they insist on making a Controller. Do we still need to make Controllers or is this out of date?
Controllers are still needed (and thus haven't been deprecated) for two reasons: query parameters, and because components aren't routable yet. You can follow the tutorial's use of controllers without it causing you too much grief later on.
However, if you want to pull ahead of the tutorial, you can use components instead, barring the two caveats above. There is no way around using controllers for query parameters, but you can avoid the lack of routable components using this simple hack:
Let's say you're creating a Route called Dashboard. The tutorial will tell you to create corresponding Controller and Template as well. Go ahead and do that, but delete the Controller. Create a component called dashboard-main, move the logic from the Controller to the component.js file and the Template to the component's Template. Then, in the Dashboard Template, just refer to the component:
{{dashboard-main items=model foo=foo bar=bar ...}}
Depending on what you're doing in the Route, you still may need the setupController() method (that's still the only way you can move values other than the model from the route to the template so that they can be passed to the component), and of course your controller/component implementation may have other minor changes, but that's the basic gist of it.
To be most ready for when controllers are deprecated, you should avoid them by using components instead.

Proper way to pass a controller to a Component

Ok, I'm trying to get at a computed property on a random controller (not my template's default controller) to pass this property into a component on a random template. With some help on irc I was pointed to: "http://emberjs.com/guides/controllers/dependencies-between-controllers/" and realized my question was more of a controller dependency question than a component question, this helped but I'm still having issues.
So on my blah template's default controller (BlahController) I use the 'needs' hook to get access to the FooBarController like this:
needs: 'foo_bar'
And in the same blah template where I'm calling my component, I get at the FooBarController's property like such:
{{my-widget someProperty=controllers.foo_bar.someProperty}}
And my component just displays the property like such:
{{someProperty}}
The property (someProperty) I'm trying to access is a computed property with it's own dependancies. I get an error that the dependent properties on the computed property don't seem to be available???
Ember components are to be only used when you need completely isolated views to build re-usable ui elements. So, all content that a component needs for its template must be passed in when you invoke the component as parameters. A component should not be bound to a controller. Instead, when it needs to propagate events, it should use the 'sendAction' api to whichever controller controls the template it is invoked in. What you really need is a view.

Different rendering techniques in emberjs handlebars template

I've been reading a lot on emberjs lately but something isn't really clear to me: I have a feeling that there are different ways of rendering a template. Can someone explain the differences between these:
{{render}}
{{partial}}
{{template}}
{{outlet}}
I'm using pre4, so if some of these keywords are obsolete, please notify.
You can search the Ember.JS source for all of these by searching for: Ember.Handlebars.registerHelper('?'. For example, to find the part where template is defined, search for: Ember.Handlebars.registerHelper('template'
{{template}}
Is similar to the {{partial}}, but looks for templates that you define in the Ember.TEMPLATES hash. From the source code we can see an example: Ember.TEMPLATES["my_cool_template"] = Ember.Handlebars.compile('<b>{{user}}</b>'); and then we can render it that way.
I heard a whisper that {{template}} is #deprecated, but I can't find where I found that information at the moment. However, it's worth mentioning that I've never found myself using this one. Instead I prefer {{partial}}.
Edit: It appears as though it isn't #deprecated as of
3df5ddfd4f. My mistake!
{{partial}}
This is different to the {{render}} approach in that the controller and view are inherited from the context that called it. For example, if you're in the UserRoute, and you load in a partial in your user template, then the UserView and UserController will both be passed to your partial, so they can access exactly the same information as its current parent.
Partial names, when defined, start with an underscore. For instance, a Profile partial will have the data-template-name of: data-template-name="_profile" but is inserted into your view as {{partial "profile"}}.
{{outlet}}
You'll probably find yourself using this one a lot. It's predominantly used in cases where the outlet changes frequently, based on user interactions. By transitioning to (this.transitionTo/{{#linkTo}}) another page, Ember inserts the view into the {{outlet}} and attaches the relevant controller and view.
As an example, if you're transitioning into /#/pets then, by default, Ember will load the PetsView into the {{outlet}}, and attach the PetsController, all of this after initialising the PetsRoute to take instructions before initialising the view and finding the controller.
{{render}}
This is a mixture of an {{outlet}} and a {{partial}}. It's used for static pages that don't switch out for other pages (as an outlet does), but it doesn't inherit the controller and view (as a partial does).
It's better with an example. Let's say you've got a navigation. Usually you'll only have one navigation, and it won't change for another one, but you want the navigation to have its own controller and view, and not to be inherited from the context (probably ApplicationRoute). Therefore when you insert the navigation ({{render "navigation"}}), Ember will attach App.NavigationController and App.NavigationView.
Summary
template: Consults a global hash and inserts the view when it finds it (possibly soon to be #deprecated);
partial: Used to split up complicated views, and inherits the controller/view from the parent (if you're in the UserController, then the partial will also have access to this, and its associated view).
outlet: Most widely used, and allows you to quickly switch out pages for other pages. Relevant controller/view attached.
render: Similar to an outlet, but is used for pages that are persistent across the entire application. Assumes the relevant controller/view, and doesn't inherit them.
Did I explain them well?
Just to clarify:
Partial: Inherited controller, inherited view, non-switchable;
Outlet: Relevant controller, relevant view, switchable;
Render: Relevant controller, relevant view, non-switchable;
The guide also provides some useful information here! Below is a quick summary:
I wanted to post another answer here that really helped me to clarify when to use the various template techniques -
Route
Using a route is when you need a full-blown route. A 'route' has a unique URL and consists of generated or user defined classes of the following type -
Route (Ember.Route)
Controller (Ember.Controller || Ember.ArrayController || Ember.ObjectController)
View (Ember.View)
Template (Handlebars template)
{{render}}
Use the {{render}} helper when you need a view but still need to provide some functionality with a controller. {{render}} does not have a unique URL and consists of the following -
Controller (Ember.Controller || Ember.ArrayController || Ember.ObjectController)
View (Ember.View)
Template (Handlebars template)
{{component}}
Use the {{component}} helper when you are building a commonly re-used template which exists independent of the context it is rendered within. An decent example may be if you were building a retail website and wanted to have a product view agnostic of where it is rendered. {{component}} does not have a unique URL nor a controller but instead has a component class and consists of the following -
Component (Ember.Component)
Template (Handlebars template)
{{partial}}
Use the {{partial}} helper when you are simply re-using some mark-up. {{partial}} does not have a unique URL nor any special backing like a component and consists of the following -
Template (Handlebars template)

accessing the model from the template

Playing around with ember, I found that sometimes the model is stored on the controller's content property, sometimes the model is directly available on the controller as well. I do not understand however, when this is the case.
Let me explain it by an example which I found when assembling my ember MVC.
Setup A - The start
I defined a custom Member object, corresponding MemberRoute, MemberView classes and a template with the name member.
The Member object had some attributes such as id, nickname, etc.
NOTE: no controller of the form MemberController was defined, thus by ember's convention, it provides the controller on its own.
Setup B - The customization
Same as setup A, but now there is a MemberController defined that contains some action methods that are triggered from within the template.
The strange behaviour (resp. what I do not completely understand)
in setup A, I can refer to the Member's attributes directly with {{id}} or {{nickname}}.
in setup B, I have to use {{content.id}} or {{content.nickname}}
As documented in ember's documentation, MemberView does
setupController : function(controller, member) {
controller.set('content', member);
},
So, could somebody help me to understand why the difference and where the difference is? Currently, my guess would be either
that the context of the template is different (possibly there is a code piece missing in the setup of the controller?)
or
the default controller that is provided by ember automatically, has some additional magic that is not directly avaiable for customized controllers.
Any help to understand this is highly appreciated. It already took my quite a while to come as far as this. I first thought it could be the modularization introduced by the project setup with requireJS (well, I still think that could have a influence). Ember is v1.0pre4.
Thanks in advance!
Patrick
So, could somebody help me to understand why the difference and where the difference is? Currently, my guess would be either
that the context of the template is different (possibly there is a code piece missing in the setup of the controller?)
or
the default controller that is provided by ember automatically, has some additional magic that is not directly avaiable for customized controllers.
It's hard to say for sure without seeing your code, but my best guess is that your MemberController extends Ember.Controller. The default provided by ember (in this scenario) would have been an Ember.ObjectController. If that's what you want, change your MemberController definition to:
App.MemberController = Ember.ObjectController.extend({
myProperty: 'value'
});
An objectController acts as a proxy to it's content property, typically that is an ember model. So if things are wired up correctly you should never need to access a model via the 'content` property. If you ever see something like:
{{content.id}} or {{content.nickname}}
it's a sign that you should change to an ObjectController. See EMBER GUIDES: REPRESENTING A SINGLE MODEL! for a more detailed explanation.
an ObjectController acts as proxy to the object set to the controller's content. When no controller is defined, Ember will create a controller for you and set its content by default to whatever object is returned by the model() function, if defined, in the route. The behaviour should be the same whether you define your own controller or let Ember define one for you
The default context in the template is the controller itself i.e. this = an instance of your controller or the generated one. When you try to access nickname in that context, Ember will first try to resolve it against the controller itself and if nothing is found, it resolves it against its content, i.e the object if you already manually set it to the controller's content.
Finally, there is no default implementation of the model() function in the Route except when you're using dynamic urls, say /foo/id that resolves against /foo/:id, Ember uses the id provided to load a Foo object with the id provided, thus providing a default implementation to the model() function. At the end it boils down to the same mechanism, only automated for your convenience.
I suggest you listen to this for more insights on how things are automated for you by Ember. But when it comes to the content being displayed, there is no magic you have to manually wire the content of the controller.