jQuery - Combining multiple element selectors with :not - how - javascript

I am having a devil of a time getting two selectors to work together as well as do when I declared seperate.
My issue:
I want to close a menu when I move to any input OR anchor tag that is NOT contained with a certain element. When I explicitly code for both input and anchor, I get the behavior I need - BUT when I try to condense my code and combine them, it behaves weirdly and does not work as intended.
So, basically when a user focus's in an input field or anchor that is NOT a child of my selector I want to close a menu. When I use two sperate handlers, it works. I want to combine them.
I am trying to shorten this....
jQuery('#hdr input:not(#opt *)')
.focusin(function(event){
setTimeout(function(){
jQuery("#opt").hide()
},100);
});
jQuery('#hdr a:not(#opt *)')
.focusin(function(event){
setTimeout(function(){
jQuery("#opt").hide();
},100);
});
I've tried all of this into one line, to no avail:
jQuery('#hdr a input:not(#opt *)')
jQuery('#hdr a, #hdr input:not(#opt *)') <-- I expect this to work, but doesn't.
jQuery('#hdr a,input:not(#opt *)')
jQuery('#hdr *:not(#opt *)')
It seems to only work when I do a single arg like: #hdr a , or #hdr input BUT when I try to combine them, no luck. I've searched high and low but no luck.

You can use the not method:
$('#hdr').find('a,input').not('#opt *')
Sometimes it's just better and more readable to use the methods instead of a huge selector string.

All the elements are child of #opt and not selector ensure that #opt which is parent and all the elements or nodes in it are prevented from event handler. Like this in Fiddle:
Working Fiddle
Also The Method of #elclanrs works.
$("#hdr a:not(#opt), #hdr input:not(#opt)")

Related

Dynamic field generation with CSS Togglebuttons and .on() binders

Question:
I am trying to build a dynamic form using jQuery. There are a few standard html form inputs in a row in addition to a CSS stylized "hidden checkbox" toggle button. (Example)
The first row is statically coded, and there is a button to add more rows to the form for batch submissions. JQuery applied to the .on(click) event works perfectly with the static content, but newly appended form rows ignore the binding. Even jsfiddle's dynamic display doesn't appear to function, though it is possible my fiddle example has a bug that my working copy doesn't have. (Fiddle)
/* activeToggle is the selector for the container and descendants,
// .toggleHappy is the hidden input element within activeToggle */
$(activeToggle).on("click", ".toggleHappy", function(e) {
e.preventDefault();
$(this).val(($(this).val() == 0) ? 1 : 0);
console.log($(this).val());
});
I have researched and found the common mistake of using .click() instead of delegating using .on(click, selector, fn()) and am thus using the latter now.
What is frustrating is I have another .on(click) that IS working with the dynamic content. (the remove function) So, I was hoping another pair of eyes might help me find out what my mistake is. I know this is very similar to other questions on the basic subject, but I have read quite a number of those discussions first, and have applied many of them to get where I currently am.
Updates:
I tried what Madhavan suggested and it does in fact work, but as expected, only for the first-child. So dynamically added rows are not pointed to. Thanks for the fast look. I feel like it might be a selector/scope issue, but whats weird is that once the page is loaded, I can type this directly into console and it works?
//this works run from console, but doesn't fire from a real click?
$(".theContainer .data .switch .toggleHappy").first().click();
ANSWER I have been working on another project in the interim and it is starting to look like .on(event, selector, fn) is not working at all for dynamically added items. But, I had a breakthrough! The other project was slightly simplified, and I found the following:
//.theContainer is static
//.data .switch .toggleHappy is the dynamic chain created
//does not delegate and bind dynamically
$(".theContainer").on("click", ".data .switch .toggleHappy", function() {});
//DOES work!
$(".theContainer").on("click", ".toggleHappy", function() {});
It would appear that a selector like .path .to .element only works well on existing static content, while .element allows .on() to be bound and delegated properly for dynamically generated nodes. See the updated fiddle.
The part that confused me was that hopping into the console and referencing dynamic elements with the full selector DID work on dynamic elements, but the events weren't delegated to them. Thanks again for the eyes that looked over this question, hope it helps someone else, because I still haven't found this on the web yet.
It appears that delegating jQuery events with .on() will only work on static content when the selector used within .on() is a list of consecutive elements. In my code, I had a single container which was static, I delegated an event to it referencing multiple elements between the container and the destination elements. It would work locally for any number of statically identified elements, but any dynamically added ones would ignore the bindings. It also would throw no errors, and it WOULD respond to lines of script executed within the console directly, using the same selector chaining as the function. I found the following:
//.theContainer is static
//.data .switch .toggleHappy is the dynamic chain created
//does not delegate and bind dynamically
$(".theContainer").on("click", ".data .switch .toggleHappy", function() {});
//DOES work!
$(".theContainer").on("click", ".toggleHappy", function() {});
It would appear that a selector like ".path .to .element" only works well on existing static content, while ".element" allows .on() to be bound and delegated properly for dynamically generated nodes. See the updated fiddle.
The part that confused me was that hopping into the console and referencing dynamic elements with the full selector DID work on dynamic elements, but the events weren't delegated to them. Thanks again for the eyes that looked over this question, hope it helps someone else, because I still haven't found this on the web yet.
$(activeToggle).on("click", function(e) {
e.preventDefault();
$(":first-child",this).val(($(":first-child",this).val() == 0) ? 1 : 0);
console.log($(":first-child",this).val());
});
I made a change like this and works fine. But I'm not sure why it is not triggering for '.toggleHappy' instead.

Variable Not Remembering Itself When Separating Functions

As an extension to my previous question and this answer (https://stackoverflow.com/a/31327605/1582712), I am trying to modulate my JavaScript code so I utilize the same double click functionality across other classes.
My code is in the following jfiddle
If you try double clicking the H3 or the table, they don't seem to come back. I believe the reason is because the $el variable is not being registered and/or remembered properly.
I have a tried a few things, such as returning the $el variable and reusing it. I tried using an array for $el[search] so each is unique. None worked. I'm a little stumped, I think its a subtle JavaScript memory issue here!
FYI:
If you run this jfiddle You'll see the double clicking works over and over again. I am hoping to get this same effect, but generalized to any html class/id in the DOM.
The problem is that you are not only hiding the elements but also removing them from the DOM (line 25 in your JSFiddle). After removing them you are also calling hide (line 17) and then toggle (line 18) but the elements do not exist to hide or toggle anymore. You can resolve the problem by removing $rowsToHide.hide(); (line 17) and $rowsToHide.remove(); (line 25). See this updated JSFiddle. This will hide the elements but not remove them from the DOM.
This is not right:
$('table#safe-distances-table').dblclick(function () {
handleDoubleClick('tr.no-impact');
});
function handleDoubleClick(search) {
var $el = $(this);
// rest of the code
}
Try to do this:
$('table#safe-distances-table').dblclick(function (evt) {
handleDoubleClick(evt.currentTarget);
});
function handleDoubleClick(el) {
var $el = $(el);
// rest of the code
}
You have to pass the clicked element, not a selector to search and modify... its not the same thing. Be careful becase this evt.currentTarget means the element the user clicked. Maybe you must capture the parent element (.parent()) in order to get all the data, but ALWAYS try to send the event... and then with currentTarget obtain the clicked element.
ENJOY!

How can I reuse this function?

I've wrote a function which is working fine and all but when I try to reuse it on multiple html blocks with the same class, it breaks. I've tried to use the .next() and .closest() method but without results. Where do I apply these? The function is to recreate a <select> dropdown but by using a unordered list.
It is important that the classes and function stay the same as the list is generated by the CMS and can be multiple times a page, so having a solution where I change the code and call each function separate is not good..
Demos
Dropdown works fine (function works fine on one unordered list)
Dropdown breaks (when reusing function and html code)
Your script had a number of things that needed changing. This should work, as best as I could understand what you were trying to do.
Main point being this:
$(".cloned").click(function(){
$('.options').toggle();
e.preventDefault();
});
The $('.options') selector inside the handler selects all the elements with the options class, regardless of where you clicked in the document. That's why every dropdown was activating on a click.
You should only select the specific .options element for the click. There are many ways to do this, but this is what I did:
$(this).next('.options').toggle();
This can be better.. Check out this fiddle
using toggleClass()
Fiddle

How do I hide an element with the same markup via jquery?

I have two custom dropdown lists that have the same markup. I need to have only one show at a time. Right now, I'm able to open both at the same time. Both should also close when I click off the list.
The same markup for both lists is required, so I can't use unique ID's or additional classes to make this happen.
Here is a link to my fiddle example: http://jsfiddle.net/dg7Lc/29/
Any help would be greatly appreciated, thanks!
-D
Consider adding a data attribute such as 'active' via jquery when you click on one of them, then hide all those that have that attribute.
$('.custom-select').eq(0).hide() will hide the first one.
Use .show() instead of .hide() to show (obviously) and change the index to (1) to get the second one.
First thought would be if you could wrap a span or div around either or both and use that to get around the "same markup" limitation. Other than that, though, I'd suggest using order in page - use .next() and .prev() to get between them, and something like
$("div.custom-select").get(0)
or
$("div.custom-select").get(1)
to select them from outside.
edit: if you can run them off of something like an onmouseover, onchange, or whatnot, it's even easier - the one that's changing will be passed into the function as the "this" parameter. Just hide both, and show this, or show both and hide this.
edit2: similarly, once you have one of them hidden properly - well, that one will be hidden, and respond to the ":hidden" selector. Use that to distinguish between them (and save the distinction as a jquery variable) before you go showing or hiding anything else
Hide the first:
$('.custom-select').first().hide();
Hide the second:
$('.custom-select').last().hide();
And then put these lines of code where needed.
http://jsfiddle.net/dg7Lc/31/
Basically, closing the others:
$('.custom-select').not(this).find('ul').slideUp('fast');
And for closing when clicking outside the box, I used this piece of code but it's a bit dirty:
$("body").click(function(e) {
var should = true;
for($e = $(e.target); should && $e.length; $e = $e.parent()) {
should = !$e.is(".custom-select");
}
if(should) {
$('.custom-select').find('ul').slideUp('fast');
}
});
You can bind a click to the document, that looks to see if they clicked on the custom-select or the document outside it and hides any open lists as it should:
$(document).click(function(ev){
if(!$(ev.target).is('.custom-select span')){ $('.custom-select').find('ul').slideUp('fast'); }
});
Updated JSFiddle

How to make function work after append

For example i'm using append, and for example i'm appendig button in to a div, and i have function $('button_id').click(... etc to work affter i append the div, how can i do that.I mean i get no errors, but the function is not starting, it's because i append and then i want to use the function but how to do that, i tryed with delegate, but same thing.I tryed with function in the button tag , onmouseover and then the function thing, but nothing it gives me function not found.What is the solution ?
I have two events, one event is click event that appends button, the other event is click event that does something if the button that was appended is clicked, but that second event is not working ?
Try using :
$(elem).live(...)
It will bind event for now and in the future.
Firstly, it always helps if you show us the exact source code. $('button_id') is the incorrect selector to start with, try something more along the lines of $('#button_id') as your selector. Also, are you appending dynamic content? Anyways, I've always used the delegate() function quite successfully, but have you tried using the live() function? Also, one more thing to make sure of is that you have the newest version of jQuery as your source.
As was stated as well, you can not have duplicate ids, if you want to have a pointer, use class, instead of id="some_id" use class="appended". To select those using jQuery, use the selector like this $('.appended').
Try something like this it will work as per your expectations.
$("#button_id").click(function(){
//On click code goes here
}).appendTo($("#div_id"));
It's difficult to determine the problem you're having without seeing your code, but delegate (or live) should be perfect for what you're trying to do:
$("body").delegate("#b", "click", function() {
alert("ok");
});
$("#example").append('<input type="button" id="b" value="Click" />');
The click handler above will fire when an element with id="b" is clicked, whether or not that element happens to be in the DOM right now or not.
However, as others have noted, it's important to remember that IDs need to be unique within a document, so by the sounds of it you may be better of using classes instead.
You can see an example of the above code running here.

Categories

Resources