JS Event bubbling up the DOM - javascript

On my meteor app I have comments and within those comments I have a button "reply" when I click on reply the form to leave an additional comment will open.
The problem is that when I click on a reply button it opens the form on all the other comments as well as the one clicked instead of only where I clicked.
this is my code
template.replyComments.events({
'click #replyToCommentButton2': function(e) {
$(".commentToShow").show();
},
//...
)};
and html
<button class="btn waves-effect waves-light" data-show="#form2" id="replyToCommentButton2">Reply
<i class="mdi-content-send right"></i>
</button>

Try using stopPropagation and narrowing down the .commentToShow class, maybe adding a data attr to the button you are clicking that will tell you the element to show:
HTML:
<a id="replyToCommentButton2" data-show="#form2">Reply</a>
JS:
template.replyComments.events({
'click #replyToCommentButton2': function(e) {
e.stopPropagation();
$(this).parent().find('.commentToShow').show();
},
)};

There are two things you'll need to do, one of them is to stop the propagation event from bubbling up the event chain and the second one is only reference the current object (referenced with this), because you're targeting all the classes instead of the current object.
template.replyComments.events({
'click #replyToCommentButton2': function(e) {
e.stopPropagation();
var targetedForm = $(this).data("show");
$(".commentToShow", targetedForm).show();
},
This should help to understand event propagation: What's the difference between event.stopPropagation and event.preventDefault?

So this is not really answer to your question, but unless you are using some third party lib that requires you to manipulate the DOM with jQuery there is a more Meteoric approach to this.
// comment.coffee
Template.comment.created = ->
# Keep the state of the comment in a ReactiveVar on the template instance
this.showReplyField = new ReactiveVar
Template.comment.events
"click [data-reply]": (e, tmpl) ->
e.stopPropagation()
# If the reply field is open then close it and vice verse
currentState = tmpl.showReplyField.get()
tmpl.showReplyField.set !currentState
Template.comment.helpers
reply: ->
# Get the state and expose it to the template. It will update reactively when the value changes and only for this template/comment.
Template.instance().showReplyField.get()
// comment.html
<template name="comment">
<p>{{text}} </p>
{{#if reply}}
{{> newComment}}
{{else}}
<button class="button" data-reply>reply</button>
{{/if}}
</template>
<template name="newComment">
<!-- Your new comment html here -->
</template>
Note that you will need to meteor add reactive-var to add the reactive var package.
This is what I'm using in my comments package for a blog. You can check out the source code here if you wish.
And if you dont like coffeescript you can translate it.
If you still prefer to use jQuery you should probably use the template optimised version that ships with Meteor. Within an event handler it's available as tmpl.$ and will only select elements within the template (so children will be included too).

This was the answer to the problem I was having (answered by someone on Meteor forums)
template.replyComments.events({
'click #replyToCommentButton2': function(e, template) {
template.$(".commentToShow").show();
},
//...
)};

Related

Identify HTML elements when event triggers

I have my app with tons of buttons/inputs/etc. with different events. I want to clearly identify each one of them which some event triggers on.
For example, when I have a piece of my app:
<div class="someClass">
<div>
<someOtherElement>
<div></div>
<div><button ng-click="someClickEvent($event)"></button></div>
</someOtherElement>
</div>
</div>
I want to identify somehow, which button I have just clicked:
function someClickEvent(e) {
// some identification code here
}
[edit]
Maybe I wrote this wrong... I want some identification like XPath or something that will point which button were triggered (for error logging purposes).
So when I click my button and some error occurs, I want to identify the button and log some information about it (e.g. div[0].someClass>div[0]>someOtherElement[0]>div[1]>button[0]).
You can get identify the button and log it by this:
$scope.clickFunc = function(event){
$scope.clickedElement = event.target.outerHTML;
};
DEMO: http://jsfiddle.net/rjdzuxaL/1/
Use ng-click instead on onclick
<button ng-click="myFunction($event)">test</button>
Working demo
Change HTML to:
<button ng-click="myFunction($event)">test</button> //onclick works on javascript. For Angularjs, use ng-click.
JS:
$scope.someClickEvent = function(e) {
// some identification code here
var element = e.target; // this will give you the reference to the element.
}
You should avoid handling DOM in the controller. Use directives for them.

Meteor template data object prevents javascript events from firing?

I ran into a very strange issue in Meteor...
I have a function that renders a template and append it to a div, inside the added template there's a button that can trigger listener events.
The strange thing is the click event can be triggered when I render the template without any data object as argument, but as soon as I pass in a data object into the template, all javascript within the newly appended template stop working...
Ideally I want to be able to pass in data to the template and have the events fire correctly, does anyone know what's exactly going on here? Thanks a lot!
Failure Scenario with passing in data to template:
client.coffee
Template.detail.events {
'click .ol_self_help_btn': (event) ->
alert 'event fired' //This is never triggered
}
Template.room.events {
'click .ol_detail': (event) ->
element = $(event.currentTarget).closest('.ol_property')
element.append Meteor.render Template.detail # //Passing in "this" data object to the template
}
detail.html
<Template name="detail">
<div class="row ol_detail_panel">
<button style='button' class='ol_self_help_btn'>Click Me</button> //The button that the event is attached to
</div>
</div>
</Template>
Success Scenario without data object passing:
client.coffee
Template.detail.events {
'click .ol_self_help_btn': (event) ->
alert 'event fired' //This is triggered when clicking on the button
}
Template.room.events {
'click .ol_detail': (event) ->
element = $(event.currentTarget).closest('.ol_property')
element.append Meteor.render Template.detail //NOT Passing in data to the template function
}
detail.html
<Template name="detail">
<div class="row ol_detail_panel">
<button style='button' class='ol_self_help_btn'>Click Me</button> //The button that the event is attached to
</div>
</div>
</Template>
This should render the current # into the template.
Template.room.events
'click .ol_detail': (event) ->
element = $(event.currentTarget).closest('.ol_property')
template = Template.detail #
element.append Meteor.render(template)
This looks messy:
element.append Meteor.render Template.detail
To debug I would break it up into something like (excuse my non-Coffee Script syntax, I'm going old school with pure JS):
var my_render = Meteor.render(Template.detail);
element.append(my_render);
Then use lots of console.log() statements to figure out where the miss match is happening. i.e.
console.log("my_render: " + my_render);
console.log("element.append(my_render): " + element.append(my_render));
btw - your example doesn't show the room template, so assuming it's pretty simple.

handling jQuery onClick event on handlebars

I would like to set up a simple jQuery onClick event to make the UI dynamic on a handlebars template. I was wondering to addClass() after a specific click.
consider the HTML (generated by handlebars)
{{#if hasButton}}
<div id="container">
<button type="submit" class="myButton">Click me!</button>
</div>
{{/if}}
i.e: After a click within a button, its container will receive a loading class that will create the interaction using CSS.
$(".myButton").on("click", function(event){
$(this).parent().addClass("loading");
});
This code should goes on my handlebars-template or should I rewrite it into a specific helper for it? Is there any examples that could be provided so I can study it then develop something similar?
Thanks in advance!
there is no need to reattach the event handler on every dynamic DOM update if you're defining them at document level:
$(document).on('click','li',function(){
alert( 'success' );
});
Hope this helps! :-)
You have to refresh your Jquery listeners AFTER the insertion of nodes into your DOM HTML.
var source = "<li>{{label}}</li>";
var template = Handlebars.compile(source);
var context = {"uri":"http://example.com", "label":"my label"};
$("ul").append( template(context) );
// add your JQuery event listeners
$("li").click(function(){ alert("success"); });
I am not sure what your problem exactly is.
It's correct like this if you keep your JavaScript in a *.js file, perhaps using parent() instead on prev() in this specific case.

Bootstrap onClick button event

This seems a silly question but just got bootstrap and it doesn't gives any examples on the website about adding a Javascript callback to a button...
Tried setting my button an id flag and then
<div class="btn-group">
<button id="rectButton" class="btn">Rectangle</button>
<button class="btn">Circle</button>
<button class="btn">Triangle</button>
<button class="btn">Line</button>
<button class="btn">Curve</button>
<button class="btn">Pic</button>
<button class="btn">Text</button>
<button class="btn">Gradient</button>
</div>
I want to add a callback to Rectangle button...
$('#rectButton').on('show', function (e) {
//ACTION
})
cant get the point of bootstrap callbacks.
All I could found on the web is oriented to Rails + Bootstrap... no bootstrap and JS only.
There is no show event in js - you need to bind your button either to the click event:
$('#id').on('click', function (e) {
//your awesome code here
})
Mind that if your button is inside a form, you may prefer to bind the whole form to the submit event.
If, like me, you had dynamically created buttons on your page, the
$("#your-bs-button's-id").on("click", function(event) {
or
$(".your-bs-button's-class").on("click", function(event) {
methods won't work because they only work on current elements (not future elements). Instead you need to reference a parent item that existed at the initial loading of the web page.
$(document).on("click", "#your-bs-button's-id", function(event) {
or more generally
$("#pre-existing-element-id").on("click", ".your-bs-button's-class", function(event) {
There are many other references to this issue on stack overflow here and here.

Dijit ComboButton / DropDownMenu onclick misunderstanding

I've just begun to play around with Dojo. I simply wanted to display a dialog when an item in a Dijit ComboButton's DropDownMenu is clicked. I tried using dojo.connect to associate the onclick event with a function which would simply display a dialog with the text contained in the item, with no luck.
I've managed to get it working in a horrible way. All the work is now actually written to the onclick attribute manually. I'm clearly misunderstanding something here. This is what I currently have:
JS:
require(["dijit/form/Button", "dijit/form/FilteringSelect", "dijit/DropDownMenu", "dijit/MenuItem"]);
//if the following is defined inside dojo.ready, nothing happens
function getmail(text)
{
alert('No mail from '+text);
}
dojo.ready(function(){
//the following does nothing:
dojo.connect(dojo.query(".dijitMenuItemLabel"), "onclick", function(evt) {
console.log("mail item clicked");
alert('Blah');
//dojo.stopEvent(evt);
});
});
HTML:
<form method="POST">
<div data-dojo-type="dijit.form.ComboButton" id="getmail">
<span>Get All Mail</span>
<div data-dojo-type="dijit.DropDownMenu">
<div data-dojo-type="dijit.MenuItem"
data-dojo-props="onClick:function(){getmail(dojo.trim(dojo.query('.dijitMenuItemLabel', this.domNode)[0].innerHTML))}">
Yahoo</div>
<div data-dojo-type="dijit.MenuItem">Google</div>
</div>
</div>
</form>
What does it look like I am clearly misunderstanding about Dojo?
(Or maybe I'm making simple JavaScript mistakes)
JSFiddle
You should be able to do it with something like
var myButton = dijit.byId('getmail');
myButton.on('click', function(){ alert('clicked') });
My guess is that you confused dojo.byId and dijit.byId when you fetched your button - regular DOM nodes work when you conenct a lowercase 'onclick' but widgets fire a camel case 'onClick' event (the distinction is because dijits fire with some keyboard events, for accessibility).
However, for newer versions of Dojo it is probably best to stay away from dojo.connect and instead just use simpler ".on" API I showed.
Ah, and before I forget, it also looks like you could have forgotten to run the Dojo parser (or set parseOnLoad to true) so the button was never created. Can you provide a fully executable example on JSFiddle?

Categories