I have a template where I have the following code:
<div {{bind-attr class=":suggestions isRecept::disabled"}} {{action "toggleRecept"}}>
<!-- skipped the rest -->
<a {{bind-attr href="recept_pdf" bubbles=false}}>Click for the recept!</a></p>
</div>
I want to link to an external pdf file. However when a user click on the link, the toggleRecept visibility action is fired. The bubbles=false is incorrect code, but that is what I wanted.
I know it is possible to limit the action, but I am curious if it is possible to do some bubble preventing on a simple HTML attribute.
Related
<div class="ui form segment">
<div class="field">
<div class="ui selection dropdown" tabindex="0">
<div class="default text">
Select
</div>
<i class="dropdown icon"></i><input name="hidden-field" type="hidden">
<div class="menu" tabindex="-1">
<div class="item" data-value="1">
Choice 1
</div>
<div class="item" data-value="2">
Choice 2
</div>
</div>
</div>
</div>
</div>
this code is written inside a template.hbs(handlebar) file.
I want to initialise the drop down with the following command
$('.ui.dropdown')
.dropdown();
where could I write the second code?
if it was an html/php file I could write inside the template
Short answer, you don't.
Long answer:
If you are developer who takes any pride in his work and doesn't want the next maintainer to fantasize about drowning you in dirty toilet water, you should create a dropdown component. This component seems small in scope and would look something like this:
{{dropdown-list options=listOfOptions onOptionSelect=(action "someAction")}}
You pass in the options, convert:
<div class="menu" tabindex="-1">
<div class="item" data-value="1">
Choice 1
</div>
<div class="item" data-value="2">
Choice 2
</div>
</div>
to:
<div class="menu" tabindex="-1">
#{{each options as |option|}}
<div class="item" data-value="{{option.value}}">
option.displayName
</div>
{{/each}}
</div>
where each options is [{displayName: "Option 1", value: 1}...]
Inside of the javascript part of the component, simply execute the above code from within didInsertElement which the docs describe:
After a component successfully renders its backing HTML element into the DOM, it will trigger its didInsertElement() hook.
Lastly, inside of the component, bind listeners to the dropdowns native events. One such function, the one for the dropdown's select action, should call this.onOptionSelect(whateverTheSelectedValueIs). This allows you to define actions differently for each dropdown.
I highly recommend you take a moment to read this section of the docs
Writing Ember requires a different mindset than writing backend rendered html + jquery style applications. You want to really decouple your javascript code from the DOM as much as possible and focus on values + data down/actions up. Components are the correct place to bind to native javascript events and integrate with 3rd party addons. Doing so effectively isolates the DOM interactions and provides a nicer api to the rest of your application. If you were to just use the routes renderTemplate hook to execute the .dropdown() call, you require every developer to remember to call dropdown any time you want to use a dropdown and have done absolutely nothing for reusability and just hacked your way to a solution. Don't be that guy, do it right :)
I have an odd conundrum.
It appears that when an element is hidden by a focus-out event ember is unable to attach the corresponding click event that triggered the focus out properly. For example with the code below if the <a> tag triggers the focus-out event on the input and the code behind turns _focused to false then the selectOpts event is never triggered. It appears to only happen if the a tag is hidden as a result of the focus-out.
Also oddly it does not matter how the a tag is hidden either if i do just display:none it still also doesn't fire the selectOpt action.
Here is my code:
<div class="dropdown">
{{input value=value class='form-control' focus-in="focused" focus-out="unfocused" }}
{{#if _focused}}
<ul class='dropdown-menu'>
{{#each _filteredOptions as |opt|}}
<li><a href="#" {{action "selectOpt" opt}}>{{opt}}</a></li>
{{/each}}
</ul>
{{/if}}
</div>
Here is a ember twilldle showing the issue.
https://ember-twiddle.com/6bbdb669d19d7a498e645bb0297f1b46?openFiles=templates.components.input-autocomplete.hbs%2Ctemplates.components.input-autocomplete.hbs
In order to get it to show the issue focus in on the text area and then try to select one of the links that appear below the input. What is supposed to happen is that when you select the link it is to populate the input field with the value.
You can use just focus-in instead of both focus-in and focus-out. So when you click on input focus-in event trigger and set _focused to true. Then, in action selectOpt you set value and after that set property _focused to false.
<div class="dropdown">
{{input value=value class='form-control' focus-in='focused' }}
{{#if _focused}}
<ul class='dropdown-menu'>
{{#each options as |opt|}}
<li>
<a href="#" {{action "selectOpt" opt}}>{{opt}}</a>
</li>
{{/each}}
</ul>
{{/if}}
input-autocomplete.js
actions: {
focused() {
this.set('_focused', true);
},
selectOpt(opt) {
console.log(opt);
this.set('value', opt);
this.set('_focused', false);
}
}
I didn't include all code for input-autocomplete it's the same as before exxept actions. Also I used options array insted your filter because didn't get any results when clicked on input.
I couldn't know how to handle Template onRendered or similar things as below.
<div class="col s1">
{{#if previous_group}}
</i>
{{else}}
</i>
{{/if}}
</div>
<div class="col s4 offset-s6 right">
{{#if next_group}}
</i>
{{else}}
</i>Complete Inspection
{{/if}}
</div>
The above is the code snippet of inspect_go template file.
As you can see, if you have previous or next group, whenever you click previous or next button, you goes to the same template by pathFor of iron:router, and in this case, the Template onRendered does not invoked because app recognize as we already are in the same page.
Template.inspection_go.onRendered(function() {
// Some things to handle within each inspection_go template
});
So I need to find a way to handle some thing when I click inspection_go href to go next inspection_go template.
Please teach me how to solve this problem!
The solution here could be the following: As you do not change the template just add a class to the <a href>.
The rest which you could not achieve without the router, do by setting Sessions in js
click event.
I have the following bit of template in a project I'm working on:
<div class="item row" {{action "expandItem"}}>
{{input type="checkbox" checked=isChecked}}
{{item.name}}
</div>
The trouble I'm running into is that clicking the checkbox does not change its state. It does, however, fire the expandItem action. I'd like the behavior to be that clicking on the checkbox changes isChecked but clicking anywhere else in the div fires expandItem. How can I accomplish this?
EDIT: The question Stop click propagation from Ember action is very close, but the difference as I see it is that the child element in the other question is using the {{action}} helper, which can easily stop propagation with bubbles=false. In my case, I don't necessarily have a hook into how Ember's default Input Component bubbles the action
SECOND EDIT: I recreated exactly the behavior I'm seeing in this JSBin. You'll notice how the Input Component and the inline action helper behave differently. Hope this helps.
Since Ember 1.13.3 you can do the following (the example does not use input helper and I would not recommend using it if possible):
Template:
<label onclick={{action "stopPropagation"}}>
<input type="checkbox" checked={{checked}}
onchange={{action "check" value="target.checked"}}>
</label>
Component/controller:
actions: {
check() {
this.toggleProperty('checked');
},
stopPropagation(event) {
event.stopPropagation();
}
}
You cannot just stop action from propagating with bubbles=false since in this case event.preventDefault is also called disabling default checkbox behavour.
Here is Ember Twiddle
I was intrigued by this problem, as far as I see there is no native way to prevent bubbling the event from an input helper.
But there is a workaround. Create a non visible div floating above the checkbox, and use a click event that selects the underlying checkbox:
Template:
<div class="item row" {{action "expandItem"}}>
<div style="position-absolute; display: inline-block;">
<div {{action "toggleSelect" bubbles=false}} style="position: absolute;left: 0;width: 12px;top: 0;bottom: 0;"></div>
{{input type="checkbox" checked=isChecked}}
</div>
{{item.name}}
</div>
Action in Controller/Component:
actions: {
toggleSelect() {
this.set('isChecked', !this.get('isChecked'));
}
}
So I have an Ember application that uses bootstrap. I got that working fine it seems, but I'm having issues getting a button from within a dropdown menu to trigger an action. I can have a button outside of that dropdown call the same action, and it works fine.
Controller:
actions: {
clearWords: function(){
console.log("clear it!!");
}
}
HBS:
<li>
<div class="dropdown"> ...
<button type="button" {{action "clearWords"}}>Clear</button>
...
</div>
</li>
<li>
<button type="button" {{action "clearWords"}}>Clear</button>
<!-- ^^ this one works -->
</li>
I've tried adding target to the action bit, but that never works either.
{{action "clearWords" target="controller.controllerName"}}
Any suggestions to get me in the right direction would be much appreciated.
PS: If you happen to be kind enough post sample code from JSBin, could you use JSFiddle instead? I can't see JSBin behind my proxy here :(
Sorry, turns out there was a stopPropagation() called further up in the controller that kept the action from bubbling up. We were using this to keep the dropdown menu open through various clicks.
Hopefully this will help someone else troubleshoot their code. I didn't think bootstrap would be blocking the actions, but this certainly explains it.