Knockout click binding fires after second click - javascript

I have a knockout binding that scrolls to a part if the page on click with this function
scrollTo() {
$("a.scroll").click(function(event) {
event.preventDefault();
$('body').animate({
scrollTop: $(this.hash).offset().top
}, 500);
});
}
The html where i call the function
<a class="scroll icon-arrow-down" href="#part" data-bind="localizedText: { id: '4-anchor-1', html: true }, tap: controller.scrollTo.bind(controller)"></a>
The problem is that it fires after the second click and not the first. Also this happen when coming on the page when you click a button it does not fire click it again it fires and then it function normally on other button to.

The issue is because on the first click you call scrollTo() which binds the event. Then on the next and each successive click you add another click() handler as well as execute all previous click event handlers. You just need to remove the scrollTo() function and add the event on load:
<a class="scroll icon-arrow-down" href="#part" data-bind="localizedText: { id: '4-anchor-1', html: true }"></a>
$("a.scroll").click(function(event) {
event.preventDefault();
$('body').animate({
scrollTop: $(this.hash).offset().top
}, 500);
});
Alternatively, if the a element is appended to the DOM dynamically you would need to use a delegated event handler:
$(document).on('click', "a.scroll", function(event) {
event.preventDefault();
$('body').animate({
scrollTop: $(this.hash).offset().top
}, 500);
});

Since you're using Knockout, don't use the jQuery event bindings. Assuming you have defined a tap binding handler (which is to say, to call an event handler like click does), your HTML markup is fine. Just turn your scrollTo method into an event handler.
scrollTo(event) {
event.preventDefault();
$('body').animate({
scrollTop: $(this.hash).offset().top
}, 500);
}

Related

JavaScript getting stuck in a loop?

I am trying to perform a simple animation that I would like to happen after a successful return of an AJAX call.
$('#result').click(function(){
$(document).ajaxSuccess(function(){
$('html, body').on("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove", function(){
$('html, body').stop();
});
$('html, body').animate({
scrollTop: $('#result').position().top
}, 500, function(){
$('html, body').off("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove");
});
});
});
The problem is that sometimes, not always, the animation does not seem to want to exit in that it causes jerky movements and a constant return to the top of the div if the user attempts to scroll away. When I remove the ajaxSuccess requirement, the problem does not occur. Any ideas?
There is no need to stop mousewheel, scroll etc. movement by using stop() function.
animate function won't be disturbed until it has reached the document top.
This would do:
$('#result').click(function(){
$(document).ajaxSuccess(function(){
$('html, body').animate({
scrollTop: $('#result').position().top
}, 500);
});
});
You're attaching a new ajaxSuccess callback every time the user clicks on #result.
This means that if the user clicked on #result N times, then N different functions are attached to be executed whenever an ajax request completes successfully. And each function will try to animate $('html, body')
Solution: Move your code out of $('#result').click function or unbind previous handlers before binding a new one.
And here is the simplified example of what is happening. Try to click two buttons one after another:
$("#one").click(() => {
console.log("Clicked First")
$("#two").click(() => console.log("Clicked Second"));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id=one>First</button>
<button id=two>Second</button>

jQUery --> After window resize scroll to section does not work as expected

After window resize my scroll function does not work as I described below (description shows how I want it to work):
I do window resize.
After window resize when I click the given menu item the window should scroll to...
corresponding to that menu item section offset().top-45 for max-width:480px (first breakpoint)
corresponding to that menu item section offset().top-90px for min-width 481px (second breakpoint)
https://jsfiddle.net/d1abevro/1/
It only works as expected for a given breakpoint without window resize (onload).
function displaymenu() {
if ($(window).width() <= 480) {
$('.c-main-menu ul').css({display: 'none'});
$(document).on("click", "a.c-main-menu__link", function(event){
event.preventDefault();
$('html,body').animate({
scrollTop: $($.attr(this, 'href')).offset().top-56
}, 800);
$('.c-main-menu ul').slideToggle();
});
$('.c-nav .menu-trigger').click(function() {
$('.c-nav .c-main-menu ul').slideToggle();
});
} else {
$('.c-main-menu ul').css({display: 'block'});
$(document).on("click", "a.c-main-menu__link", function(event){
event.preventDefault();
$('html,body').animate({
scrollTop: $($.attr(this, 'href')).offset().top-90
}, 800);
});
}
}
That is caused because after each resize you append a new event. You should kill the old event an create a new one in order to prevent conflict with the old event. To get this approach the best way is to adding a namespace for your event, for example:
$(document).on("click.menuLinkEvent",".my_links", function(){});
And before adding the new event kill any old event it using unbind method and passing the event with the namespace:
$(document).unbind("click.menuLinkEvent");
Also looks like you understand correctly that the event will be appended each time after resize so you added a setTimeout function, but forgot to add a time, so however it will fire inmediately.
I made some changes to your fiddler. Let me know if it works as you expect

How to Scroll to contact us when click "Contact Us" button on modal?

I was struggling to find a way to make it so when i click "Contact us!" on my modal, it would close the modal then scroll to the Contact Us part.The method i found now also scrolls when i press close, is there a way to fix this. This is the function used!
jQuery(function($) {
$('#leadworkModal, #tilingModal').on('hidden.bs.modal', function (e) {
$('html, body').stop().animate({
scrollTop: $("#contact-us").offset().top
}, 2000);
});
});
You have to attach an event to the button:
jQuery(function($) {
$(document).on('click', '#contactButton', function (e) {
if($('#leadworkModal').hasClass('in')) $('#leadworkModal').modal('hide');
if($('#tilingModal').hasClass('in')) $('#tilingModal').modal('hide');
$('html, body').stop().animate({
scrollTop: $("#contact-us").offset().top
}, 2000);
});
});
If you attach event inside button onclick event (as suggested in comments). It will work only once. Because event still is attached for further.
So I would just check if modal is shown just hide it.

Why do I need to click twice to fire up this jQuery event?

I have this:
$(".slideDownArrow").click(function(){
currentBlockIndex++;
$('.secondLevel li').eq(currentBlockIndex).trigger('click');
});
and when I click on the slideDownArrow it works for me and many other people, but not for everyone - my client has to click twice to trigger the secondLevel li click event. What could be the cause of it and how could I fix this?
The secondLevel li click function:
$('.secondLevel li, .exteriorBox li').bind('click', function(){
var el = $(this),
elIndex = el.index();
$('html, body').animate({
scrollTop: hArray[elIndex]
}, 1000);
});
Go straight to the HtmlElement click method instead:
$('.secondLevel li')[currentBlockIndex].click();
Rather than use get(), [] returns the HTML element. click is the native click event generator.
As the event is in response to a user click, you can ignore any comments about security reason. I have tried this on all browsers and no problems.

jQuery click event triggered multiple times off one click

I am having trouble with multiple clicks being registered in jQuery when only one element has been clicked. I have read some other threads on Stack Overflow to try and work it out but I reckon it is the code I have written. The HTML code is not valid, but that is caused by some HTML 5 and the use of YouTube embed code. Nothing that affects the click.
The jQuery, triggered on document.ready
function setupHorzNav(portalWidth) {
$('.next, .prev').each(function() {
$(this).click(function(e) {
var target = $(this).attr('href');
initiateScroll(target);
console.log("click!");
e.stopPropagation();
e.preventDefault();
return false;
});
});
function initiateScroll(target) {
var position = $(target).offset();
$('html, body').animate({
scrollLeft: position.left
}, 500);
}
}
Example HTML
<nav class="prev-next">
Prev
Next
</nav>
In Firefox one click can log a "Click!" 16 times! Chrome only sees one, but both browsers have shown problems with the above code.
Have I written the code wrongly or is there a bug?
-- Some extra info ------------------------------------------
setupHorzNav is called by another function in my code. I have tested this and have confirmed it is only called once on initial load.
if ( portalWidth >= 1248 ) {
wrapperWidth = newWidth * 4;
setupHorzNav(newWidth);
}
else
{
wrapperWidth = '100%';
}
There are mutiple instances of nav 'prev-next'. All target different anchors. All are within the same html page.
<nav class="prev-next">
Prev
</nav>
Try unbinding the click event like this
$(this).unbind('click').click(function (e) {
});
You don't need .each() for binding event handlers. Try this instead:
$('.next, .prev').click(function(e){
var target = $(this).attr('href');
initiateScroll(target);
console.log("click!");
e.stopPropagation();
e.preventDefault();
return false;
});
EDIT:
I think it is the way you are attaching the event handler from within the setupHorzNav function that is causing it. Change it to attach it only once from say, $(document).ready() or something.
I have managed to get the situation of multiple event handlers by attaching the event handlers from a function that gets called from event handler. The effect is that the number of click event handlers keeps increasing geometrically with each click.
This is the code: (and the jsfiddle demo)
function setupNav() {
$('.next, .prev').each(function () {
$(this).click(function (e) {
setupNav();
var target = $(this).attr('href');
console.log("click!");
e.stopPropagation();
e.preventDefault();
return false;
});
});
}
setupNav();
See how calling the setupNav() function from the click event handler adds multiple eventhandlers (and the click log message) on successive clicks
Since it is not clear from your question whether you are calling the binding function multiple times, a quick and dirty fix would be:
$('.next, .prev').unbind('click').click(function() {
...
});
What you are doing here is unbinding any previously bound event handlers for click and binding afresh.
Are there no other click bindings elsewhere?
Are you loading the page with ajax?
You could also try this:
$('.next, .prev').click(function (e) {
var target = $(this).attr('href');
initiateScroll(target);
console.log("click!");
e.stopPropagation();
e.preventDefault();
return false;
});

Categories

Resources