jQuery traversing. Find siblings including itself - javascript

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.

Related

JQuery clone is not working with class selector

Fiddle
I am trying to clone a span from the onClick() function of a button. First time this works fine but when I try second time it is not cloning. What am I doing wrong?
Here is the essence of my code.
$(document).ready(function(){
$('.addmachinerow').on('click',function(){
var edcname = $('.edc_name option:selected').val();
var machine_description = $("input[name='machine_description'").val();
var capacity = $("input[name='capacity'").val();
var voltage_level = $("input[name='voltage_level'").val();
var powertype = $("select[name='typeofpower'").val();
var edcautovalue = $('.ecaddingspan').attr('data-value');
//if($('#bank_increment').html() == '') $('#bank_increment').html('0'); else $('#bank_increment').html(parseInt($('#bank_increment').html())+1);
//if($('#bank_clickededit').html() == '') var bank_increment = $('#bank_increment').html(); else var bank_increment = $('#bank_clickededit').html();
$('.ecaddingspan').clone().appendTo('.edcparent');
//$('.bankname, .bankbranch , .IFSCcode , .bankaccno , .accsincefrom').val('');
var edc_details = {'edcname' : edcname, 'machine_description' : machine_description, 'capacity' : capacity, 'voltage_level' : voltage_level, 'powertype' : powertype }
//$('.bank_details_array').append(JSON.stringify(bank_details)+'&&');
});
});
Additionally:
How can i clone the entire sets on clicking the Total clone button ?
I need to save the values in array with different names. Is that possible ?
How can i clone the entire sets on clicking the Total clone button ?
You've to use event delagtion on() instead :
$('body').on('click','.addmachinerow', function(){
//Event code
})
Since the new .addmachinerow added to the page dynamically after the clone.
I need to save the values in array with different names is that possible ?
I suggest the use of the array name [] like :
<input name='machine_description[]' />
<input name='voltage_level[]' />
Hope this helps.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
$('.cloneitem').not('.cloned').clone().addClass('cloned').appendTo('body');
});
});
</script>
</head>
<body>
<p class="cloneitem">This is a paragraph.</p>
<button>Clone all p elements, and append them to the body element</button>
</body>
</html>
The issue is a common misconception of JQuery selectors. If you play with ID selectors then switch to class selectors then you often don't notice a difference in behaviour. The ID selector doc says
ID Selector: If more than one element has been assigned the same ID, queries that use that ID will only select the first matched element in the DOM
whilst for the class selector
Class Selector: Selects all elements with the given class.
What this means is that when you clone the target element you get away with a subsequent ID selection (JQuery ignores the duplicates) but a subsequent class selection will trip you up if you were not expecting JQuery to return multiple matches. Class selectors are great for grouping elements but not so great for cloning.
While I am on the soap box - whenever you use the clone function you should consider and fix the potential duplicate ID and un-required class duplicates that you are producing. Duplicate ID's are definitely bad show - duplicate classes may actually be by design but you should still consider them.
In the code sample below I assign the class iAmSpartacus to the original span which the onClick() function then clones. Each clone also gets the iAmSpartacus class so I remove it from each new clone to ensure that the $(".iAmSpartacus") selector always returns a maximum of one element. The spans show their current class property to prove the point.
// this runs one - shows us classes of original span
var origSpan=$(".iAmSpartacus")
origSpan.html("My classes are: " + origSpan.prop("class"))
$("#daButton").on("click", function(e) {
var newSpan = $(".iAmSpartacus").clone();
newSpan.removeClass("iAmSpartacus"); // remove the dup targetting class
newSpan.appendTo('.edcparent');
newSpan.html("My classes are: " + newSpan.prop("class"))
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="daButton">Click me</button>
<div class="edcparent" style="border: 1px solid red;">
<span class="ecaddingspan iAmSpartacus" style="display: block;">I am a span</span>
</div>

Remove parent div if child div contains a certain data attribute

Since, I'm doing this dynamically, I have to check whether the main div matches a certain user-id. If it does, then dive into it and do the extra work. Let me show you what i'm talking about.
<div class="col-md-6 user-card-holder" data-user="2">
<div class="col-xs-2 single-card">
<div class="house" data-house="hearts" data-value="q">Q-hearts</div>
</div>
</div>
There are many div's having the classname user-card-holder. I have to check the specific one with the data-user attribute. Now what I'm checking is:
If a div contains data-house with the value of hearts and also data-value with the value of q, then remove that div along with it's parent. Here parent means the div having the class single-card and not the user-card-holder
I have tried using filter(). Maybe I'm doing something wrong here.
$('.user-card-holder[data-user='+ card.user +'] div div').filter(function(){
var div = $(this).data('house') == card.house && $(this).data('value') == card.number;
return div.parent()
}).remove();
I have seen answers which shows to remove the element based on data attribute, but not it's parent.
I'd suggest:
// this finds all <div> elements with a
// 'data-house' attribute equal to 'hearts' and a
// 'data-value' attribute equal to 'q':
$('div[data-house=hearts][data-value=q]')
// traverses to the parent of the matching element(s):
.parent()
// removes the parent element(s) from the DOM:
.remove();
Alternatively, if you're searching an ancestor dynamically to find the appropriate element(s) to remove, which seems to be the case on a re-reading of your question:
// finds <div> element(s) with the class of 'user-card-holder'
// and the 'data-user' attribute equal to the value of the 'card.user'
// variable, and finds the descendant <div> element(s) matching
// the selector used above:
$('div.user-card-holder[data-user=' + card.user + '] div[data-house=hearts][data-value=q]')
// traverses to the parent of the descendant element:
.parent()
// removes the parent element of that descendant:
.remove();
References:
CSS:
Attribute-selectors.
jQuery:
parent().
remove().
Try this function:
removeCardFromUser(2);
function removeCardFromUser(id) {
$('.user-card-holder').filter(function(){
var user = $(this).data('user');
if (user === id) {
$(this).find('div').filter(function(){
var house = $(this).data('house');
var value = $(this).data('value');
if (house === 'hearts' && value === 'q') {
$(this).parent().remove();
}
});
}
});
}
It looks for a div with class 'user-card-holder' and data-user = {given id} and then looks for its descendants with data-house = 'hearts' and data-value='q' and deletes its parent.
David's answer would suffice though! :)

Jquery assign second child attribute

Is there a way to assign nested div attribute with variable? Like
<div>
<div>
123456
</div>
</div>
Become
<div>
<div sectionid="123">
123456
</div>
</div>
BTW above component will be created by JavaScript.
I've tried something like this, but it didn't work.
var a = $('<div><div>123456</div></div>');
a.eq(":nth-child(2)").attr("sectionid", "123");
Try this snippet.
//FOR DOM HTML
console.log("FOR DOM HTML");
//1st way
$('#input > div').find('div').attr("sectionid","123");
console.log($('#input').html());
//2nd way
$('#input > div > div').attr("sectionid","321");
console.log($('#input').html());
//JS HTML
console.log("FOR JS OBJECT");
var input = $('<div><div>123456</div></div>');
//1st way
input.eq(0).children().attr('sectionid', '456');
console.log(input[0].outerHTML);
var input = $('<div><div>123456</div></div>');
//2nd way
$(input[0]).children().attr('sectionid', '789');
console.log(input[0].outerHTML);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="input">
<div>
<div>
123456
</div>
</div>
</div>
nth-child(2) maches elements that are the second child element of their parent. This is not the case for your div, it is the first element of the parent div.
.eq finds an element at a specific index. It is not the place to pass a selector.
The child selector, >, will find a child element, i.e. div>div will find a div that is an immediate child of a div.
Note that the code you've provided, $('<div></div>123456<div></div>');, doesn't create a DOM tree like the one you've pasted.
Update, now that the code is edited, the value of a is a div with a child div. Since a.find will perform a search within a, you don't have to use a child selector, but can find the div immediately:
a.find('div')
Just apply attribute to children. No complicated 'find', eq(), etc.
var a = $('<div><div>123456</div></div>');
a.children().attr('sectionid', '123');
$('body').append(a);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Why don't you add it in the first place? Not clear if you add it later!
$(document).ready(function() {
var sectionid = "123";
var a = $('<div><div sectionid="' + sectionid + '">123456</div></div>');
$('body').append(a);
});
div[sectionid]{
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Try this - I have added comments to the code to explain what is happening.
Inspect the element to see that the attribute is added
var a = $('<div><div>123456</div></div>'); // change this to match the structure you want
a.children() // .children gets the direct descendant (which should be the nested div
.eq(0) // gets the first in the array that is returned (if there are multiple direct descendents) - it is a 0 based index selector
.attr('sectionid', '123');
$('body').append(a)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
More information about .children()
More information about .eq()
try it :
$(document).ready(function(){
$("div").eq(1).attr("sectionid","123");
})

Compare Elements via jQuery

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 ) )

how to get outerHTML with jquery in order to have it cross-browser

I found a response in a jquery forum and they made a function to do this but the result is not the same.
Here is an example that I created for an image button:
var buttonField = $('<input type="image" />');
buttonField.attr('id', 'butonFshi' + lastsel);
buttonField.val('Fshi');
buttonField.attr('src', 'images/square-icon.png');
if (disabled)
buttonField.attr("disabled", "disabled");
buttonField.val('Fshi');
if (onblur !== undefined)
buttonField.focusout(function () { onblur(); });
buttonField.mouseover(function () { ndryshoImazhin(1, lastsel.toString()); });
buttonField.mouseout(function () { ndryshoImazhin(0, lastsel.toString()); });
buttonField.click(function () { fshiClicked(lastsel.toString()); });
And I have this situation:
buttonField[0].outerHTML = `<INPUT id=butonFshi1 value=Fshi src="images/square-icon.png" type=image jQuery15205073038169030395="44">`
instead the outer function I found gives buttonField.outer() = <INPUT id=butonFshi1 value=Fshi src="images/square-icon.png" type=image>
The function is:
$.fn.outer = function(val){
if(val){
$(val).insertBefore(this);
$(this).remove();
}
else{ return $("<div>").append($(this).clone()).html(); }
}
so like this I loose the handlers that I inserted.
Is there anyway to get the outerHTML with jquery in order to have it cross-browser without loosing the handlers ?!
You don't need convert it to text first (which is what disconnects it from the handlers, only DOM nodes and other specific JavaScript objects can have events). Just insert the newly created/modified node directly, e.g.
$('#old-button').after(buttonField).remove();`
after returns the previous jQuery collection so the remove gets rid of the existing element, not the new one.
Try this one:
var html_text = `<INPUT id=butonFshi1 value=Fshi src="images/square-icon.png" type=image jQuery15205073038169030395="44">`
buttonField[0].html(html_text);
:)
Check out the jQuery plugin from https://github.com/darlesson/jquery-outerhtml. With this jQuery plugin you can get the outerHTML from the first matched element, replace a set of elements and manipulate the result in a callback function.
Consider the following HTML:
<span>My example</span>
Consider the following call:
var span = $("span").outerHTML();
The variable span is equal <span>My example</span>.
In the link above you can find more example in how to use .outerHTML() plug-in.
This should work fine:
var outer = buttonField.parent().html();

Categories

Resources