Click event hijacked by jQuery instead of knockout - javascript

I'm using the Knockout webmail tutorial as a template for a Single Page Application I'm working on.
However I'm having trouble implementing the click binder, I've had this sort of thing working before but his time the click events are being hijacked.
My view model has a function:
var self = this;
self.goToItem = function(item) { location.hash = "#/Item/" + item.id };
which is standard.
<h2>Saved Items</h2>
<div data-bind="foreach: savedItems">
<div data-bind="click: $root.goToItem">
<p data-bind="text: name"></p>
</div>
</div>
I've tried the:
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>
but, tellingly, this came back empty although the foreach has data to loop over.
The problem now is that the mousevent click is now caught by jQuery, I haven't had to delve into this before, but I am sure knockout runs without jQuery. At the moment the only jQuery I use is for the Ajax calls.
So where do I go to inspect the events on DOM objects, preferably in Chrome?
How can jQuery butt in?

Have you tried to use clickBubble binding?
Preventing the event from bubbling
By default, Knockout will allow the click event to continue to bubble up to any higher level event handlers. For example, if your element and a parent of that element are both handling the click event, then the click handler for both elements will be triggered. If necessary, you can prevent the event from bubbling by including an additional binding that is named clickBubble and passing false to it, as in this example:
<div data-bind="click: myDivHandler">
<button data-bind="click: myButtonHandler, clickBubble: false">
Click me
</button>
</div>
Normally, in this case myButtonHandler would be called first, then the click event would bubble up to myDivHandler. However, the clickBubble binding that we added with a value of false prevents the event from making it past myButtonHandler.
More details about click binding is here http://knockoutjs.com/documentation/click-binding.html

If I replaced
click: $root.goToItem
with
click: goToItem
it works again.
It seems the jQuery event firing was a red herring, I compared it to a working system and it started off in jQuery. I had to brush up on my DOM debugging, which is no bad thing.
Is the $root superflous, it took someone else to point this out to me. I was sure that in a foreach loop you could only access the $root functions via $root.

Related

Make sure that a specific Jquery click event executes first

I have a complicated DOM structure with divs, uls, li, and span elements.
On this elements can be a jquery click event which do some logic.
If the application goes offline I have to disable the click events on this elements.
It is possible to add a generic click event which executes first, where I can check that the application is offline and if it's than stop the propagation?
I can have click events on each part of the dom structure.
(Refactoring the DOM is not an option.)
EDIT:
<div>
<div>
<ul>
<li>
<div>
<span>
</span>
</div>
</li>
<li>
</li>
<ul>
</div>
I found event listeners on the spans and on the LI-s too.
Maybe you can solve this with an simpler approach if you're able to categorize which elements can't have interaction while offline.
For example, let's say that all controls that are disabled in offline mode have a class called .requires-connection attached to it, like:
<li id="save-stuff" class="requires-connection">
<i class="icon-save"></i><span>Save Changes</span>
</li>
If you add an .offline-mode class to your <body> when you detect that no connection to your server is available, you can globally disable the interaction in the relevant UI controls (and in it's children as well) with:
body.offline-mode .requires-connection {
pointer-events:none !important;
opacity:0.7 !important;
}
Alternative Solution
If the above won't work in your context, you might just need to be aware of how those events are fired. How they bubble up and, for handlers in the same element, that jQuery fires then in the order that they're registered.
After being aware of that, you can just create a custom event handling workflow by creating custom events that might do your checks to preventDefault and/or stopPropagation when needed.
If you don't have much control on the order that the event handlers are registered you can use some techniques from this post;
I think you'd be better not allowing the use of an input control, than allowing and then trying to control the event propagation.
If you asked for my suggestion, I would say disable buttons that are not applicable when user is offline and re-enable them when user is back online.
For example you may group certain controls that should work while online as follows:
<fieldset id="online-applicable-controls">
<button>a button [applicable when online]</button>
<button>another button [applicable when online]</button>
<!-- more buttons probably -->
</fieldset>
And the script to enable/disable the above group of buttons as applicable will be:
var onlineApplicableControls = document.getElementById("online-applicable-controls");
document.addEventListener("online", enableOnlineControls);
document.addEventListener("offline", disableOnlineControls);
function disableOnlineControls() {
onlineApplicableControls.disabled = true;
}
function enableOnlineControls() {
onlineApplicableControls.disabled = false;
}
Note, since the above script accesses a DOM element, you should execute it on DOMContentLoaded. Using JQuery, that translates to $(document).ready(function(){ /* place the script here */ });

Angular ui sref not working with touch events

i have a link with ui-sref attribute and also a jQuery touch event, but the problem is that when i click on this element the jQuery handler is running but the ui-sref not.
Jquery:
$('#fa-bar, #mobile-nav li').on('touchstart', function( e ) {
e.stopPropagation();
$('#mobile-nav').toggleClass('toggle-mobile-nav');
$('#mobile-nav').toggleClass('prevent-scroll');
});
Html:
<li ui-sref="state" ui-sref-active="nav-active"><a>Link</a></li>
See the docs and this example:
However, stopEvent also calls an event object method, event.stopPropagation, which keeps the event from bubbling any further up into the DOM. Note that the table itself has an onclick event handler that ought to display a message when the table is clicked. But the stopEvent method has stopped propagation, and so after the data in the table is updated, the event phase is effectively ended, and an alert box is displayed to confirm this.
This is pure javascript and also applies for AngularJS. Your call to e.stopPropagation() prevents ui-router from getting the event. This is sometimes handy if you want to add an URL to something (so you can still use open-in-new-tab feature of your browser), but want a different behavior on normal clicks.
Use latest or atleast 0.3.2 for ui-router
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.2/angular-ui-router.min.js"></script>

Passing Element Data to a Bootdtrap Modal

Having a frustrating time, made even worse that the examples I see everywhere are not working in this instance. My assumption is because I am not understanding what elements are being loaded in which order.
The question is common enough, I have a button that I want to pass data from into the modal it opens. Let's say I want to pass in the id. My first idea was something like this which is the typical answer on Stack Overflow:
HTML:
<button class="btn btn-primary btn-block" data-toggle="modal" data-target="#myModal" id="product-button">Product Name</button>
JavaScript:
$(function() {
$('#product-button').click(function() {
var productId = $(this).attr('name');
$(".modal-body #testContainer").val(productId);
});
});
This is seen here:
Passing data to a bootstrap modal
However, this appears not to work for me. The kicker for my scenario is that the buttons are generated dynamically and I am wondering if because I've wrapped everything in a helper function and it ties itself to the page before the dynamic buttons are created and therefore doesn't know they exist and to listen for a .click event (they are created through a search, the buttons are the results of the search)
Anybody have any ideas on how I can go about passing data to a modal with this limitation?
If the buttons are generated dynamically, you have to use event-delegation to make it work:
$(function() {
$(document).on('click','#product-button',function() {
var productId = $(this).attr('name');
$(".modal-body #testContainer").val(productId);
});
});
Event Delegation:
Event delegation refers to the process of using event propagation (bubbling) to handle events at a higher level in the DOM than the element on which the event originated. It allows us to attach a single event listener for elements that exist now or in the future.

Event Bubbling or Looping Callbacks?

I am having trouble with JQuery / javascript / Knockout.js
The events are looping incrementally every time they are called.
Like for example, a click event with alert.
If I click once, it will alert once.
BUT, if I click the second time, it will alert twice.
That goes on the third time and so on, It loops by the number of times it was called.
I am quite risking myself here because I cannot paste the codes unless I give you the whole program which is not possible because this is an incomplete company project.
So I am very sorry if I don't have any codes to provide. I just need ideas / answers / possible solutions.
What do you call this problems? Is it Event Bubbling?
So my main question is, is it possible to stop all the events after calling it once? I have no loop statements whatsoever, all I have is some functions and an .on('click'... events
I finally found the answer to my question.
Since the .on events are stacking every time it's clicked, and once you clicked it twice, the events will also fire twice, then I had to insert .off() before .on('click', functionName);
That makes it like this:
$('testBtn').off().on('click', functionName);
That should clear up all the event stacking.
One common situation when binding click events is to have a common handler being used in both parent and child elements.
Example:
<div id="parent" data-bind="click: doSomething">
<a data-bind="click: doSomething">Clickable</a>
</div>
When the child is clicked its handler, doSomething, will be triggered once, and then the parent click handler, that again calls doSomething, will be also triggered.
To prevent event propagation in scenarios like this you can set the extra clickBubble binding to false in the inner element.
Example:
<div id="parent" data-bind="click: doSomething">
<a data-bind="click: doSomething, clickBubble: false">Clickable</a>
</div>
More about all the details of the click binding here.

jQuery click event firing twice?

This is a fairly weird case, you can see the code here:
http://jsfiddle.net/zpZtH/2/
you should not wrap input elements by using a label element, try this:
<label for="average-data" class="section-view-time-checkbox">
<span class="custom checkbox checked"></span> Average
</label>
<input type="checkbox" id="average-data" style="display: none;">
http://jsfiddle.net/zpZtH/7/
http://jsfiddle.net/Cc55g/
You need to call event.preventDefault() within your click handler. This prevents the default click action from being executed once your custom function runs. The second alert is occurring because the form is being submitted.
This is a common Bug in Javascript. you can find many articles around internet specially on SO for event being fired twice. You can try something like this
$(document).on('click', '#task-list li', function(e)
{
alert('Hellow world');
e.stopPropagation();
return false;
});
And it's definitely Javascript problem because if you hit google and search for event fire twice you will see that Angular, Jquery and backbone etc all are somewhere firing events twice or even thrice. So, it's seems that it's javascript behind this. And off course if you search this with Mozilla Developers Network then you can see experts have also said so.

Categories