How to call child(`component`) method from parent? - ember.js

How to call the child(component) method from parent(router) template?
I would like to know the ember recomended correct approach.
here is my try( i am directly calling not works!!)
Live demo on Twiddle

Because ember motto is Data down, Action up. Calling an action from child component is not meaningful.
But if it is suitable for your case, use it as contextual. Seen as shown this twiddle.
Such as:
{{#child-omponent as |actionHandler|}}
<footer>
<h3 onclick={{action actionHandler }}>Click me to called child components action</h3>
</footer>
{{/child-omponent}}

Related

how to call an element in another layer hbs

There are two hbs files, one is under another layer, for example:
testA.hbs contains,
<div>
{{/testB.hbs}}
</div>
<div id="area">
Hello, world
</div>
At testB.js, I want to call the id area which is presented at testA.hbs. How can I achieve this?
Based on my understanding on what you need, you want to pass the property id from one template test-a to another template test-b.
So in order to make a property id available to your template test-b, you must pass it in like this {{test-b id="area"}}
Now you can access the property id in your
test-b.hbs as {{id}}
test-b.js as this.get('id')
Have a look at my ember-twiddle for a working example. Replicated the same scenario with two components.

Handlebars reference component one directory up

I have the following code:
{{#tabs-controls initial='content' modal="true" title="Hotspots" tabs=tabs style="on-ground" as |uniqueTarget currentTab|}}
<div class="tab-pane active" id="content-{{uniqueTarget}}" role="tabpanel">
//... Code
</div>
{{/tabs-controls}}
However tabs-controls is a component that lives outside the directory of the component calling it.
-components
-tabs-control
-hotspots
-hotspots-container
-hotspots-content
-template.hbs
I've tried:
{{#../tabs-control}}
{{#../..tabs-control}}
Both again without the pound sign...All I get are compiler errors.
What is the right way to achieve this?
This sort of relative path in Handlebars is more about navigating the rendering contexts than about file layout. Using the example from the Handlebars documentation, if you were using the context-switching version of each you could do:
{{permalink}}
{{#each arrayOfObjects}}
{{..permalink}} <!-- you are accessing the permalink property above -->
{{permalink}} <!-- you are accessing the permalink property of the of the object being "eached" -->
{{/each}}
However, this doesn't apply to Ember since the context-switching forms of helpers were removed.
The way to think about the path to components is that /components is the root, so if you have /components/tabs-control, the way you call it is {{tabs-control}}. If you want to render /components/hotspots/hotspots-container, the way to do it is {{hotspots/hotspots-container}}.

How to render Ember component on same line

This Ember template code...
<div class="detail bedrooms">
<span>Number of bedrooms:</span> {{rental.bedrooms}}
</div>
<div class="detail temperature">
<span>Current Temperature:</span> {{city-temperature location=rental.city}}
</div>
...results in this rendering...
How could one get the "25C" text to render on the same line as "Current Temperature" in the same way that "San Francisco" is on the same line as "Location"?
I have tried getting the city-temperature component to return only text, but (secondary question here) is it even possible for a component to return only text if the text is from a remote ajax request since the promise seems to need a DOM element to append to?
This Ember app is available here on GitHub. It's a modified version of the official Ember.js tutorial app with this "Current Temperature" detail added.
The problem is that; city-temperature is a component; and by default ember components is assigned div as their tags. Due to this; the content of city-temperature starts at a new line.
What can you do? Play with css and make sure div tag of city-temperature does not start at a new line; but instead floating right within the owner div. The second option is making city-temperature component tagless; so that it does not start at a new line. To achieve that; you can just declare:
tagName: ''
within city-temperature.js. You can see the following twiddle to see the second option I mentioned.
After reading your comments; I have forked your repository and made minor modifications to achieve what you want. You can check my repository and my corresponding commit to see what I changed.
Basically; I really did not like the idea that weather service is returning a DOM element. I have changed it to return an instance of ember promise (I mean Ember.RSVP.Promise). Within city-temperature.js I just set a retrieved weather value from weather service and set it to the component instead of making DOM modification. Finally; I modified city-temperature.hbs to render weatherValue and added a simple css item in order to prevent weather-container div to insert a new line break.
I am not sure; whether you will like my solution or not; but I guess you will retrieve the visual appearance you want. You can always rely on promises for async tasks; you do not need to create DOM elements and pass them around to components and append them to somewhere within DOM tree of the corresponding component. I believe one of the reasons we are making use of a framework like Ember is to prevent such DOM modifications. Best regards.
An ember component adds a div by default. If you don't want to add this div tag, you need to set tagName to an empty string.
That's called tagless component.
Further, for your case, you can give a tagName='span' so you will not need a span in your template.
export default Ember.Component.extend({
tagName: 'span',
classNames: ['weather-container'],
weather: Ember.inject.service(),
//rest of your code...
});

How to bind action only under certain condition [Ember.js]

I just want to know, is there some way I can achieve the below purpose.
<button class="{{unless publishable "button-disabled"}}" {{if publishable (action "publish")}}>Publish</button>
Of course, it can be done in action method. I just think it could keep code drier if it can be done in template.
NOTE:
I know the code above will not work. It's only for purpose illustration.
I know button can use disabled attribute to achieve this. In my original work, it is actually a <a/> which doesn't have disabled. I need to keep it as <a/> tag for css purpose.
I wish to keep the button in page no matter it is disabled or not. This is kind of web page convention. In that case, user will know that he must missing something when the button is disabled.
It is possible using {{mut}} in combination with {{action}} helper:
<button {{action (if publishable 'publish' (action (mut undefProp)))}}>Publish</button>
Working demo.
You can read more about this specific use case (mut converts to function) in this blog post.
Explanation:
We use action helper and action which we pass to that helper will be computed - based on if condition.
If condition evaluates to true we return 'publish' which is simply action name.
If condition evaluates to false then we pass action which does nothing - we use something like workaround: (action (mut undefProp)).

How to extensively configure an Ember.Component

I am creating an Ember.Component which displays a CRUD table. As the component shall be reusable it needs a lot configuration, such as columns to display, pagination options, etc. ...
At the moment I am inserting the component using handlebars:
<div class="some-div">
{{power-table items=this.model columns='...'}}
</div>
I wouldn't want to use this nice way of inserting a component. However, it is pot really possible to extensively configure a component here, is it? I found out it's not even possible to pass an object as parameter, e.g. the following it not possible:
<div class="some-div">
{{power-table items=this.model columns=[id, name, foo, bar] }}
</div>
How and where should I configure the component?
What you can do is that instead of setting columns=[id,name,foo,bar] in the handlebar like this:
<div class="some-div">
{{power-table items=this.model columns=[id, name, foo, bar] }}
</div>
You can set the columns property in the controller for the handlebar template and use the name of the property in the handlebar file. So all the logic would come from the controller and the handlebar would just tell which property is accessible in the component and by what name. So the controller for the enclosing template would be the best place to heavily configure the component. Have a look at the following page for more info:
http://emberjs.com/guides/components/passing-properties-to-a-component/
I am not sure if I understood your problem correctly.