How to render component/helper from another one? - ember.js

I have render-component ( source ) which used to render components/helpers from controller fields. It worked fine for ember 1.9.1 but after updating up to ember 1.12.1 I found changes in API. After updating code I restore simple cases ( like render view by name from some property ). But largest part of functionality still broken.
I'm interesting about where can I read more about such things like
env ( which used inside components/helpers internal implementation )
morph ( I understand that it's a part of html-bars, but I'm interested in more documentation )
hooks ?
Can anyone share some experience at creating such helper ? Or way to find solution in such cases? ( I mean that this things not fully documented )
P.S. I know about component-helper from ember 1.11 -- but it doesn't allow render helpers ( with params) and using it I should define all properties in template. And when name of component/helper is dynamic -- I should pass different params / attributes.
Thx in advance
P.P.S
Some examples of functionality I want restore with my helper ( more examples and motivation you can find at helper page -- I just want note difference between my helper and build-in component-helper ):
{{#render-component componentName _param='btn-component' action="addSection"}}
{{render-component 'pluralize-component' ___params=hash}} // hash = { count:ungrouped.content.meta.total, single:"Object"}
{{#render-component 'componentName' _param=paramName someOption=someOptionValue}}

You've got quite a few questions here, but to answer the one in your title: Ember 1.11 introduced the component helper that allows you to dynamically render components.
componentName: 'someComponentName'
...
{{component componentName param=value someAction='someMapping'}}

This article contains most of the information one might use to implement what I think you're getting after (compared to the standard component helper).
One notable out-of-the-box solution they suggest is the use of the (almost deprecated) dynamic-component addon.
{{dynamic-component
type=theType
boundProperty=foo
staticProperty="bar"
onFoo="fooTriggered"
}}
Hopefully this (and other suggestions from the article) steer you towards your solution.

I was looking for an answer to this, ended up with a solution myself.
My scenario was that I wanted to pass in a component to another component and render it inside that component, which sounds like what this question was aiming for.
For those who don't clearly know how the {{component}} helper works:
Use it to render another component.
{{component "component-name" param1="value" param2="value"}}
This would work exactly the same way as:
{{component-name param1="value" param2="value"}}
For my scenario, I did this:
In the template invoking the first component:
{{my-comp-1 comp=(component "my-comp-2" param1="value" param2="value") other-param="value"}}
In my-comp-1's template, use the attribute used for the component:
{{component comp}}
That was all I needed to do.
This works perfectly as of Ember 2.7.0.

Related

How to inject components in whole application in ember.js

I'm on developing a ember-cli project where I have created many reusable components. I want these components in every template(hbs) file. I can do {{component1}} {{component2}} {{component3}} in each template but this looks redundant to me since I've to write all these lines in every template. All I want to know is if I can inject components in all the templates like way services are injected into routes, components etc where ever I need.
Example of how I inject services is below
/intializers/session-object.js
export function intialize (application){
application.inject('route','session','service:session');
application.inject('controller','session','service:session');
application.inject('component','session','service:session');
application.inject('adapter','session','service:session');
});
I tried injecting the components into templates as similar as above.
/intializers/session-object.js
export function intialize (application){
application.inject('template','my-component','component:my-component');
});
As expected, the above code fails. No where in the ember guides is mentioned that I can inject components in templates. But, wanted to know if anybody did this before.
I believe there could be a strong reason why ember is not allowing us to inject components into templates.
Any help in explaining the reason why this cannot be implemented in ember.js is great or providing a solution if it can be implemented is awesome. Thanks in advance guys.
Injecting to template is not meaningful.
You can create a partial template and put that common components there then use that partial.
-common.hbs
{{nav-bar}}
{{error-messages}}
another.hbs
{{partial 'path-to-common-template'}}

TextField View Helper - Ember.Handlebars.helpers.view.call is not a function

I'm working on upgrading my grunt CLI based ember 1.8 app to 1.10 with HTMLbars & have made progress, but my view helpers and components don't work; such as date-input, ember-select, bing-map, product-item. So I'm starting with the date-input view helper which returns this error now - "Ember.Handlebars.helpers.view.call is not a function". This input control is rendered via {{date-input... which is associated to 'DateInputView' in views/date-input.js which extends Ember.TextField. It's also associated to helpers/date-input.js and Ember.Handlebars.makeBoundHelper(). The function inside returns Ember.Handlebars.helpers.view.call() which results in the error. I read something about how maybe my template compiler isn't the new one required or maybe a Component should be used rather than a View Helper, but it seems like there should be a simple fix for the View Helper, don't you think?
Development of this viewHelper was done by another party and the purpose of the callback making a call to viewHelper is a mystery. Regardless, the use of viewHelpers is being discouraged going forward and I've re-worked the date-input as a Component.

Proper way to seed routes for view spec

I am testing my views with RSpec. Due to some changes, there is now a call to url_for in the view and all the spec that I wrote for show actions are failing:
No route matches {:controller=>"events", :action=>"show"}
The :id part is missing and because of that the call fails.
(I know that I can just stub that failing method call)
The only thing I found is pretty old and looks like a bad workaround. Also the RSpec documentation does not show something helpful.
Is there a proper way to tell RSpec that it should be on something like events/123?
Some more context:
In the view
I call a helper, something like this:
def some_helper_method
url_for(only_path: false)} + "something_else"
end
The call to that method fails with
Failure/Error: render
ActionView::Template::Error:
No route matches {:controller=>"events", :action=>"show"}
I'm currently fixing it by stubbing the call to that method view.stub(some_helper_method: 'SOME_URL')
Okay, I think I found your answer. I cloned your repo and debug a lot =P until I found that you need to infer the desired parameters in your view spec, since rspec-rails only provides the :controller parameter for the view being rendered. Well, in an attempt to understand better what the issue is, I found this explanation in the rspec-rails documentation:
View specs infer the controller name and path from the path to the view template. e.g. if the template is "events/index.html.erb" then:
controller.controller_path == "events"
controller.request.path_parameters[:controller] == "events"
This means that most of the time you don't need to set these values. When spec'ing a partial that is included across different controllers, you may need to override these values before rendering the view
In other words, the previous link that you posted still works and is still the solution for the parameters "issue" in your view spec. You can follow the discussion about the topic in this PullRequest thread.
So, the conclusion is that if you really don't want to stub out your call to url_for helper (or the helper that is calling it), you need to supply the desired :id parameter since there's no route for any show action without an :id param (as pointed out by you). Our final result (tested) is indeed:
controller.request.path_parameters[:id] = event.id
If this a workaround ? I really don't think so, since rspec-rails itself is internally using this feature to provide the :controller param.
I'm sorry I couldn't be more helpful before, but I think that this closes all of our main doubts.
My opinion ? If you really don't need to make any assertions based on the url_for behavior (or any helper behavior for that matter), just stub it, since it is expected to already have been tested in isolation. Otherwise, use the :id param, and don't worry about it. It is not a workaround.
Cheers friend !
If you will face the id problem the try this in your route.rb
get "events/show/:id", :to=> "events#show"

Emberjs - unable to redefine named, explicitly compiled Handlebars template

As part of an attempt to port a fairly large/complex existing application to the Ember world, I'm generating and compiling named Handlebars templates dynamically, and associating views with them, using the technique:
var template = Ember.Handlebars.compile("some handlebars stuff");
Ember.TEMPLATES["myTemplate"] = template;
var view = Ember.View.create({
templateName: "myTemplate"
});
One of the things I'd like to do is be able to recompile new/different Handlebars template markup which overwrites the template named "myTemplate" and have it be accessible to views at that name.
I'm getting unexpected results trying to do this - a couple fiddles that illustrate the problems:
First fiddle - Shows what happens if you wait before rendering a view after the named template contents have changed.
Second fiddle - Shows what happens if there's no delay before rendering a view after the named template contents have changed.
There's obviously some magic under the hood that I'm not understanding. Can anyone shed some light on this?
UPDATE:
I went through the source code for Ember.View and the container module, and came to realize that I could solve the problem in the First fiddle by overriding the "template" computed property in a way that skips the container cache lookup. I've put up another fiddle here to demonstrate the solution I found.
This seems to be working the way I'd like it to - but - it feels like I might be fighting with the framework and "unhooking" from the container in a way that might bite me later. Is there a better, more Ember-esque way to accomplish what I'm trying to do? Will the hack I found break things?
UPDATE 2
I've also discovered that it's also possible to simply call
view2.get('container').reset();
before appending view2 in the First fiddle. Seems cleaner/safer, but is it "legal"? I've updated the First fiddle to illustrate this.
(in the second fiddle, both views show the second template)
This is because view1.appendTo($("#target")); just schedules the append, actual view rendering does not happen until end of the run loop. Before that happens, you've set Ember.TEMPLATES["myTemplate"] = template2;
(in the first fiddle, both views show the first template)
Pretty sure this is because ember container caches template fx, but not 100% on that. Checking...
I'm going to call this one answered. As I mentioned in my second comment, I'm using the solution shown in this fiddle in my project, along these lines:
mYiew.get('container').reset();
There's some discussion about the container not being intended to be used as an API here: https://github.com/emberjs/ember.js/commit/5becdc4467573f80a5c5dbb51d97c6b9239714a8 , but there doesn't seem to be any mention of using the container from Views for other use cases.
Also, a View's container can be accessed directly (at ".container") - meaning the devs haven't made it "hard" to get to the way they have for an Application's ".__ container __". This might suggest something about how they intend it to be used.
Since a View having the ability to clear its cache whenever it wants to doesn't seem to me to be unreasonable or a bad practice, I'm using the above mentioned solution...at least until someone sets me straight with a better idea (or a cache API).

Ember.Controller doesn't exist?

I'm just getting started with Ember. I'm a little confused on some things, as the guides on the main site seem to indicate different ways of working.
In the main docs (http://emberjs.com/documentation/), it indicates that a controller should just extend an ordinary Ember object like this:
Ember.Object.extend();
Which works fine for me.
Then in the guide to using Routing (http://emberjs.com/guides/outlets/) it suggests that there is a Controller object type that you can extend:
Ember.Controller.extend();
This doesn't work for me, and if I simply try to console.log Ember.Controller, its undefined.
I'm using Ember version 0.9.8.1.
Should I worry about this, or should I just carry on with extending Objects as my controllers?
0.9.8.1 is aging, and unfortunately even the guides on the site are ahead of it -- use latest (at https://github.com/emberjs/ember.js/downloads) to keep up with the most current best practices.
Update: 1.0-pre is out (emberjs.com), so that is the best to use. The docs / guides have been brought up to date.
I think #pauldechov means the specific "latest" build which you can find here: https://github.com/emberjs/ember.js/downloads
But also keep in mind that the documentation and "latest" are not always in sync.