I have a script which is obscured (ie cannot read the div elements from script). Upon rendering in inspect DOM element I can locate what the div I want to assign a function to. However I cannot do this. Do I need the div id within the script (ie obscured div id)?
I want to assign click on function and plan do it as follows:
<script>
$(document).ready(function () {
$('.contentoverlay').on('mouseover', function() {
click();
});
});
</script>
The script in itself is very long so I won't paste it here.
Overall I want to know:
Do I need to locate the obscure script's div is and assign my click function to it
Is the function above correct
If there are multiple overlays do I have to assign the function above to each one (the overlays in themselves are mouse pointer none, so they do pass down clicks, but would the function above get passed down or even blocked if I don't assign it to all the overlays)?
example: http://output.jsbin.com/joxetuc
First, i want explain my comment first, then i will answer your 3 questions in the end
A) honestly i have bad english here, i dont know what "obscured" means (even i google this), but i think that's means new DOM that newly created (dynamic created element) by javascript. like this:
started DOM <table></table>
New DOM <tr><td>texttt</td></tr>
the result <table><tr><td>texttt</td></tr></table>
if this not correct, my whole answer below will be wrong.
B) So, in jsbin example, i only give you div#container. And then create new DOM inside div#container when you click created button.
C) i create 1 function to handle if new DOM is clicked, which will write $(element).text() to div.log
//function to execute if element clicked
$('.container').on('click', '#newid', function(i,e){
var txt = $(this).text();
$('.log').append(txt+' ');
});
D) i handling event mouseover too with same function in click function. Because i'm lazy, i only write $(this).click(); which $(this) is refer to div#newid
//if mouseover, perform click
$('.container').on('mouseover', '#newid', function(i,e){
$(this).click();
});
so, in that jsbin i show you how to handle mouseover new DOM to execute click() function.
Now, Your Question
1) Do I need to locate the obscure script's div is and assign my click function to it?
You dont need it, as long as you know how to locate that element.
2) Is the function above correct?
that's not correct function. the correct 1 is:
parentElemenentOfNewDOM.on('mouseover', newDOMElement, function() {
$(this).click(); //this will perform your default click function that you give before
});
3) If there are multiple overlays do I have to assign the function above to each one (the overlays in themselves are mouse pointer none, so they do pass down clicks, but would the function above get passed down or even blocked if I don't assign it to all the overlays)?
you dont need to assign same function to handle multiple element (overlays). What you need is the correct script to handle all of your new multiple element. And my script will handle all of the new element.
if you want to know the different, see this DEMO http://output.jsbin.com/vukudu
Related
I've the following html structure
<body data-page="first">
<div class="start">Test</div>
</body>
and the following js
$('body[data-page="first"] .start').on('click',function (){
body.attr('data-page','second');
});
$('body[data-page="second"] .start').on('click',function (){
console.log('Test');
});
I would expect, that after the second click on .start, the console would show "Test", but it doesn't...
Can you tell me what I'm doing wrong?
Thanks in advance!
While you have your answer, I don't think the essential point has been made in any of the answers so far, and that is that the binding of an event handler must happen after the target element exists.
When you try to bind an event handler to a particular element in the DOM, the element must exist at the time. If it does not exist, the handler has nothing to bind to, and so the binding fails. If you later create the element, it's too late, unless you re-run the binding statement.
It will soon become second nature to call appropriate event handler binding statements after you create a new element (by modifying the HTML using javascript) that needs a handler.
For instance, in my current project I regularly make AJAX calls to a server to replace blocks of HTML as things happen on the page. Even if some of the new elements are exactly the same as the ones being replaced, they will not inherit any bindings from the replaced elements. Whenever I update the HTML I call a function that contains necessary statements to bind my event handlers to the new copy of the active elements.
Your code would work if you made the following change:
$('body[data-page="first"] .start').on('click',function ()
{
body.attr('data-page','second');
$('body[data-page="second"] .start').on('click',function (){
console.log('Test');
});
})
A couple of other (off-topic, but related) points:
It's possible to bind a handler to an element multiple times. The trick to avoiding this is to include the .off() method in the chain before binding (noting though that .off("click") will unbind all click handlers bound to that element, not just yours) e.g.
$("#mybutton").off("click").click(function(){myHandler()});
"the arrow function doesn’t have its own 'this' value" () so don't use arrow functions in event handlers if you plan to reference any of the element's properties via 'this'. e.g.
$("#mybutton").off("click").click(() => {console.log(${this.id})}); // >> "undefined"
The issue is that the page is rendered with the data-page set to first, and when you click again on it, that part of javascript still see "first", since is not rerendered, so you need a dynamic function, the read all the intereaction with that button, and than check wich value that attribute has. Like this you can make infinite cases, and still go on.
$('body .start').on('click',function (){
const attr = $('body').attr('data-page');
if(attr === 'first') {
$('body').attr('data-page','second');
} else {
console.log('second');
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body data-page="first">
<div class="start">Test</div>
</body>
And if you don't like the fact that is targetting all the "body" wich is weird, becouse you should have only 1 body, you can use an ID to target the right one
PS: is never a good idea to duplicate your function, if you can set everything in a dynamic function, that reads everything, is easier to debug in the feature, and is lighter and more clean to work on
$('body[data-page="first"] .start').click(function (){
var body = $('body[data-page="first"] .start');
body.attr('data-page','second');
});
This method can help :
var timesClicked = 0;
$('.start').on('click',function (){
timesClicked++;
if (timesClicked>1) {
console.log('Test');
}
});
Forgive me if I word the title wrong, I'm speculating on what my problem might be as I'm not a javascript coding expert. I have a series of divs that are generated by a php loop with unique ids created by adding the unique id contained in an auto increment column in the mysql db table that contains all the info for the row.
When the user clicks on the div this function fires off:
onclick=\"showModal('".$rowInfo['ID']."_row-id')\"
javascript code:
function showModal(ID) { /* code that shows hidden modal window */ }
This works fine, however now I need to start adding javascript buttons (in my case img tags with onclick functions) to the div with the showModal onclick function.
I added this code to the showModal(ID) function:
var downArrow = document.getElementById(ID+'_down-arrow'); // Down arrow is the button users click to show addition buttons/divs
downArrow.addEventListener('click',arrowCheck,false); // checks to see if down arrow was clicked, if so arrowCheck function runs and stops propagation.
arrowCheck function:
function arrowCheck(e) { e.stopPropagation(); }
This bit of code also works but ONLY AFTER the user has clicked the div once, the first time the div is clicked both functions fire off (ie the modal window and the extra buttons that the down arrow shows) but after the first click the addEventListener does it's job and clicking the down arrow only shows extra buttons, elsewhere brings up the modal, etc.
I'm guessing I need to create the event listener before the user clicks the div and fires off showModal(), is this correct? I'm not sure how to create a unique event listener for each down arrow image before the div is clicked, or even if I need to. Thanks for any help!
Since the event listener is being created within the modal function, you need to call the modal function before the other listener is even added.
To get your desired results, you could either directly add the onclick method to the image that the PHP code creates, or you could detect when the page is finished loading and add those listeners then. To do the latter, though, you'd need to either query for something the images all have in common, like a classname, or you'd have to keep track of the IDs used and manually add a listener for each. e.g.:
<body onload="initEventhandling()">
initEventHandling = function () {
var buttons = document.getElementsByClassName("image-button");
for (button in buttons) {
button.addEventListener('click', arrowCheck, false);
}
}
David Millar's code pointed me in the right direction. I tried to put the initEventHandling function in the onload of the body tag but I couldn't get it to work. It executed the function but I could not get the eventListeners to work. I solved it by creating an event listener using the onload for each img tag, so my code ended up like this:
<img id=\"".$appChart['ID']."_down-arrow\" onload=\"addEvent('".$appChart['ID']."')\" onclick=\"clickReviewArrow('".$appChart['ID']."')\" src='...' />
javascript:
function addEvent(ID) { var downArrow = document.getElementById(ID+'_down-arrow');
downArrow.addEventListener('click',arrowCheck,false); }
function arrowCheck(e) { e.stopPropagation(); }
David Millar may have been suggesting this, if so I'll mark his answer.
I have a function which dynamically creates an element and attaches a click event to this new element.
In the current state of my app, this function is called 5 times: for the 4 first created elements, all works fine, but the 5th one has no event attached!
I insist: I'm not merely saying that click doesn't work: Using $._data(myElemn,'events') in the console, I get Object { click=[1]} returned for the 4 working elements, but "undefined" for the last one.
Here is the code.
But I don't think is where the problem lies: since it works for other elements, It seems that the difference should come from the particular context of the 5th element.
So my question is rather: can we imagine which particular conditions may cause and event not to be attached (obviously,without any error message).
var createDDT= function(element) { /*
---------
Creates a drop-down toggle button embedded into element.
*/
$(element).css({position:'relative'}) // (relative: since DDT pos is absolute)
.append(
$('<span \/>').addClass(DDT)
.css({display:'none',})
.append($('<span \/>'))
// when click, toggle submenu:
.click(function(event) {
// hide or show current %Submenu:
var submenu=$(event.target).closest('li').find(jqSUBMENU);
submenu.toggleClass(OPEN);
// hide any other %Open %Submenu:
$(jqOPEN).not(submenu).removeClass(OPEN);
setTimeout(liveWidthDisplay,_params.cssTimeout); // adjust LWD's position
return false; // avoid following link, if embedded in <a>
})
);
}
[EDIT] As I previously said, the issue resides probably outside of the function. To emphasize it, in my app I tried replacing the code by the following:
var createDDT= function(element) { /*
---------
Creates a drop-down toggle button embedded into element.
*/
$(element).css({position:'relative'}) // (relative: since DDT pos is absolute)
.append(
$('<span \/>').addClass(DDT)
.css({display:'none',})
.append($('<span \/>'))
// when click, toggle submenu:
.click(function(event) {
alert(event.target.id);
})
);
}
Then the result is unchanged: $._data(myElem,'events') returns "undefined".
Unfortunately, I can't realistically add a significant context into jsFiddle, since it is a huge app.
can we imagine which particular conditions may cause and event not to
be attached
Yes, either you aren't actually passing your 5th element to the createDDT function - or else you have some other code that is destroying the event handler - possibly innerHTML or some such.
In any case a better way to handle this, that will ensure you get the event is to attach a single event handler higher up in the DOM. For example on the body (although any parent element that exists in the DOM will do).
// presuming DDT is a classname such as ".foo"
$('body').on('click', DDT, function(event) {
alert(event.target.id);
});
This way you have a single event that you don't need to create for each element regardless of it is dynamically added to the DOM or not.
I have multiple div's on my page, that can be added to the page dynamically, and can also be removed.
On page load, the dynamically created div's are loaded from localStorage with uniqiue id's and a common class depending on the div, and I call a function along with that, content().
The function content() looks like this:
function content(){
alert("test");
$(".two button").click(function(){
var id = $(this).parent().attr("id");
alert(id);
});
}
Pretty simple, all it does is alert "test" when the function is called, and if you click .two <button>, it will alert .two <textarea> .val().
This works fine once the div's have been loaded, but I run into the problem when I clone the div's
When I clone the div's, it gives them a unique id and a common class like above. At the end of cloneDiv(), I call content(), so that clicking on the elements inside will produce the same results as above.
The problem is, the function will get called as many times as there are div's on the screen, but also means that clicking on the <button> in div .two will alert .two <textarea> .val() three times.
TLDR; Clicking on the button in .two get's called as many times as there are div's on the screen, as the function is called once the dynamic div is created, but should only be called once.
There's a lot of code to do all this, but I think I explained what happens pretty clearly. I will however whip up a demo if that would help more.
You want to use the .on function:
$('body').on('click', '.two button', function(){
var id = $(this).parent().attr("id");
alert(id);
});
I would change the 'body' part of that to the real container of these buttons. So say the buttons are always inside a content div with id my-div, you'd do:
$('#my-div').on('click', '.two button', function(){
var id = $(this).parent().attr("id");
alert(id);
});
You also only need this code to run once, so no need to put it in a function that gets called multiple times. Just put it in your $(document).ready(....).
A fiddle: http://jsfiddle.net/gromer/dxbqz/
This is what "event delegation" is for. You set up a handler on the document and it will handle events from its descendants, even if they are created after the handler is attached:
$(document).on("click", ".two button", function(){
// put a click hander on the document to process clicks
// from buttons that are descendants of elements with class=two
The problem is this: "At the end of cloneDiv(), I call content(), so that clicking on the elements inside will produce the same results as above." What happens is that you are compounding the events on to the existing elements so that is why you get so many callbacks. You should instead use the .on function, and use it only once. If you call .on multiple times it will produce the same results because multiple events will be registered.
$(".two button").on("click",function(){
var id = $(this).parent().attr("id");
alert(id);
});
Do this once, every button matching (".two button") will respond to it, even if appended later.
Another approach would be to pass in the element to the content() call and then mark it up from there if you are always calling this function when creating the elements anyway.
function content(element){
$(element).click(function(){
var id = $(this).parent().attr("id");
alert(id);
});
}
As a side note, using alerts to debug can be problematic as they interrupt program execution. I would highly recommend using console.log(id) instead and then looking in the console for your testing variables. console.trace() is also a good one to keep in mind if you are using a third party script and need to see what went wrong where.
I've recently started using Twitter's new Bootstrap 2.0.1 and its Javascript popovers.
I want to write a script so that no more than one popover can be displayed at one time. In other words, when a new popover is generated for whatever reason (e.g. the client clicks or hovers over a new element with a popover), all of the PREVIOUSLY displayed popovers are hidden first.
Here's the function that initially sets up all of the popovers for my webpage:
$(function (){
$("[rel=popover]").popover({placement:'left', trigger:'click', html:true});
});
What I need, I think, is to write a function that hides all popovers. I would call that function BEFORE displaying every popover, to ensure that only one popover is displayed at a time. The function might look like this, I imagine:
function hidePopovers(){
$(function (){
$("[rel=popover]").popover('hide');
});
}
But my problem is figuring out WHERE (or HOW) to call this hidePopovers function. I want to call it when a popover is triggered, but before the popover is displayed. Help?
Oh, and just to clear up any confusion, the new Bootstrap now has a 'click' trigger that allows you to display popovers upon clicking. More details about it can be found here.
Thank you so much!
Considering what you have presented as the problem to solve, I think that it would be much more efficient to simply store a reference to the last popover open, rather than execute the hide() method on every single popover element you might select on the page. As far as I understand it, you only want a single popover to be open in the first place, so there should only ever be at most a single one to hide.
The following would do the trick:
var $visiblePopover;
$('body').on('click', '[rel="popover"]', function() {
var $this = $(this);
// check if the one clicked is now shown
if ($this.data('popover').tip().hasClass('in')) {
// if another was showing, hide it
$visiblePopover && $visiblePopover.popover('hide');
// then store reference to current popover
$visiblePopover = $this;
} else { // if it was hidden, then nothing must be showing
$visiblePopover = '';
}
});
JSFiddle
Technically, you could potentially change the selector where the delegate handler is attached (in the example code 'body' is used) to a more specific element of the page, allowing you to attach the only-one-visible-at-a-time behavior to only a subset of the popovers on the page.
For instance, if you had a specific form where the popovers would appear too close together, but other popups on the page wouldn't collide/overlap, you could select just the form (e.g., '#some_form_id'), and only the popups in the form would have the behavior.
JSFiddle
Note: In this latter example, I also optimized the code a bit by changing the stored reference to only use the actual Popover object, rather than the jQuery-ized DOM element it is attached to.
Haven't tested this but something like this might work:
Set the trigger to manual.
Listen for click events and on click, call hidePopovers(), and then show the clicked popover.
$(function (){
function hidePopovers(){
$(function (){
$("[rel=popover]").popover('hide');
});
}
$("[rel=popover]").popover({placement:'left', trigger:'manual', html:true});
$("[rel=popover]").click(function() { hidePopovers(); $(this).popover('show');});
});