Compare Elements via jQuery - javascript

I'm in a situation where I want to check if two elements (one is clicked and another one a reference) are the same, what I'm trying to do is:
$("#process li").click(function() {
currentElement = $(this);
referenceElement = $("#process li:first-child");
if (currentElement === referenceElement) {
$(".mark").removeClass("mark");
$(this).addClass("mark");
}
});
So what I want is to check if the clicked <li> is the first child of the ul#process and if so first remove a .mark class from another element and then add it to the clicked one. I don't get any working result - ideas anyone?
UPDATE:
Thanks you very much! This is my solution:
$("#processlist li").click(function() {
currentElement = $(this);
if (currentElement.is('li:first-child')) {
$(this).addClass("mark");
}
});
Now if I click on a , if it is the first child of this list, the class .mark is added - sweet!

Comparing objects in JS is very troublesome. The simplest way is to just pick a few key properties and compare those, eg:
if (currentElement.prop('id') === referenceElement.prop('id') {
// rest of your code...
}
However, given your use case you could use is:
if (currentElement.is('#process li:first-child')) {
// rest of your code...
}
Example fiddle

You need to extract the DOM element from the jQuery object. You can use the get method of jQuery for this.
e.g. if( currentElement.get( 0 ) === referenceElement.get( 0 ) )

Related

How to use jQuery to select deeply nested elements created dynamically with javascript

So I have an object in my code and I use js to add the properties of the object to an array named rec based on users interaction. then I use a function named unRec to get unique elements of the array. Then I add the values returned by unRec to the HTML. Then I use jquery to wrap each of the values in anchor tags. So the code is basically like this
obj= {
0: "<span>module1</span>",
1: "<span>module1</span>",
2:"<span>module1</span>",
3:"<span>module2</span>",
4:"<span>module2</span>",
5:"<span>module3</span>",
6:"<span>module3</span>",
7:"<span>module3</span>",
8:"<span>module3</span>",
9:"<span>module4</span>"
}
function unRec(arr){
preRec = [];
for (j of arr){
if (preRec.indexOf(j)=== -1) {
preRec.push(j);
}
}
return (preRec);
}
Recom.innerHTML = unRec(rec);
$('#congrat #recom span').wrap('')
Now am unable to select the created anchors. Hence this function doesn't work
$('#congrat #recom .disp').click(function(e) {
var url = $(this).attr('href') + '#' + $(this).text();
$('#module').html('loading...).load(url); e.preventDefault();
});
I have tried to use find to select the anchors but it still doesn't work. This is the test
var t = $('#congrat #recom').find ('a').length;
console.log(t);
The HTML is basically like this:
<div id="congrat">
<span id="recom"></span>
</div>
<div id="module">click on one of the modules above<div>
Please provide a solution to select the created anchors. Thanks in advance

jQuery traversing. Find siblings including itself

I'm using jQuery traversing to jump between DOM elements.
First of i have a onClick function:
$(document).on('keyup', '.size, .ant', function(){
Inside of this function I send data about what's clicked, to another function.
sulorTableRowWeight( $(this) );
function sulorTableRowWeight(thisobj){
Now, I'd like to traverse from the clicked element $(this) to its parent. I'd like to find the parent's siblings and then traverse down to a specific sibling.
var inputSize = $(thisobj).parent().siblings('.sizeTd').children('.size');
My problem is when I want to traverse back down to the element I came from, it is not listed as a sibling because it isn't a sibling...
var inputSize = $(thisobj).parent().siblings(); console.log(inputSize)
console will give me the siblings, but not the one U came from...
So, when a user clicks ".size" I'd like to traverse up to the parent and back to size.... When a user clicks ".ant" I'd like to traverse up to the parent and then down to ".size"...
I tried to hardcode the traversing:
var inputSize = $(thisobj).parent().siblings('.sizeTd').children('.size');
But it won't work because it is not actually a sibling.
So what is it? And how can I get back to it?
If it is not possible, I have to run some if/else statements, U guess...
UPDATE
$(document).on('keyup', '.size, .ant', function(){
//Find changed <select> .tbody
var tbodyId = $(this).parent().parent('tr').parent('tbody').attr('id');
//Check <tbody> #id
if(tbodyId === "cpTableBody"){
}
else if(tbodyId === "sulorTableBody"){
sulorTableRowWeight( $(this) );
}
else if(tbodyId === "konturTableBody"){
konturTableRowWeight( $(this) );
}
else if(tbodyId === "kantbalkTableBody"){
kantbalkTableRowWeight( $(this) );
}
})
//Function sulorTableRowWeight
function sulorTableRowWeight(thisobj){
//Find the selected data-weight
var selectedWeightmm3 = $(thisobj).parent().siblings('.selectTd').children('.select').find(':selected').data('weightmm3');
//Find input .size value
var inputSize = $(thisobj).parent().siblings('.sizeTd').children('.size'); console.log(inputSize)
PROBLEM
My var inputSize will return undefined when I click a ".size" element. That´m's because it is not listed as a sibling to itself.
I know it's keyup, not click...
e.target will select the current input
$(document).on('keyup', '.size, .ant', function(e) {
inputSize = $(e.target);
if($(e.target).is('.ant')) {//test if the element is .ant
inputSize = $(e.target).parent().find('.size');//get .size based on .ant
}
console.log(inputSize[0]);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<input class="size x1" placeholder="x1">
<input class="ant x1" placeholder="x1 ant">
</div>
<div>
<input class="size x2" placeholder="x2">
<input class="ant x2" placeholder="x2 ant">
</div>
Hmm, if you're passing in $(this) as thisObj I don't think you need to be nesting thisObj in a $(). (See note below)
Anyway, you could try using .parents('<grandparent>').find('<child>') so basically you're traversing one higher level up the tree with <grandparent>, then getting all the descendants that match the child selector. That should include the branch of the three that $(this) represents. But it's hard to say for sure without seeing your HTML.
** A good practice when assigning jQuery objects to variables is to use $ syntax, ie var $this = $(this) so you know anything prepended with a $ is a jQuery object.
inside sulorTableRowWeight , you should have the reference to the clicked element in thisobj variable.

jQuery slideDown not working on element with dynamically assigned id

EDIT: I cleaned up the code a bit and narrowed down the problem.
So I'm working on a Wordpress site, and I'm trying to incorporate drop-downs into my menu on mobile, which means I have to use jQuery to assign classes and id's to my already existing elements. I have this code that already works on premade HTML, but fails on dynamically created id's.
Here is the code:
...
var menuCount = 0;
var contentCount = 0;
//find the mobile menu items
var submenus = $('[title="submenu"]');
if (submenus.length && submenus.parent('.fusion-mobile-nav-item')) {
console.log(submenus);
submenus.addClass('dropdown-title').append('<i id="dropdown-angle" class="fa fa-angle-down" aria-hidden="true"></i>');
submenus.each(function() {
$(this).attr("href", "#m" + menuCount++);
})
var content = submenus.parent().find('ul.sub-menu');
content.addClass('dropdown-content');
content.each(function() {
$(this).attr("id", "m" + contentCount++);
})
}
$(document).on('click', '.dropdown-title', function(e) {
var currentAttrValue = $(this).attr('href');
if ($(e.target).is('.d-active') || $(e.target).parent('.dropdown-title').is('.d-active')) {
$(this).removeClass('d-active');
$(currentAttrValue).slideUp(300).removeClass('d-open');
} else {
$('.dropdown-title').removeClass('d-active');
$('.dropdown-content').slideUp(300).removeClass('d-open');
$(this).addClass('d-active');
console.log($(currentAttrValue));
//THIS LINE FAILS
$(currentAttrValue).slideDown(300).addClass('d-open');
}
e.preventDefault();
});
I've registered the elements with the class dropdown-title using $(document).on(...) but I can't figure out what I need to do to register the elements with the custom ID's. I've tried putting the event callback inside the .each functions, I've tried making custom events to trigger, but none of them will get the 2nd to last line of code to trigger. There's no errors in the console, and when I console log the selector I get this:
[ul#m0.sub-menu.dropdown-content, context: document, selector: "#m0"]
0
:
ul#m0.sub-menu.dropdown-content
context
:
document
length
:
1
selector
:
"#m0"
proto
:
Object[0]
So jQuery knows the element is there, I just can't figure out how to register it...or maybe it's something I'm not thinking of, I don't know.
If you are creating your elements dynamically, you should be assigning the .on 'click' after creating those elements. Just declare the 'on click' callback code you posted after adding the ids and classes instead of when the page loads, so it gets attached to the elements with .dropdown-title class.
Check this jsFiddle: https://jsfiddle.net/6zayouxc/
EDIT: Your edited JS code works... There also might be some problem with your HTML or CSS, are you hiding your submenus? Make sure you are not making them transparent.
You're trying to call a function for a attribute, instead of the element. You probably want $(this).slideDown(300).addClass('d-active'); (also then you don't need $(this).addClass('d-active'); before)
Inside submenus.each loop add your callback listener.
As you are adding the class dropdown-title dynamically, it was not available at dom loading time, that is why event listener was not attached with those elemnts.
var menuCount = 0;
var contentCount = 0;
//find the mobile menu items
var submenus = $('[title="submenu"]');
if (submenus.length && submenus.parent('.fusion-mobile-nav-item')) {
console.log(submenus);
submenus.addClass('dropdown-title').append('<i id="dropdown-angle" class="fa fa-angle-down" aria-hidden="true"></i>');
submenus.each(function() {
$(this).attr("href", "#m" + menuCount++);
// add callback here
$(this).click( function(e) {
var currentAttrValue = $(this).attr('href');
if ($(e.target).is('.d-active') || $(e.target).parent('.dropdown-title').is('.d-active')) {
$(this).removeClass('d-active');
$(currentAttrValue).slideUp(300).removeClass('d-open');
} else {
$('.dropdown-title').removeClass('d-active');
$('.dropdown-content').slideUp(300).removeClass('d-open');
$(this).addClass('d-active');
console.log($(currentAttrValue));
$(currentAttrValue).slideDown(300).addClass('d-active');
}
e.preventDefault();
});
})
var content = submenus.parent().find('ul.sub-menu');
content.addClass('dropdown-content');
content.each(function() {
$(this).attr("id", "m" + contentCount++);
})
}
Turns out my problem is that jQuery is adding to both the mobile menu and the desktop menu, where the desktop menu is being loaded first when I search for that ID that's the one that jQuery finds. So it turns out I was completely wrong about my suspicions.

Checking if Element hasClass then prepend and Element

What I am trying to achieve here is when a user clicks an element it becomes hidden, once this happens I want to prepend inside the containing element another Element to make all these items visible again.
var checkIfleft = $('#left .module'),checkIfright = $('#right .module');
if(checkIfleft.hasClass('hidden')) {
$('#left').prepend('<span class="resetLeft">Reset Left</span>');
} else if(checkIfright.hasClass('hidden')) {
right.prepend('<span class="resetRight">Reset Right</span>');
}
I tried multiple ways, and honestly I believe .length ==1 would be my best bet, because I only want one element to be prepended. I believe the above JS I have will prepend a new element each time a new item is hidden if it worked.
Other Try:
var checkIfleft = $('#left .module').hasClass('hidden'),
checkIfright = $('#right .module').hasClass('hidden');
if(checkIfleft.length== 1) {
$('#left').prepend('<span class="resetLeft">Reset Left</span>');
} else if(checkIfright.length== 1) {
right.prepend('<span class="resetRight">Reset Right</span>');
}
else if(checkIfleft.length==0){
$('.resetLeft').remove()
} else if (checkIfright.length==0){
$('.resetRight').remove()
}
Basically if one element inside the container is hidden I want a reset button to appear, if not remove that reset button...
hasClass() only works on the first item in the collection so it isn't doing what you want. It won't tell you if any item has that class.
You can do something like this instead where you count how many hidden items there are and if there are 1 or more and there isn't already a reset button, then you add the reset button. If there are no hidden items and there is a reset button, you remove it:
function checkResetButtons() {
var resetLeft = $('#left .resetLeft').length === 0;
var resetRight = $('#left .resetRight').length === 0;
var leftHidden = $('#left .module .hidden').length !== 0;
var rightHidden = $('#right .module .hidden').length !== 0;
if (leftHidden && !resetLeft) {
// make sure a button is added if needed and not already present
$('#left').prepend('<span class="resetLeft">Reset Left</span>');
} else if (!leftHidden) {
// make sure button is removed if no hidden items
// if no button exists, this just does nothing
$('#left .resetLeft').remove();
}
if (rightHidden && !resetRight) {
$('#right').prepend('<span class="resetRight">Reset Right</span>');
} else if (!rightHidden) {
$('#right .resetRight').remove();
}
}
// event handlers for the reset buttons
// uses delegated event handling so it will work even though the reset buttons
// are deleted and recreated
$("#left").on("click", ".resetLeft", function() {
$("#left .hidden").removeClass("hidden");
$("#left .resetLeft").remove();
});
$("#right").on("click", ".resetRight", function() {
$("#right .hidden").removeClass("hidden");
$("#right .resetRight").remove();
});
FYI, if we could change the HTML to use more common classes, the separate code for left and right could be combined into one piece of common code.
Add the reset button when hiding the .module, if it's not already there :
$('#left .module').on('click', function() {
$(this).addClass('hidden');
var parent = $(this).closest('#left');
if ( ! parent.find('.resetLeft') ) {
var res = $('<span />', {'class': 'resetLeft', text : 'Reset Left'});
parent.append(res);
res.one('click', function() {
$(this).closest('#left').find('.module').show();
$(this).remove();
});
}
});
repeat for right side !
I've recently experimented with using CSS to do some of this stuff and I feel that it works quite well if you're not trying to animate it. Here is a jsfiddle where I can hide a module and show the reset button in one go by adding/removing a 'hideLeft' or 'hideRight' class to the common parent of the two modules.
It works by hiding both reset button divs at first. Then it uses .hideLeft #left { display:none;} and .hideLeft #right .resetLeft { display: block; } to hide the left module and display the reset button when .hideLeft has been added to whichever element both elements descend from. I was inspired by modernizr a while back and thought it was a neat alternative way to do things. Let me know what you think, if you find it helpful, and if you have any questions :)

jquery - filter elements based on matched values from clicked filter option and container element values

UPDATE 2:
Thanks so much for all your help. While all three solutions worked, I like Bill's in terms of readability and performance. As always, I'm amazed by the level of expertise and help here. REALLY appreciate the help.
UPDATE:
Put demo up on jsfiddle: http://jsfiddle.net/FC4QE/17/
I need to create a filter. Users click on a brand name link and if there is a match then I need to filter out the other products. The brand is contained in a product name, so I'm searching for a match and if there is one or many, I need to hide the other products.
I have the following javascipt/jquery code:
$(function(){
$('#filter-by-brand li a').click(function(){
// get html string of clicked item
var brandNameSelected = $(this).html();
var productContainer = $('#product-collection div.productBoxWrapper');
// reset products in the view
if (brandNameSelected == 'All Brands'){
productContainer.fadeIn("slow");
}
// for each product title (a tag)
$("#product-collection h4 a").each(function(){
var productTitle = jQuery(this).html();
// if item clicked is contained inside product title, hide all
// products and only show the ones where the title matched
if(productTitle.indexOf(brandNameSelected) != -1){
// hide container of all products, this hides all products
productContainer.fadeOut("slow");
// then show only ones that match. the problem is that only the one product is
// displayed since we're inside the .each. How can I show all products where product title contains the item clicked?
$(this).parent().parent().parent().parent().fadeIn("slow");
}
});
});
});
I explained everything in the comments inside the code, but basically, while the code works, because I'm showing the products where item clicked is contained inside the .each method, it only shows the last item matched. How can I show all the matched ones inside the .each or is this impossible and is there another way?
Hope this makes sense and that someone might have some advice!
Thanks.
I got the nicest looking results from this:
$('#filter-by-brand li a').click(function()
{
var brandNameSelected = $(this).html();
var productContainer = $('#product-collection .product-container');
if (brandNameSelected == 'All Brands')
{
productContainer.fadeIn("slow");
}
else {
$(".product-container")
.fadeOut(100)
.delay(100)
.filter(function() {
return $(this).html().indexOf(brandNameSelected) > -1;
})
.each(function(index, item) {
$(item).fadeIn("slow");
});
}
});
You can play with it at http://jsfiddle.net/tu8tc/1/;
For "all brands", bail out. For specific brand names, hide all productContainers unconditionally then selectively fadeIn those that meet the criterion.
$(function() {
$('#filter-by-brand li a').click(function() {
var brandNameSelected = $(this).html();
var productContainer = $('#product-collection .product-container');
if (brandNameSelected == 'All Brands') {
productContainer.fadeIn("slow");
return;
}
productContainer.hide();
$("#product-collection h4 a").each(function() {
var productTitle = $(this).html();
if(productTitle.indexOf(brandNameSelected) != -1) {
$(this).closest(".product-container").stop().fadeIn("slow");
}
});
});
});
See update of your fiddle
Note how jQuery's .closest() avoids the ugly .parent().parent().parent().
.stop() is precautionary, just in case a fadeout() is already running on the element. Not necessary if this is the only code that animates productContainers.
EDIT...
Or to be concise and more efficient, with judicious use of jQuery's .filter you can do almost everything in one statement (though readability suffers):
$(function() {
$('#filter-by-brand li a').click(function() {
var brandNameSelected = $(this).html();
$('#product-collection').find('.product-container').hide().end().find('h4 a').filter(function() {
return (brandNameSelected == 'All Brands') || ($(this).html().indexOf(brandNameSelected) != -1);
}).closest(".product-container").stop().fadeIn("slow");
});
});
See further update to fiddle
Why not simply hide products that you want filtered out?
if(productTitle.indexOf(brandNameSelected) == -1)
{
$(this).parent().parent().parent().fadeOut("slow");
}
See http://jsfiddle.net/2Sduq/1/ .

Categories

Resources