Count number of first layer/set of children in cloned element - javascript

I am trying to count the number of it's first layer of children not including it's child of child of child.. This is my codes
HTML
<div class="container">
<div class="row">
<div class="btn-container col-md-12">
Hello
</div>
</div>
</div>
JS
$('a').click(function(){
var c = $(this).closest('.row').clone();
$(this).after( c );
var count = $(this).closest('.row').find('.btn-container').length;
alert(count);
});
The alert should always return 1 since the cloned element is appended inside of it.
jsFiddle
I tried ..
.find() but also as I expected, it will count all inside of it.. Child of child of child and so on...
var parent = $(this).closest('.row');
var count = $('.btn-container', parent).length;
But still can not get what I want.
I already think of adding a name/class specifying to them. Like btn-container first-children ..
But I am wondering if there is a jQuery trick that will make it simplier.

find('.btn-container') will select all descendants .btn-container. You should use direct child selector > like following.
$('a').click(function () {
var c = $(this).closest('.row').clone();
$(this).after(c);
var count = $(this).closest('.row').find('>.btn-container').length;
//---------------------------------------^^--------------------
alert(count);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="row">
<div class="btn-container col-md-12">
Hello
</div>
</div>
</div>

Rather than find() you could use children(). From jQuery .children() documentation:
The .children() method differs from .find() in that .children() only
travels a single level down the DOM tree while .find() can traverse
down multiple levels to select descendant elements (grandchildren,
etc.) as well
var count = $(this).closest('.row').children('optional-selector').length;

Related

How can I iterate through a number of similar elements and change the properties of each in turn?

Within my webpage I have a number of regular elements that all share the same structure. These elements contain a span that may be filled with some text, or may be left blank.
These elements start by being hidden using JQuery's hide() function.
I want to be able to get each element in turn, check whether its child span contains any text, if it does then I want the element to be displayed using show().
Here is an example of the elements I wish to hide/show:
<div id="application-number-row" class="row validation-row">
<div class="col">
<span>Application Number</span>
</div>
<div class="col">
<span id="application-number-value" class="validation-row-value">value</span>
</div>
</div>
<div id="property-value" class="row validation-row">
<div class="col">
<span>Property Value</span>
</div>
<div class="col">
<span id="property-value-value" class="validation-row-value"></span>
</div>
</div>
At the moment I have the below code. The first function works correctly and hides all of the elements with the .validation-row class. The second function however does not work and I'm unsure how to structure my code so that it iterates over each .validation-row in turn.
function hideAllDataRows() {
$('.validation-row').hide();
}
function displayPopualtedDataRows() {
var validationRow = $('.validation-row');
if (validationRow.find('.validation-row-value').html != "") {
validationRow.show();
}
}
Here is a breakdown of what I want to happen:
Get each .validation-row found in the HTML document
Iterate through each .validation-row and check if the child .validation-row-value <span> contains any text.
If it does, call $(show()) on the entire .validation-row
Get each .validation-row found in the HTML document
var rows = $(".validation-row");
Iterate through each .validation-row and check if the child .validation-row-value contains any text.
don't need to 'get' them first, but if it helps:
var rows = $(".validation-row");
rows.each(function() {
if ($(this).find("span.validation-row-value").text() !== "") {
}
});
If it does, call $(show()) on the entire .validation-row
var rows = $(".validation-row");
rows.each(function() {
if ($(this).find("span.validation-row-value").text() !== "")
$(this).show();
});
Can streamline this using .map or :contains

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");
})

JavaScript insertBefore not working properly

In an attempt to make my answer more flexible on this question:
function invertDivs(parentDiv) {
var first = document.getElementById(parentDiv).firstChild;
console.log(first);
var second = document.getElementById(parentDiv).lastChild;
console.log(second);
document.getElementById(parentDiv).insertBefore(second, first);
}
<div id="parent">
<div id="first">Div 1</div>
<div id="second">Div 2</div>
</div>
<button onclick="invertDivs('parent');">Invert Divs</button>
However, the divs are only inverted sometimes, not always.
An initial click on the button yields this on the console:
A second click:
After a bunch of clicks:
I'm confused as to what's wrong with the code. I select the first child of parent div, and do the same for the last child. Then I just insert the current second div before the first. That's the end of the function. They are also the direct children of the parent div, as required by the insertBefore function.
As mentioned in comments, firstChild and lastChild can return text nodes for the whitespace between elements. You can use firstElementChild and lastElementChild to ignore these.
function invertDivs(parentDiv) {
var first = document.getElementById(parentDiv).firstElementChild;
console.log(first);
var second = document.getElementById(parentDiv).lastElementChild;
console.log(second);
document.getElementById(parentDiv).insertBefore(second, first);
}
<div id="parent">
<div id="first">Div 1</div>
<div id="second">Div 2</div>
</div>
<button onclick="invertDivs('parent');">Invert Divs</button>
For some other workarounds, which you might need for older browsers, see element.firstChild is returning '<TextNode ...' instead of an Object in FF
You're not taking into account text nodes. In your HTML example above, there are 5 nodes.
[0] => TextNode
[1] => #first
[2] => TextNode
[3] => #second
[4] => TextNode
It seems pretty evident that you don't care about the text nodes here. You have quite a few options.
One option would be to filter out all the text nodes. (Can't use Array.prototype.filter method because childNodes is not an array, but a NodeList)
This will give you an array of only DOM elements.
function invertDivs(parentNodeId) {
var childElements = [],
parentNode = document.getElementById(parentNodeId);
//Filter out the child nodes that aren't elements.
//parentNode.childNodes is a NodeList, and not an array (even though it looks like one)
for (var i = 0; i < parentNode.childNodes.length; ++i) {
if (parentNode.childNodes[i].nodeType === 1)
childElements.push(parentNode.childNodes[i]);
}
parentNode.insertBefore(childElements[childElements.length - 1], childElements[0]);
}
<div id="parent">
<div id="first">Div 1</div>
<div id="second">Div 2</div>
</div>
<button onclick="invertDivs('parent');">Invert Divs</button>
Another option would be to use the more modern DOM API properties: See Barmar or GolezTrol's answers. They would be much more performant if you audience has support for IE9+ browsers.
It's not random. If I click 2 times, to add Div 2 to the end of the list, then click 3 times to get Div 1 at the end of the list. This pattern repeats.
The reason is because there are also next nodes inbetween. This is the whitespace inbetween the elements.
To work around this, use the children attribute. This selects the child elements (instead of nodes).
function invertDivs(parentDiv) {
var parent = document.getElementById(parentDiv);
var first = parent.children[0];
console.log(first);
var second = parent.children[parent.children.length-1];
console.log(second);
document.getElementById(parentDiv).insertBefore(second, first);
}
<div id="parent">
<div id="first">Div 1</div>
<div id="second">Div 2</div>
</div>
<button onclick="invertDivs('parent');">Invert Divs</button>
The answer to your question is given in the MDN docs(https://developer.mozilla.org/en-US/docs/Web/API/Node/firstChild) for Node.firstChild. If you refer to docs you will understand why you are getting the #text as the first Node.

Siblings with same attribute value

I have a div structure like
<div>
<div class='class1'>contens</div>
<div class='class2'>contens</div>
<div class='class2'>contens</div>
<div class='class2'>contens</div>
<div class='class3'>contens</div>
<div class='class2'>contens</div>
<div class='class1'>contens</div>
</div>
Here I want to write a selector which will select all the div elements with class='class2', they should be adjacent to each other. i.e I should select only index 1,2,3 but not div index 5 since its not adjacent to group.
Please Help here.
You can use the adjacent sibling selector
var elems = $('.class2 + .class2').add( $('.class2 + .class2').prev() )
FIDDLE
or caching the selector (with an argument to a IIFE)
var elems = (function(x) {return x.add( x.prev() )})($('.class2 + .class2'));
FIDDLE
Here is an alternative solution with .filter:
For example:
$('.class2').filter(function() {
return $(this).prev('.class2').add($(this).next('.class2')).length > 0;
});
It filters out the elements that don't have a sibling with class .class2.

Remove from Parent DIV container

i have got this :
<div id="video_pattern">
<div id="des"position:relative;></div>
<div id="mes"position:relative;></div>
</div>
i want to remove the
> <div id="video_pattern">
but the
<div id="des"position:relative;></div>
<div id="mes"position:relative;></div>
should stay, is this possible?
To handle your exact situation you can use this code:
var ToRemoveElement = document.getElementById("video_pattern");
ToRemoveElement.parentNode.appendChild(document.getElementById("des"));
ToRemoveElement.parentNode.appendChild(document.getElementById("mes"));
ToRemoveElement.remove();
This is the way to go if you only want these specific elements removed from the video_pattern div. If you want a more generic solution to remove all child elements then use the following:
var ToRemoveElement = document.getElementById("video_pattern");
var children = ToRemoveElement.children;
while (children.length > 0) {
ToRemoveElement.parentNode.appendChild(children[0]);
}
ToRemoveElement.remove();
JSfiddle example
Using Jquery you can do like this
var inner = $("#video_pattern").contents();
$("#video_pattern").replaceWith(inner);

Categories

Resources