Counting div elements based on id - javascript

I have a page similar to:
<div id="content">
<div id="boxes">
<div id="box:content:1:text" />
<div id="box:content:2:text" />
<div id="another_id" />
<div id="box:content:5:text" />
</div>
</div>
I want to know the number of div with id that matches the expression box:content:X:text (where X is a number). I can use pure javascript or jquery for doing that.
But inside boxes i can have several types of divs that i don't want to count ("another_id") and i can have gaps from the X of an element and the next element, they are not in sequence.
I was searching a way to gets the elements based on a regexp but i haven't found any interesting way. Is it a possibile approach ?
Thanks

jQuery:
$("div[id]").filter(function() {
return !(/^box:content:\d+:text$/.test(this.id));
}).size();
Pure JavaScript:
var elems = document.getElementsByTagName("div"),
count = 0;
for (var i=0, n=elems.length; i<n; ++i) {
if (typeof elems[i].id == "string" && /^box:content:\d+:text$/.test(this.id)) {
++count;
}
}

To expand on Boldewyn's comment, you can provide multiple classes delimited by spaces, and then work with those classes separately or in combination.
This probably removes the need for the ids, but I've left them in just in case:
<div id="content">
<div id="boxes">
<div id="box:content:1:text" class="box content 1 text" />
<div id="box:content:2:text" class="box content 2 text" />
<div id="another_id" />
<div id="box:content:5:text" class="box content 5 text" />
</div>
</div>
And then with jQuery you can count just the desired items with:
$j('#content>#boxes>.box.content.text').length
(or perhaps just use '#boxes>.box.text' or whatever works for what you're trying to match)

Related

How to show element only if other element contains something using jQuery?

My guess is what I want to achieve should be easy, but due to my lack of knowledge of front-end development, I cannot manage to solve issue. Have a page that works with AJAX-filters that users can select. Filters that are currently applied show up within <div> with id=current-filters.
HTML looks like this:
<div id="current-filters-box">
<div style="margin-bottom: 15px">
<strong>Current filters:</strong>
<div id="current-filters">
<!-- here every single applied filter is displayed -->
</div>
</div>
</div>
Need to hide the the entire DIV current-filters-box in case no filter is applied.
The page uses a Javascript file, bundle.js which is massive, but contains the following line:
s=document.getElementById("current-filters")
Therefore tried the following if-statement to hide the DIV:
if(s.length<1)$('#current-filters-box').hide()
and
if(s=0)$('#current-filters-box').hide()
But this does not seem to have any effect. Can someone tell, what I did wrong?
Demo of page can be found here
EDIT: this is what the HTML looks like when filters are applied:
<div id="current-filters-box">
<div style="margin-bottom: 15px">
<strong>Current filters:</strong>
<div id="current-filters">
<div class="badge-search-public">
<strong>Humanities & Languages</strong> <span class="x" data-property="disciplines" data-value="4" onclick="filter.removeFilter(this)">×</span>
</div>
<div class="badge-search-public">
<strong>January</strong> <span class="x" data-property="months" data-value="1" onclick="filter.removeFilter(this)">×</span>
</div>
</div>
</div>
Both of your conditions are incorrect or I would say they are not doing what you think they do.
s.length will always prints undefined so instead of s.length<1 you could use s.children.length
and the second one is not a condition rather it is an assignment
s==0 // condition
s=0 //assignment
the correct condition for your requirement would be
if(s.children.length<1){
I have assigned snippets for illustration.
Without filters
s = document.getElementById("current-filters")
console.log(s.children.length);
if (s.children.length < 1) {
$('#current-filters-box').hide(1000)
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="current-filters-box">
filter box
<div style="margin-bottom: 15px">
<strong>Current filters:</strong>
<div id="current-filters">
<!-- here every single applied filter is displayed -->
</div>
</div>
</div>
Without filters
s = document.getElementById("current-filters")
console.log(s.children.length);
if (s.children.length < 1) {
$('#current-filters-box').hide(1000)
}
<div id="current-filters-box">
<div style="margin-bottom: 15px">
<strong>Current filters:</strong>
<div id="current-filters">
<div class="badge-search-public">
<strong>Humanities & Languages</strong> <span class="x" data-property="disciplines" data-value="4" onclick="filter.removeFilter(this)">×</span>
</div>
<div class="badge-search-public">
<strong>January</strong> <span class="x" data-property="months" data-value="1" onclick="filter.removeFilter(this)">×</span>
</div>
</div>
</div>
Try this .
if( $('#current-filters').is(':empty') ) {
$('#current-filters-box').hide()// or $('#current-filters-box').css("display","none")
}
You are performing an assignment, try..
if (s.children.length)
Using vanilla JavaScript, you can check if the current-filters div is empty or not and toggle the parent div current-filters-box like this:
s= document.getElementById("current-filters");
t= document.getElementById("current-filters-box");
if(s.children.length<1) {
t.style.display = 'none';
// t.style.visibility= 'hidden'; <<-- use this if you want the div to be hidden but maintain space
}
else {
t.style.display = 'block';
// t.style.visibility= 'visible'; <<-- use this if you used visibility in the if statement above
}
You can achieve this by adding your own variable which counts or maintains your applied filters, e.g.
var applied_filter_count = 0;
at every time filter is applied
applied_filter_count++;
if(applied_filter_count) {
$('#current-filters-box').show()
}
and at every time filter is removed
applied_filter_count--;
if(!applied_filter_count) {
$('#current-filters-box').hide()
}
and by default current-filters-box should be display:none

How to return ONE element based on class with multiple classes

Say I have 3 divs
<div class="one"></div>
<div class="one two"></div>
<div class="one two three"></div>
<div class="one two"></div>
<div class="one"></div>
And in my js I have the following
var active = document.getElementsByClassName("one");
Which is returning all three divs. I only want the FIRST and LAST div to be called. How can this be achieved using jquery?
This can be achieved easily with javascript. Just check if the classList of a <div> is equal to just the class you want to select. If it is not equal it means that the classList contains more than one class.
function getValue()
{
var divs = document.getElementsByClassName("one");
for(var i=0; i < divs.length; i++)
{
if(divs[i].classList == 'one')
{
alert(divs[i].innerHTML);
}
}
}
<div class="one">hi</div>
<div class="one two">there</div>
<div class="one two three">coffee?</div>
<div class="one">not today?</div>
<input type="button" onclick="getValue()" value="click me" />
While you said How can this be achieved using jquery? you can use jquery like this
//$('.one:first , .one:last').css('background' , 'red'); // if you just need first one and last one
$('.one:not(.two , .three)').css('background' , 'red'); // if you need the one class but not two or three
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="one">1</div>
<div class="one two">2</div>
<div class="one two three">3</div>
<div class="one">1</div>
I'd suggest, in this case:
// finding all elements whose 'class' attribute starts with
// 'one' and also ends with 'one'
document.querySelectorAll('[class^="one"][class$="one"]');
Or, more simply:
// finding all elements whose class attribute-value is
// equal to 'one'
document.querySelectorAll('[class="one"]');
References:
Attribute selectors.
document.querySelectorAll()
Check the jQuery equals selector: http://api.jquery.com/attribute-equals-selector/. Following three possibilities:
jQuery("[class='My class1']")
$$("[class='My class1']")
$("[class='My class1']").

Reorder divs in javascript without jquery

lets say I have html:
<div id="1">1</div>
<div id="2">2</div>
<div id="3">3</div>
how would I in javascript and not jquery reorder these divs to:
<div id="1">1</div>
<div id="3">3</div>
<div id="2">2</div>
You can use display:flex and the order css (I had to add a letter before the number for your id as SO didn't seem to like it for the css)
.container {display:flex; flex-direction:column}
#s1 {order:1;}
#s2 {order:3;}
#s3 {order:2;}
<div class="container">
<div id="s1">1</div>
<div id="s2">2</div>
<div id="s3">3</div>
</div>
More information about order
More information about flex
Update
Sorry read the question wrong - thought you wanted to do it without js
var div = document.getElementById('3')
div.parentNode.insertBefore(div, document.getElementById('2'))
<div id="1">1</div>
<div id="2">2</div>
<div id="3">3</div>
The solution given by the duplicate questions are incorrect because they make the assumption that the elements are next to each other. But even in this simple example, there is a text node containing white-space between the elements.
Given that the two elements are not nested, you can use this to swap two elements:
function swapElements (first, second) {
var tmpNode = document.createElement('div');
tmpNode.setAttribute('id', '_tmp');
var firstParent = first.parentNode;
firstParent.insertBefore(tmpNode, first);
second.parentNode.insertBefore(second, first);
firstParent.insertBefore(second, tmpNode);
firstParent.removeChild(tmpNode);
}
Use it like:
var first = document.querySelector('#1');
var second = document.querySelector('#2');
swapElements(first, second);

jQuery Insert closing div tag and opeing div tag after count

I am trying to get jquery to close a div and inset an opening div with a class after x amount of items.
Here is what I have tried:
$(this).after('</div> <div class=\"bar">Bar');
it outputs:
<div class="bar">Bar</div>
What I need is:
<div class="item2">
<div class="CountThese2"> Count Me </div>
<div class="CountThese2"> Count Me </div>
</div>
<div class="bar">
<div class="CountThese2"> Count Me </div>
<div class="CountThese2"> Count Me </div>
</div>
<div class="bar">
<div class="CountThese2"> Count Me </div>
<div class="CountThese2"> Count Me </div>
</div>
<div class="bar">
<div class="CountThese2"> Count Me </div>
<div class="CountThese2"> Count Me </div>
</div>
http://jsfiddle.net/yoderman94/JEtj2/
You can't add half a tag. I think what you're trying to do is wrap the elements. Your fiddle is pretty messy, but here's a simple example of how you can do that:
http://jsfiddle.net/9Q62H/
while($('#wrapper > a:lt(2)').wrapAll('<div class="bar">bar</div>').length) { }
Which turns this:
<div id="wrapper">
1
1
1
1
1
1
1
1
</div>
into this:
<div id="wrapper">
<div class="bar">bar
1
1
</div>
<div class="bar">bar
1
1
</div>
<div class="bar">bar
1
1
</div>
<div class="bar">bar
1
1
</div>
</div>
You can't manipulate the DOM that way, with or without jQuery. To accomplish the same thing, insert a new div after the current div's parent, and then move all of the current div's following siblings to the new div:
var bar = $("<div>").addClass("bar").text("Bar");
bar.insertAfter($(this).parent());
bar.append($(this).nextAll());
Edit: To preserve text nodes, including the whitespace between your links, it's not quite as simple as $(this).nextAll(), sadly. You need to use .contents() to select the text nodes, then slice at the index of this:
var contents = $(this).parent().contents();
var bar = $("<div>").addClass("bar").text("Bar");
bar.insertAfter($(this).parent());
bar.append(contents.slice(contents.index(this) + 1));
http://jsfiddle.net/JEtj2/6/
I'm going to recommend a different approach here. When you call .after() you need to be giving it a complete open and close tag. You cannot open a tag then close it later like you are trying to above.
My advice would be to try and take an approach like the following, so you can pass a complete open and close tag to .after()
var theDiv = "<div class='bar'>";
for(var i = 0; i < 2; i++) {
theDiv += '<div class="CountThese2"> Count Me </div>';
}
theDiv += "</div>";
$('#thing').after(theDiv);
See how I constructed the whole div including contents before calling .after() ?

Jquery tranversing DOM to find consecutives values

Thanks for looking, all helpful answers are voted up.
This is my markup. I'm trying to find 2 consecutive divs cmk1 and cmk2 with the content RIGHT and HERE in consecutive order.
div id 1 shouldn't match because there's a right but not here.
div id 3 shouldn't match because there's a here but no right.
I'm trying to find something that looks like div id 2 where right is followed by here. Also the text has to be exact: <div>more than right</div> should not match even though it contains the word right
What's the most efficient way to do this?
Update: I just had a thought, I could find each class=cmk1. if it matches RIGHT, I could select its next (cmk2) and if it matches also, that's what I'm looking for. But how do I do this while loop in jquery? and most importantly how do I exit out of it?
<div class="sep" id="1">
<div class="cmk1">right</div>
<div class="cmk2">valc</div>
<div class="opp">vald</div>
<a class="go">Go</a>
</div>
<div class="clear">
<div class="sep" id="12">
<div class="cmk1">RIGHT</div>
<div class="cmk2">HERE</div>
<div class="opp">vala</div>
<a class="go">Go</a>
</div>
<div class="clear">
<div class="sep" id="59">
<div class="cmk1">vale</div>
<div class="cmk2">valf</div>
<div class="opp">here</div>
<a class="go">Go</a>
</div>
<div class="clear">
$('div.sep > div').each(function() {
if($(this).text() == 'RIGHT') {
if($(this).next('div').text() == 'HERE') {
alert('Values occur consecutively in div id: ' + $(this).parent().attr('id'));
return false;
}
}
});
I've basically looped over all the child divs of the each .sep div and tested for the first word. If it is matched, next can be used to determine if the next div contains the second word.
$(':contains(RIGHT) :contains(HERE)')
Try:
$(':contains(right), :contains(here)')
.filter( function() {
return ( $(this).text() == 'right' && $(this).next().is(':contains(here)') ) ||
( $(this).text() == 'here' && $(this).prev().is(':contains(right)') );
} );
The only drawback is this is case sensitive.

Categories

Resources