While loop condition changed in jQuery - javascript

The while loop condition I want to change is done by clicking on a button, while a second button continues the loop and adds to a counter. The problem is the code doesn't wait for jQuery to load and therefore creates an infinite loop. I wasn't able to use setInterval() because the code also includes counters for variables used elsewhere in my code.
var condition = true;
while(condition === true) {
$('#modal').modal();
$('#modalButton1').on('click', function() {
variableCounter++;
});
$('#modalButton2').on('click', function() {
condition = false;
});
}

You are assigning the click event handlers continuously in the while loop. Instead you should define the event handlers once in the document-ready section and then put the desired functionality (i.e. end the modal dialogue when button 2 was clicked) into the handler function for these click events.
$(function(){
$('#modalButton1').on('click', function() { variableCounter++; });
$('#modalButton2').on('click', function() { $('#modal').hide(); })
});
I don't know whether .hide() will achieve what you want. You should call the relevant function for shutting down your modal dialogue here.

Related

onClick function used on dynamic content not working properly

I hit a problem with the onclick function when i add divs with ids like "n_block"+(1-~). When I use the jquery zoom function on the objects to make them smaller or bigger onClick doesn't work anymore. I'm not really good at programming so the code might be kind of confusing.
Heres the code i use for the onClick of items:
$(document).on("click",function (e, ui){
//When the document gets clicked, check if one of the items was clicked.
if($(e.target).is($("#n_block" + cloneCount1)) || $(e.target).is($("#n_block" + cloneCount1+ " span"))){
//Set current item.
var item = $("#n_block" + cloneCount1);
//Set style to current item.
item.css("border-color", "Black");
item.css("border-width","2px");
item.css("background-color", "floralwhite");
jsPlumb.repaintEverything();
//Check if key Delete was pressed while item selected & delete that item with his children.
$('html').keydown(function(e){
if(item.css("border-width")=="2px"){
if(e.keyCode == 46) {
/* Prevents line bugging*/
jsPlumb.detachEveryConnection();
jsPlumb.deleteEveryEndpoint();
var razred = getClass(item, "b_"),
id = item.prop("id");
item.remove();
if(razred == "b_2"){
$(".ovoj."+id).remove();
}
else if (razred == "b_4"){
$(".ovojLoop."+id).remove();
$(".empty_block_c."+id).remove();
}
if ( $('.objects').find('div').length == 2) {
$(".objects").empty();
$(".objects").append('<div class="b_s" id="start_block">START</div><p id="start_text">Insert symbols here!</p><div class="b_s" id="end_block">STOP</div> ');
}else{
/* Connects objects together with line. ****/
povezi(cloneCount, tip_crte, ".objects");
}
}
jsPlumb.repaintEverything();
}
});
}
// If item is not clicked set this css to the current item.
else{
$("#n_block" + cloneCount1).css("border-width","1px");
jsPlumb.repaintEverything();
}
});
And heres the zoom code for zooming in when button is clicked:
var currentZoom = 1.0;
$(".zoomin").click(function (){
//Detaches the connections from item to item.
jsPlumb.detachEveryConnection();
jsPlumb.deleteEveryEndpoint();
//Prevents spamming of button, animates the objects
$(".project").stop().animate({ "zoom": currentZoom += .1}, "slow", function() {
if(!$(".objects").children().is($("p"))){
povezi(cloneCount, tip_crte, ".objects");
}
});
});
Use event delegation for binding events to dynamically added elements.
$(document).on('click', ".zoomin", function (){
//Your code.
});
When you use normal .click() to bind event to an element, then that even gets bound to only those elements which exist in the DOM at the moment of the execution of code. Using event delegation, you can tell jQuery that we need to add the handler to every '.zoomin' element which comes inside a particular element no matter when it is added.
The solution depends when exactly is the script which tries to bind the events are executed.
For Eg: Lets assume this script is in document ready function of jquery
$(document).ready(function(){
$(".zoomin").click(function (){
//your logic here
});
});
Here this script is executed when the page HTML is completed loading into the browser. Now when the script executes it tries to find a element with the class zoomin and if found it will add a event to that element and move on. If the element is not found the script just moves on. So we should actually take care of when the script is executed and is the intended element available at that particular instant of time. If the element is not yet available in the HTML (element might come in later dynamically using jquery) we have 2 options to bind event to the element.
1) Execute the script when the element is being added into the HTML: Lets say I have a event which brings up a pop up with some image. Now I want to zoomin and zoomout the image. Since the image in the popup is added dynamically and I have control of when its being added, I can do this.
$(document).ready(function(){
$('.ViewImage').on('click',function(){
// some code is executed which brings up the popup
// now we know that the image is added into html we can now run the script
$(".zoomin").click(function (){
//your logic here
});
});
});
2) We have no Clue/ Control when the element is added into HTML but still want to bind a event to it: This is scenario where we have no control on when the element is being added or not sure where it is being added from (might be from some external plugin used etc) or not having control at all on the element which is added. Thats when we use this syntax as suggested by #Rejith R Krishnan
$(document).on('click', ".zoomin", function (){
//Your code.
});
This will work on all the elements which are in the HTML at the time of execution of the script and on the elements which will be added in the future with the class name zoomin. So this script can be placed inside/ outside of jquery document ready event

Onload fires no matter where I place it

Right, I'm getting quite aggitated with this. I'm probably doing something wrong, but here's what I'm doing:
$(document).ready(function () {
$('#somebutton').click(function () {
openPage1();
});
$('#someotherbutton').click(function () {
openPage2();
});
});
var openPage1 = function () {
$('#iframe').attr('src', 'someurl');
$('#iframe').load(function () {
$('#button').click();
});
};
var openPage2 = function () {
$('#iframe').attr('src', 'anotherurl');
$('#iframe').load(function () {
$('#anotherbutton').click();
});
}
Whenever I click somebutton everything goes as expected. However when I click someotherbutton. The .load() from openPage1() is called first and I can't find a way to stop that. The .load() from openPage1() has a button with the same name, however on openPage2() I need to modify the contents before clicking the buttons.
I need to use .load() because I can't click the buttons before the document is ready.
Basically what I need is two seperate .load() instances on the same iframe, that don't fire off on each other.
Besides that, maybe my understanding of jQuery/JS is wrong, but shouldn't the .load() events only be listening after clicking the corresponding button?
Can someone help me out, this has been keeping me busy all afternoon.
Try using on, and once loaded, unbind
$("#iframe").on("load", function(){
$(this).off("load");
$('#button').click();
});
That way you remove the handler you put up before the second button is clicked?
By writing : $('#iframe').load(function (){ $('#button').click(); });, you are adding a listener on the load event, which will stay and be re-executed on each subsequent reload of the iframe.
Here is a jsfiddle to demonstrate this : click on the "reload" button, and see how many times the "loaded" message appears in your console.
in your case, if you click on #somebutton, then on #someotherbutton, after the second click, you will have two handlers bound on the load event, and both will be triggered.
If you click 5 times on #somebutton, you should end up calling 5 times $('#button').click().
If you want to execute it once, you can follow Fred's suggestion, or use jQuery .one() binder :
$('#iframe').one('load', function(){ $('#button').click() });
Here is the updated jsfiddle : 'loaded' should be displayed only once per click.
Maybe try and replace the lines in both functions like this:
$('#iframe').load(function() {
$('#anotherbutton').click();
};
$('#iframe').attr('src', 'anotherurl');
Otherwise it might be firing the event before the new event-handler has been set.
This isn't really an answer to your problem Now it is an answer, but I think utilizing functions as they were intended could be beneficial here, i.e.:
//Utilize a single function that takes arguments
var openPage = function (frame, src, eventEl) {
frame.attr('src', src); // If you pass frame as a jQuery object, you don't
frame.on("load", function(){ // need to do it again
$(this).off("load");
evEl.click(); //Same for your buttons
});
}
//Simplify other code
$(document).ready(function () {
$('#somebutton').click(function () {
openPage($("#iframe"),somehref,$("#buttonelement"));
});
$('#someotherbutton').click(function () {
openPage($("#iframe"),anotherhref,$("#someotherbuttonelement"));
});
});

Toggling click handlers in Javascript

I have an HTML button to which I attach an event, using jQuery's bind(), like so:
$('#mybutton').bind('click', myFirstHandlerFunction);
In myFirstHandlerFunction, I'd like this handler to replace itself with a new handler, mySecondHandlerFunction, like this:
function myFirstHandlerFunction(e) {
$(this).unbind('click', myFirstHandlerFunction).bind('click', mySecondHandlerFunction);
}
In the second click handler, mySecondHandlerFunction, I'd like to toggle the button back to its original state: unbind the mySecondHandlerFunction handler and reattach the original handler, myFirstHandlerFunction, like so:
function mySecondHandlerFunction(e) {
$(this).unbind('click', mySecondHandlerFunction).bind('click', myFirstHandlerFunction);
}
This works great, except for one small detail: because the click event has not yet propagated through each of the button's click handlers, the click event is passed on to the button's next click handler, which happens to be the handler that was just bound in the previous handler. The end result is mySecondHandlerFunction being executed immediately after myFirstHandlerFunction is executed.
This problem can be easily solved by calling e.stopPropagation() in each handler, but this has the negative side-effect of cancelling any other click handlers that may have been attached independently.
Is there a way to safely and and consistently toggle between two click handlers, without having to stop the propagation of the click event?
Update: Since this form of toggle() was removed in jQuery 1.9, the solution below does not work anymore. See this question for
alternatives.
It looks like toggle() would solve your problem:
$("#mybutton").toggle(myFirstHandlerFunction, mySecondHandlerFunction);
The code above will register myFirstHandlerFunction and mySecondHandlerFunction to be called on alternate clicks.
Just use a boolean to toggle the functionality of the handler, there's no need to juggle which handler is listening:
$('#mybutton').bind('click', myHandlerFunction);
var first = true;
function myHandlerFunction(e) {
if(first){
// Code from the first handler here;
}else{
// Code from the second handler here;
}
first = !first; // Invert `first`
}
This solution is a hack, but it is short and sweet for your rough work:
$('#myButton').click(function() {
(this.firstClk = !this.firstClk) ? firstHandler(): secondHandler();
});
It's a hack because it's putting a new property directly onto this which is the click-target HTML DOM element, and that's maybe not best practice. However, it thus avoids creates any new globals, and it can be used unchanged on different buttons simultaneously.
Note that the first part of the ternary operation uses = and not == or ===, i.e. it's an assignment, not a comparison. Note also that the first time the button is clicked, this.firstClk is undefined but is immediately negated, making the first part of the ternary operation evaluate to true the first time.
Here's a working version:
$('#a > button').click(function() {(this.firstClk = !this.firstClk) ? a1(): a2();});
$('#b > button').click(function() {(this.firstClk = !this.firstClk) ? b1(): b2();});
function a1() {$('#a > p').text('one');}
function a2() {$('#a > p').text('two');}
function b1() {$('#b > p').text('ONE');}
function b2() {$('#b > p').text('TWO');}
div {display: inline-block;width: 10em;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="a"><p>not yet clicked</p><button>click</button></div>
<div id="b"><p>NOT YET CLICKED</p><button>CLICK</button></div>
I was looking at this today, and realized there was still not a way to do this without a global variable listed. I came up with the following to add locations to an ESRI basemap, but it would work generally too:
function addLocationClickHandler() {
var addLocationClick = overviewMap.on('click', function (event) {
addLocationClick.remove();
})
$('#locationAddButton').one('click', function (cancelEvent) {
addLocationClick.remove();
$('#locationAddButton').on('click', addLocationClickHandler)
});
}
$('#locationAddButton').on('click', addLocationClickHandler)
This should allow you to put something else in the section where you overwrite the click handler and not necessitate a global variable.
This would help add data-click-state attribute on your button
$(document).ready(function() {
$('#mybutton').on('click', function() {
if ($(this).attr('data-click-state') == 1) {
$(this).attr('data-click-state', 0)
myFirstHandlerFunction();
} else {
$(this).attr('data-click-state', 1)
mySecondHandlerFunction();
}
});
});
Like this:
$(this).bind('click', myMasterHandler);
handler = 0;
function myMasterHandler(e) {
if(handler == 0) {
myFirstHandler(e);
handler = 1;
} else {
mySecondHandler(e);
handler = 0;
}
}

jQuery: Get reference to click event and trigger it later?

I want to wrap an existing click event in some extra code.
Basically I have a multi part form in an accordion and I want to trigger validation on the accordion header click. The accordion code is used elsewhere and I don't want to change it.
Here's what I've tried:
//Take the click events off the accordion elements and wrap them to trigger validation
$('.accordion h1').each(function (index, value) {
var currentAccordion = $(value);
//Get reference to original click
var originalClick = currentAccordion.click;
//unbind original click
currentAccordion.unbind('click');
//bind new event
currentAccordion.click(function () {
//Trigger validation
if ($('#aspnetForm').valid()) {
current = parseInt($(this).next().find('.calculate-step').attr('data-step'));
//Call original click.
originalClick();
}
});
});
jQuery throws an error because it's trying to do this.trigger inside the originalClick function and I don't think this is what jQuery expects it to be.
EDIT: Updated code. This works but it is a bit ugly!
//Take the click events off the accordion elements and wrap them to trigger validation
$('.accordion h1').each(function (index, value) {
var currentAccordion = $(value);
var originalClick = currentAccordion.data("events")['click'][0].handler;
currentAccordion.unbind('click');
currentAccordion.click(function (e) {
if ($('#aspnetForm').valid()) {
current = parseInt($(this).next().find('.calculate-step').attr('data-step'));
$.proxy(originalClick, currentAccordion)(e);
}
});
});
I think this:
var originalClick = currentAccordion.click;
Isn't actually doing what you think it is - you're capturing a reference to the jQuery click function, rather than event handler you added, so when you call originalClick() it's equivalent to: $(value).click()
I finally came up with something reliable:
$(".remove").each(function(){
// get all our click events and store them
var x = $._data($(this)[0], "events");
var y = {}
for(i in x.click)
{
if(x.click[i].handler)
{
y[i] = x.click[i].handler;
}
}
// stop our click event from running
$(this).off("click")
// re-add our click event with a confirmation
$(this).click(function(){
if(confirm("Are you sure?"))
{
// if they click yes, run click events!
for(i in y)
{
y[i]()
}
return true;
}
// if they click cancel, return false
return false;
})
})
This may seem a bit weird (why do we store the click events in the variable "y"?)
Originally I tried to run the handlers in x.click, but they seem to be destroyed when we call .off("click"). Creating a copy of the handlers in a separate variable "y" worked. Sorry I don't have an in depth explanation, but I believe the .off("click") method removes the click event from our document, along with the handlers.
http://www.frankforte.ca/blog/32/unbind-a-click-event-store-it-and-re-add-the-event-later-with-jquery/
I'm not a jQuery user, but in Javascript, you can set the context of the this keyword.
In jQuery, you use the $.proxy() method to do this.
$.proxy(originalClick, value);
originalClick();
Personally, I'd look at creating callback hooks in your Accordion, or making use of existing callbacks (if they exist) that trigger when opening or closing an accordion pane.
Hope that helps :)
currentAccordion.click is a jQuery function, not the actual event.
Starting with a brute-force approach, what you'd need to do is:
Save references to all the currently bound handlers
Unbind them
Add your own handler, and fire the saved ones when needed
Make sure new handlers bound to click are catched too
This looks like a job for an event filter plugin, but I couldn't find one. If the last point is not required in your application, then it's a bit simpler.
Edit: After some research, the bindIf function shown here looks to be what you'd need (or at least give a general direction)

Queuing and stop propagating a click event to inside a div in Javascript

I'm trying to implement a "wait for 3 seconds to do this operation" <div>.
So, I have a <div> that has a bunch of elements in it that I want to be unclickable for say 3 seconds (a timer, or some other event), but somehow capture the events in a queue, and then fire them after the period (or some event of my choice) has elapsed/performed?
I'm thinking this is a problem kind of like putting up a modal dialog, and then not having anything beneath it clickable. Am I right in thinking this?
One possibility is to have the click handler for your DIV respond to clicks on its child elements as the event bubbles up. That handler would perform the queuing until the delay elapsed. Here's a rough example (using jQuery event handling for convenience):
(function() {
var isReady = false, queue = [];
setTimeout(function() {
isReady = true;
processQueue()
}, 3000);
$("#mainDiv").click(function(ev) {
if (isReady) {
//code to handle the click based on which child was clicked (ev.srcElement)
} else {
queue.push(ev.srcElement);
}
});
function processQueue() {
var i, elem;
for (i = 0; elem = queue[i]; i++) {
$(elem).click(); //re-trigger the click event
}
queue.length = 0;
}
})();
Give the div an onclick function, which starts off for the first 3 seconds as just holding an array of calls with their events...then after your 3000 millisecond timer is done, run a function that changes the div's onclick, allows things to be edited, and runs the array of events.
Another thing that Ive found to be helpful is the function.
setTimeout("alert('hello')",1250);
So something along the lines of surrounding all of the elements onclick method with a second method that will store that call for as long as you need.
<div onclick=registerClick("normallyDoThis()")></div>
Then you can setup a timer at the beggining of the time to change the Div and execute all the commands. Possibly with the eval command?
setTimeout("changeTheDiv()", 3000);
function changeTheDiv()
{
/*eval() all the items in a list of onclicks youve been storing up */
/*Then go through and parse out the register() from all the onclick methods*/
}
I hope this helps

Categories

Resources