I want to find div element that contain custom attribute mod than append that div to list item. But first I have to remove divs that contain duplicate mod value. Here's what I have done
<div class="list"></div>
<div class="container">
<div mod="dog"></div>
<div mod="man"></div>
<div mod="woman"></div>
<div mod="dog"></div>
<div mod="bird"></div>
<div mod="insects"></div>
<div mod="dog"></div>
</div>
this is my script
modArr($('.container').find('[mod]'))
function modArr(el){
var filterArray = [] // store mod
, modNames = [] // store mod value
, arrIndex = [] // store non duplicate index
, li = [] // store
modArray = el
// store mod value
for(var i=0; i < modArray.length; i++){
modNames.push($(modArray[i]).attr('mod')) // get mod value from div
}
// search for non duplicate mod value and get the index of none duplicate mod
for(var i=0; i < modArray.length; i++){
if(filterArray.indexOf(modNames[i]) === -1){
filterArray.push(modNames[i])
arrIndex.push(i) // push non duplicate index value
}
}
filterArray = [] // reset filterArray
// push module from modArray to filterArray using index in arrIndex
for(var i=0; i < arrIndex.length; i++){
filterArray.push(modArray[arrIndex[i]])
}
// push to li array
$.each(filterArray,function(i,el){
li[i] = '<li>'+ el.outerHTML +'</li>'
})
$('<ul></ul>')
.append(li.join(''))
.appendTo('.list')
}
What you can see is that I've used to many loops, is there any simple way to do this. Thanks!
We can use an object as a map for checking duplicates, see comments (I've added text to the mod divs so we can see them):
modArr($('.container').find('[mod]'));
function modArr(elements) {
// A place to remember the mods we've seen
var knownMods = Object.create(null);
// Create the list
var ul = $("<ul></ul>");
// Loop the divs
elements.each(function() {
// Get this mod value
var mod = this.getAttribute("mod");
// Already have one?
if (!knownMods[mod]) {
// No, add it
knownMods[mod] = true;
ul.append($("<li></li>").append(this.cloneNode(true)));
}
});
// Put the list in the .list element
ul.appendTo(".list");
}
<div class="list"></div>
<div class="container">
<div mod="dog">dog</div>
<div mod="man">man</div>
<div mod="woman">woman</div>
<div mod="dog">dog</div>
<div mod="bird">bird</div>
<div mod="insects">insects</div>
<div mod="dog">dog</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
We can also just use the DOM to check for duplicates, but it's a bit slower (not that it matters for the number of elements here):
modArr($('.container').find('[mod]'));
function modArr(elements) {
// Create the list
var ul = $("<ul></ul>");
// Loop the divs
elements.each(function() {
// Get this mod value
var mod = this.getAttribute("mod");
// Already have one?
if (ul.find('div[mod="' + mod + '"]').length == 0) {
// No, add it
ul.append($("<li></li>").append(this.cloneNode(true)));
}
});
// Put the list in the .list element
ul.appendTo(".list");
}
<div class="list"></div>
<div class="container">
<div mod="dog">dog</div>
<div mod="man">man</div>
<div mod="woman">woman</div>
<div mod="dog">dog</div>
<div mod="bird">bird</div>
<div mod="insects">insects</div>
<div mod="dog">dog</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Note: I used this.cloneNode(true) rather than outerHTML because there's no need to take a roundtrip through markup. If you want more jQuery there, it's $(this).clone(); ;-) Similarly, if you don't like this.getAttribute("mod"), there's $(this).attr("mod").
I'd be remiss if I didn't point out that mod is an invalid attribute name for div elements. You can use any name you want starting with data-, though, so perhaps use <div data-mod="dog"> instead.
Try this, only adds if an element with mod is not already in list:
$('.list').append('<ul>');
$('.container [mod]').each(function(index, el) {
if($('.list [mod=' + $(el).attr('mod') + ']').length === 0) {
$('.list ul').append($('<li>' + el.outerHTML + '</li>'));
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="list"></div>
<div class="container">
<div mod="dog">Dog1</div>
<div mod="man">Man1</div>
<div mod="woman">Woman1</div>
<div mod="dog">Dog2</div>
<div mod="bird">Bird1</div>
<div mod="insects">Insect1</div>
<div mod="dog">Dog3</div>
</div>
Related
I have a list of table columns. I would like to display them in one row.
What am I trying is :
for (var i = 0; i < key.length; i++) {
writeToScreen3('<div class="col-sm">' + key[i] + '</div>'); //column name
}
function writeToScreen3(message) {
var pre = document.createElement("p"); //I realize I am creating another element <p> How to do it diffrently?
pre.innerHTML = message;
output.appendChild(pre);
}
What I need is this transferred to JavaScript :
<div class="container">
<div class="row">
<div class="col-sm">
One of three columns
</div>
<div class="col-sm">
One of three columns
</div>
<div class="col-sm">
One of three columns
</div>
</div>
</div>
What I also tried :
function test8() {
$("#output").html('<div class="container">< div class= "row" >'); //but it always closes these 2 divs here . I want it not to close it. output is a div field
}
You can do something like this:
function createContainer(columns) {
function createDivWithClass(cls) {
const div = document.createElement('div');
div.classList.add(cls);
return div;
}
const container = createDivWithClass('container');
const row = createDivWithClass('row');
container.appendChild(row);
for (let i = 0; i < columns.length; i++) {
const column = createDivWithClass('col-sm');
column.textContent = columns[i];
row.appendChild(column);
}
return container;
}
const container = createContainer([1, 2, 3, 4]);
document.getElementById('output').appendChild(container);
console.log(container.outerHTML);
<div id="output"></div>
Here, I've defined a function called createDivWithClass to make it easier to create a <div> and set a class name to it.
Then, I'm using this function to create a <div class="container">, create a <div class="row"> and add that to the container, and then go through the columns array and create <div class="col-sm"> and add those to the row element.
Just like you can append elements to the #output element in the DOM, you can also append elements to elements that you've created and are not yet in the DOM.
Hope I can explain well.
So I have 8 boxes with class .boxA with a numeric value generated from js:
<div class="tfooter">
<div class="boxA" id="bx3" value="3">3</div>
<div class="boxA" id="bx27" value="27">27</div>
<div class="boxA" id="bx46" value="46">46</div>
<div class="boxA" id="bx40" value="40">40</div>
<div class="boxA" id="bx42" value="42">42</div>
<div class="boxA" id="bx29" value="29">29</div>
<div class="boxA" id="bx13" value="13">13</div>
<div class="boxA" id="bx1" value="1">1</div>
</div>
First of all I push all values in a array:
var randomnumber = Math.ceil(Math.random()*50);
var array = [];
$(".boxA").each(function(){
var dNumber = $(this).attr('value');
array.push(dNumber);
});
Each of this boxes contain a random number from 1 to 50.
Now, I want to generate another random number and check if exists in the array. If exists, generate another number until it's unique in that array. When is unique, create another div.
I've tryed with indexOf, with inArray, with while, but I can't get it working. The problem is that generate. Generate new number until not in array.
Thank you very much!
You could avoid the trial-and-error method by first building an array with the allowed values (i.e. those that do not appear in the list), and then pick a random value from that.
Here is a snippet that will add a new (non-used) number at the top of the list at the press of a button:
function getUsedNumbers() {
return $(".boxA").map(function(){
return +$(this).attr('value');
}).get();
}
function getCandidates(exclude) {
// Generate a list of values from 0 to 49, and make it a Set
// (Sets allow for faster look-up and value removal)
var candidates = new Set(Array(50).keys());
for (value of exclude) {
// Remove the already used value from our Set:
candidates.delete(value);
}
// Convert Set back to array and return it:
return [...candidates];
}
function pickRandomly(array) {
return array[Math.floor(Math.random()*array.length)];
}
$('#add').click(function () {
var used = getUsedNumbers();
var candidates = getCandidates(used);
// Safety:
if (!candidates.length) {
alert('No more candidate values available');
return;
}
var choice = pickRandomly(candidates);
// Insert the selected number at the top of the list:
$(".tfooter").prepend(
$("<div>").addClass("boxA").text(choice).attr({
id: "bx"+choice, value: choice
})
);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="add">Add</button>
<div class="tfooter">
</div>
If you do this repeatedly, then it is not so efficient to re-read the list of values from the page each time, since you actually know what is there already.
Consider making the candidates Set the master reference for your data, and only depend on that to generate the output.
You need to use $.inArray() to check if the random number exists in an existing array or not. if the number doesn't exist, it adds that random number to the array. Below is an updated code:
$("#generateNewNumber").on('click', function() {
var newArray = [];
$(".boxA").each(function() {
newArray.push(parseInt($(this).attr('value')));
});
var randomNumber = Math.ceil(Math.random() * 50);
console.log('Random number is: ' + randomNumber);
if ($.inArray(randomNumber, newArray) !== -1) {
console.log(randomNumber + ' exisits in array');
} else {
newArray.push(parseInt(randomNumber));
$(".tfooter").append('<div class="boxA" id="bx' + randomNumber + '" value="' + randomNumber + '">' + randomNumber + '</div>')
console.log(randomNumber + " doesn't exisits in array, hence adding in an array.");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="generateNewNumber">Generate Random Number</button>
<div class="tfooter">
<div class="boxA" id="bx3" value="3">3</div>
<div class="boxA" id="bx27" value="27">27</div>
<div class="boxA" id="bx46" value="46">46</div>
<div class="boxA" id="bx40" value="40">40</div>
<div class="boxA" id="bx42" value="42">42</div>
<div class="boxA" id="bx29" value="29">29</div>
<div class="boxA" id="bx13" value="13">13</div>
<div class="boxA" id="bx1" value="1">1</div>
</div>
Here is how I would had set up the code:
Create the array with numbers 1-50 in it.
Create a random number based on the list's length.
Randomly splice a position. That position will then be removed from the array but return a an array with one item.
If the array is empty (length 0), start over at 1.
Then you don't need to check if the number exists, because it has already been removed from the array.
function createBoxNumbersArray(startNumber, endNumber) {
var boxNumbers = [];
for (var i = startNumber; i <= endNumber; i++) {
boxNumbers.push(i);
}
return boxNumbers;
}
function getRandom(boxNumbers) {
position = Math.floor((Math.random() * boxNumbers.length-1));
return boxNumbers.splice(position, 1)[0];
}
var boxNumbers = createBoxNumbersArray(1, 50);
var randomBoxNumber = getRandom(boxNumbers);
Seems like indexOf would be the way to go. Your problem is that you're probably comparing the HTML attribute value (a string) to the random number (a number).
so, once you update to:
array.push(parseInt(dNumber));
You will be able to check
if(array.indexOf(randomnumber) >= 0) { } // regenerate random
So... I have four divs on a page. All four of them belong to the class foobar. What I wanna do here is give each of them a value from a certain Array in JavaScript. Do note I am using jQuery 3.2.1.
My JavaScript:
var $elements = jQuery.makeArray($(".foobar"));
[1,2,3,4].forEach(function (x) {
$elements.forEach(function (y) {
y.text(x.toString());
});
});
My HTML:
<div class="foobar"></div>
<div class="foobar"></div>
<div class="foobar"></div>
<div class="foobar"></div>
And as always, it does not work. Basically what I wanna do here is give each Number in that Array as the text() for each div.
You are setting the same text to every element inside inner loop. Try this
var $elements = $(".foobar");
[1,2,3,4].forEach(function (x, i) {
$($elements[i]).text(x)
});
Or use .text(func)
var texts = [1,2,3,4];
var $elements = $(".foobar").text(function(i) {
return texts[i];
})
Check this fiddle. https://jsfiddle.net/bj3s92gr/
Bassicaly you have to bucle the divs with class foobar, and assing the position of the array in the html.
var $elements = $(".foobar");
$arr = [1,2,3,4];
$elements.each(function(e){
$(this).html($arr[e]);
});
Create an array of numbers, traverse thru all the .foobar elements, and assign a value from the array.
var $elements = jQuery.makeArray($(".foobar"));
var numbers = [1, 2, 3, 4];
var count = 0;
$(".foobar").each(function() {
$(this).text(numbers[count]);
count++;
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
My HTML:
<div class="foobar"></div>
<div class="foobar"></div>
<div class="foobar"></div>
<div class="foobar"></div>
I have several divs that looks like this:
<div class='popupDiv' data-layergroup='layer1'>divcontent 1</div>
<div class='popupDiv' data-layergroup='layer1'>divcontent 2</div>
<div class='popupDiv' data-layergroup='layer2'>divcontent 3</div>
<div class='popupDiv' data-layergroup='layer2'>divcontent 4</div>
I'm a bit stumped as to how to loop through all popupDiv divs, and then loop through each layergroup separately. I want to end with a single array for each layergroup. I'd need something like:
var mainArray = [];
$('.popupDiv').each(function(){
var tempArray = [];
$([unique layer value]).each(function(){
// Put div values from layergroup in tempArray
});
mainArray.push(tempArray);
});
return mainArray;
But I don't know the syntax I'm looking for. What do I do?
<div class='popupDiv' data-layer='layer1'></div>
<div class='popupDiv' data-layer='layer1'></div>
<div class='popupDiv' data-layer='layer2'></div>
<div class='popupDiv' data-layer='layer2'></div>
Loop through the elements
$('.popupDiv[data-layer]').each(function(){
});
to loop through each group seperately, you can use below logic
//create an array to store processed data-layer type
var dataArray = new Array();
$('.popupDiv').each(function(){
var dataLayer = $(this).data('layer');
//check if data-layer already processed
if(!dataArray.indexOf(dataLayer))
{
//update data array
dataArray.push(dataLayer);
$('.popupDiv[data-layer="'+ dataLayer +'"]').each(function(){
//do your stuff here
});
}
});
You can loop through each of the div having attribute 'data-layer' as follows:
$('.popupDiv').each(function(i) {
if ($(this).attr('data-layer') == 'layer' + i + 1) {
$(this).each(function() {
alert($(this).attr('data-layer'));
//change this to whatever you want
});
}
});
So this will check for 'layer1', 'layer2' and so on.
You do not need two each loops here. You can use Has Attribute Selector. you are also having duplicate IDs for divs. IDs should be unique, use class name instead:
$('[data-layergroup]').each(function(){
// Do stuff with each div
console.log($(this).data('layergroup'));//current data layer value
});
For iterating over the values(FYI-BAD APPROACH):
$.each($("[data-layergroup]").map(function() { return $(this).data('layergroup');}).get(), function(index, item) {
// item
});
use class instead of id:
<div class='popupDiv' data-layer='layer1'></div>
<div class='popupDiv' data-layer='layer1'></div>
<div class='popupDiv' data-layer='layer2'></div>
<div class='popupDiv' data-layer='layer2'></div>
Then you can loop each layer seperatly:
for (var i = 1; i <= 2; i++) {
$(".popupDiv[data-layer|='layer"+i+"']").each(function(){
// do stuff with layer i
});
}
I am having a bunch of div tags in my html page. Now I need to write a jQuery to calculate the grid's value. In the below example I will be using grid0 as the base id and I want the count in that series which is 1 here.
<div id="grid00">0</div>
<div id="grid01">0</div>
<div id="grid02">0</div>
<div id="grid03">1</div>
<div id="grid04">0</div>
<div id="grid05">0</div>
In another example given below I will be using id's starting with grid1 and the total value is 6. Please guide me!
<div id="grid10">5</div>
<div id="grid11">0</div>
<div id="grid12">0</div>
<div id="grid13">1</div>
<div id="grid14">0</div>
<div id="grid15">0</div>
I tried this jQuery("div[id^='grid0']"). But this is giving me all the elements. But I need the count using the value inside them.
Thanks!
Start by selecting the divs with the starts-with selector and loop through the results and tally up the text values casted to integers.
function GetSum(prefix) {
var sum = 0;
$("div[id^='" + prefix + "']").each(function(){
sum += parseInt($(this).text());
});
return sum;
}
var grid0Total = GetSum("grid0");
var grid1Total = GetSum("grid1");
Or if you wanted to take it a step further with a jQuery function:
jQuery.extend({
gridSum: function(prefix) {
var sum = 0;
if(!!prefix) {
$("div[id^='" + prefix + "']").each(function(){
sum += parseInt($(this).text());
});
}
return sum;
}
});
then you could write:
var grid0Total = jQuery.gridSum("grid0");
var grid1Total = jQuery.gridSum("grid1");
You could also use the map() function like so:
var sum = 0;
$("div[id^='" + prefix + "']").map(function(){
return sum += parseInt($(this).text());
});
return sum;
See them all in action here: http://jsfiddle.net/FpmFW/1/
Try:
function total(idPrefix) {
var total = 0;
$('div[id^="' + idPrefix + '"]').each(function() {
total += parseInt($(this).text());
});
return total;
}
var grid0total = total('grid0'),
grid1total = total('grid1');
See: http://jsfiddle.net/Au8Fr/
I'd give all grid divs one commmon class. Something like this:
<div class="grid" id="myGrids">
<div class="grid" id="grid10">5</div>
<div class="grid" id="grid11">0</div>
<div class="grid" id="grid12">0</div>
<div class="grid" id="grid13">1</div>
<div class="grid" id="grid14">0</div>
<div class="grid" id="grid15">0</div>
</div>
Now you can easily count their values:
var count=0;
$(".grid").each(function(){
count+=parseInt($(this).text())
})
You can loop through all of your grid0X divs like this:
var countOnes = 0;
$('div[id^=grid0]').each(function() {
if ($(this).text() === "1") {
++countOnes;
}
});
That finds all div elements whose ID starts with grid0 (so, grid00, grid01, etc.). The loop counts how many of them contain just the text "1", which is what I think you were after in your question; if not, the loop logic is easily manipulated.
Similarly, for grid1X, just change the selector to use 1 instead of 0.
Alternately, though, if these divs are in some kind of container, you could use a selector to find the container and then loop through its children, e.g.:
HTML:
<div id="grid0">
<div>0</div>
<div>0</div>
<div>0</div>
<div>1</div>
<div>0</div>
<div>0</div>
</div>
JavaScript:
$("#grid0 > div").each(...);
...and avoid having all those IDs.