separate groups of images with jQuery - javascript

Goal is to create a image-carousel with 7 images in a row.
I'm reading data from a json-file. This all works fine.
What I do not get working is a loop that separates groups of 7 images in separate as per example below. Any advice is greatly appreciated for this jQuery-beginner.
<div class='active item'>
Image-1
Image-2
Image-3
Image-4
Image-5
Image-6
Image-7
</div>
<div class='item'>
Image-8
Image-9
Image-10
I tried with two things:
insertBefore
$.each(data.items, function(index, element) {
var myString = $('<div></div>');
if (index % 7 == 0) {
$("<p>Test</p>").insertBefore(".span2");
}
myString.append($('<div class="span2">')
.append($("<a href=" + index + " class='thumbnail'>"))
.append("<img src=http://0.0.0.0:3000/images/col/tn/" + element.imgf + " alt='Image' style='max-width:100%;'/>")));
myString.appendTo('#show-carousel');
if /else
$.each(data.items, function(index, element){
var myString = $('<div></div > ');
if (index % 7 == 0) {
myString.append("<div class='item'>");
myString.append($("<div class='row-fluid'>")
.append($(' < div class="span2"> ')
.append($("<a href="+index+" class='thumbnail'>")
.append("<img src=http://0.0.0.0:3000/images/col/tn/"+element.imgf+" alt='Image' style='max-width: 100%;'/>"))));
}
else {
myString.append($('<div class="span2">')
.append($("<a href="+index+" class='thumbnail'>")
.append("<img src=http://0.0.0.0:3000/images/col/tn/"+element.imgf+" alt='Image' style='max-width: 100%;'/>")));
}
myString.appendTo('#show-carousel');

You can extract the functionality of executing a callback for a certain portion of an array into a helper function.
// function that executes a callback for a portion of an array
function forEachArrayGroup(arr, start, end, fn) {
if (end > arr.length) end = arr.length; // normalize for out of bounds
for (let i = start; i < end; i++) {
fn(arr[i], i);
}
}
This would allow you to separate the logic of splitting data into portions from adding data to the DOM:
for (let i = 0; i < items.length; i += 7) {
// we create an item that will hold the portion
const $item = $('<div class="item"></div>');
// append the group to the current item
forEachArrayPortion(items, i, i + 7, function(dataItem, index) {
// this executes for each item in the group
const $imgWrapper = // create the a, img and rest
$item.append($imgWrapper);
});
}
Here's a full example:
const data = { items: Array.from({ length: 18 }, (_, i) => i).map(() => ({ imgf: 'i_am_fake' })) };
function forEachArrayGroup(arr, start, end, fn) {
if (end > arr.length) end = arr.length; // normalize for out of bounds
for (let i = start; i < end; i++) {
fn(arr[i], i);
}
}
function displayItemsInGroups(items, groupSize) {
for (let i = 0; i < items.length; i += groupSize) {
// this executes for each group of `partSize` number of items
// we create an item that will hold the group
const $groupItem = $('<div class="item"></div>');
// make sure the first item is active
if (i === 0) {
$groupItem.addClass('active');
}
// create the row that will contain the image groups
const $groupRow = $("<div class='row-fluid'>");
// add group row to the current item
$groupRow.appendTo($groupItem);
// add current item to the carousel
$groupItem.appendTo('#show-carousel');
// append the group to the current row
forEachArrayGroup(items, i, i + groupSize, function(dataItem, index) {
// this executes for each item in the group
const $imgWrapper = $('<div class="span2">')
.append($("<a href=" + index + " class='thumbnail'>")
// fake image
.append("<div class="+dataItem.imgf+">Image "+(index+1)+"</div>"));
$groupRow.append($imgWrapper);
});
}
}
displayItemsInGroups(data.items, 7);
.item {
padding: 10px;
border: 1px solid #aaa;
margin-bottom: 1px;
}
.item.active {
border-color: #018bbc;
background-color: lightblue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="show-carousel"></div>

If I understand you correctly, you are trying to separate the images in groups of 7. To do this, you are on the correct path by using Modulus.
I would test to see when your loop index mod seven equals zero and then append a div group. Check out the code below.
var $carousel = $('#show-carousel'),
$item,
myArr = [],
i;
// populate our array with some fake data.
for (i = 0; i < 15; i++) {
var imgInfo = {
imgf: 'image' + (i + 1) + '.jpg'
};
myArr.push(imgInfo);
}
// loop through the array and add your items to your element
$.each(myArr, function(index, obj) {
if (index % 7 === 0) {
// create a div that will hold your images
$item = $('<div class="item"></div>');
// append this div to our carousel element
$carousel.append($item);
}
// $item is a reference to the last created div
$item.append('<div class="span2"><img src="http://0.0.0.0:3000/images/col/tn/' + obj.imgf + '" alt="Image" style="max-width:100%;"></div>');
});
$('.item:eq(0)').addClass('active');
#show-carousel .item {
display: none;
padding: 5px;
margin: 5px;
border: 1px solid red;
}
#show-carousel .item.active {
display: block;
}
#show-carousel .item .span2 {
display: inline-block;
width: 50px;
height: 50px;
padding: 5px;
margin: 5px;
border: 1px solid grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="show-carousel"></div>
*edit: updated code to better reflect what you had in your example.

Related

How to build a table on HTML page which is pushed as list?

I am trying to show .csv content on a page as a table. The list includes unknown rows and columns that depends on the user. It is not a fixed type like 2x2 or 3x4.
But I got something like the following;
[
[
&
#
x
2
7
;
x
x
.......
I am redirecting a list and also tried json. The content of the list is not fixed. The length and column side are dependable. I am trying to pass data properly and show as table
return list;
return render(request, 'yuklenen.html', {'veriler': yuklenen, 'file': listx })
I want to show it as
<div id="contain"></div>
Here's the code:
<script>
var str = '<ul>';
var data1 = "{{file}}" ;
for(var x in at){
str+='<li>' + at[x] + '<li>';
}
str += '</ul>';
document.getElementById("contain").innerHTML = str;
</script>
Hope this will get you started:
function rand(min, max)
{
return Math.round(Math.random() * (max - min) + min);
}
function update()
{
const at = [];
for(let x = 0; x < rand(3, 10); x++)
{
const c = [];
for(let y = 0; y < rand(1, 10); y++)
{
c[y] = rand(0, 100);
}
at[x] = c;
}
var str = '<ul>';
for(var x in at){
str+='<li>';
for(var y in at[x])
str += "<span>" + at[x][y] + "</span>";
str+='</li>';
}
str += '</ul>';
document.getElementById("contain").innerHTML = str;
}
update();
ul
{
display: table;
border-collapse: collapse;
}
li
{
display: table-row;
}
li > span
{
border: 1px solid black;
vertical-align: middle;
text-align: center;
display: table-cell;
width: 2em;
height: 2em;
}
<button onclick="update()">update</button>
<div id="contain"></div>

How to get rid of extra bullets in my unordered list?

Hi I am printing an array to my DOM using an input method. I can get the user input to print out the list, but there are too many bullets. Here is my code below:
function addPokemon() {
var pokemonName = document.getElementById("pokemon-name-container");
pokemonName.innerHTML = document.getElementById("pokemon-names").value;
for (var i = 0; i < element.length; i++) {
if (typeof element[i].value !== "undefined") {
pokemonArray.push(element[i].value);
}
}
console.log(pokemonArray);
for (var i = 0; i < pokemonArray.length; i++) {
document.getElementById("pokemon-container").innerHTML += "<li>" + pokemonArray[i] + "<li>";
}
}
var pokemonArray = [];
var element = document.getElementsByClassName("move-container");
How can this be fixed?
Added what element was for those asking
To close <li>, you need a /,
document.getElementById("pokemon-container").innerHTML += "<li>" + pokemonArray[i] + "</li>";
What's happening is that the browser autocloses your first <li> as soon as it sees the other <li>. Then it treats that other <li> as another item, auto-closing that as well.
The issue is that you did not close your list item element before you started to append another one.
.innerHTML += "<li>" + pokemonArray[i] + "<li>"; // The 2nd one not closing...
It is implicitly creating an empty list item after each of the ones you want.
Example
I made up the DOM, because you did not provide it.
const pokemonArray = [];
const element = document.querySelectorAll('.pokemon');
addPokemon();
function addPokemon() {
var pokemonName = document.getElementById("pokemon-name-container");
pokemonName.innerHTML = document.getElementById("pokemon-names").value;
for (var i = 0; i < element.length; i++) {
if (typeof element[i].value !== "undefined") {
pokemonArray.push(element[i].value);
}
}
console.log(pokemonArray);
for (var i = 0; i < pokemonArray.length; i++) {
document.getElementById("pokemon-container").innerHTML += "<li>" + pokemonArray[i] + "</li>";
}
}
<input type="input" id="pokemon-names" />
<input type="text" class="pokemon" value="Bulbasaur" />
<input type="text" class="pokemon" value="Charmander" />
<input type="text" class="pokemon" value="Squirtle" />
<ul id="pokemon-name-container"></ul>
<ul id="pokemon-container"></ul>
Using JavaScript to manipulate the DOM
A better way to do this would be to to create the DOM elements in JavaScript and append them to the container. You could also store a state and re-render the list every time you add a new Pokémon.
const POKEMON_NAMES = [ 'Bulbasaur', 'Charmander', 'Squirtle' ];
const state = {
pokemon: []
};
let sel = document.querySelector('.available-pokemon');
sel.appendChild(new Option('', ''));
POKEMON_NAMES.forEach(name => sel.appendChild(new Option(name, name)));
sel.addEventListener('change', addPokemon);
function addPokemon(e) {
let selectedPokemon = e.currentTarget.value;
if (selectedPokemon.length > 0 && !state.pokemon.includes(selectedPokemon)) {
state.pokemon.push(selectedPokemon);
renderPokemonList();
}
}
function renderPokemonList() {
let container = document.querySelector('.pokemon-container');
emptyElement(container);
state.pokemon.sort().forEach(pokemon => {
let listItem = document.createElement('LI');
listItem.textContent = pokemon;
container.appendChild(listItem);
});
}
function emptyElement(element) {
while (element.firstChild) {
element.removeChild(element.lastChild);
}
}
.pokemon-container {
border: thin solid grey;
min-height: 1em;
width: 50%;
padding: 0.5em 2em;
}
<select class="available-pokemon"></select>
<ul class="pokemon-container"></ul>

Ignore Whitespace-only Array Elements

I have many comma separated strings, each of which consists of a list of tags, and I want to style each tag inside a box (see here).
I converted each comma separated string ("p") into an array, then wrapped <span> tags around each value in the array, so I could style it with CSS, which worked great.
But whitespace strings are also getting wrapped in span tags which I do not want, I want to ignore those (or hide them).
How do I ignore those occurrences of "p" which contain only whitespace? The answers here and here but didn't work for me.
HTML:
<p>Skill 1, Skill 2, Skill 3</p>
<p>Skill 1</p>
<p> </p>
Javascript:
$("p").each(function() {
var words = $(this).text().split(", ");
var total = words.length;
$(this).empty();
for (index = 0; index < total; index++) {
$(this).append($("<span class = 'tag' > ").text(words[index]));
}
})
CSS:
.tag {
background-color: lightgray;
padding: 3px;
margin: 3px;
border-radius: 3px;
}
JS Fiddle
Just check to see if the trimmed text is truthy first. Also make sure not to implicitly create global variables, always declare variables with const (or let or var) before using them, otherwise errors will be thrown in strict mode:
if (words[index].trim()) {
$(this).append($("<span class = 'tag' > ").text(words[index]));
}
// Converts comma separated string into tags
function convertToTags(s) {
$(s).each(function() {
var words = $(this).text().split(", ");
var total = words.length;
$(this).empty();
for (let index = 0; index < total; index++) {
if (words[index].trim()) {
$(this).append($("<span class = 'tag' > ").text(words[index]));
}
}
})
}
// Calls the function on document ready
$(document).ready(function() {
convertToTags("p");
});
.tag {
background-color: lightgray;
padding: 3px;
margin: 3px;
border-radius: 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>This, is, a, test</p>
<p>This</p>
<p> </p>
You need to apply your function only to the relevant elements.
In the following example I've used this condition:
$(this).text().trim().length > 0
$("p")
.each(function() {
const text = $(this).text().trim();
// This condition will make sure that "empty" p elements won't be affected
if (text.length > 0) {
var words = $(this).text().split(", ");
var total = words.length;
$(this).empty();
for (index = 0; index < total; index++) {
$(this).append($("<span class = 'tag' > ").text(words[index]));
}
}
})
.tag {
background-color: lightgray;
padding: 3px;
margin: 3px;
border-radius: 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Skill 1, Skill 2, Skill 3 </p>
<p>Skill 1</p>
<p> </p>
function convertToTags(s) {
$("p").each(function() {
var text = $(this).text();
if(!text.replace(/ /g, '')){
$(this).remove();
return;
}
var words = text.split(", ");
var total = words.length;
$(this).empty();
for (index = 0; index < total; index++) {
$(this).append($("<span class = 'tag' > ").text(words[index]));
}
})
}
Magic lies in the first 2 statements within .each function. Before doing the split, we will check if there is anything else in this paragraph other than whitespace(s).
If not, remove this paragraph and start the next iteration.

Append string to specific div only once if same div is used throughout DOM

I'm working on building a portfolio site and I'm pulling content from a JSON file. It's working, but I'm having a hard time generating the content only one time. I'm creating a div with the project type's name, and then adding container and row inside to make it work with Bootstrap. Then, I'm going through the projects and pulling the data, and creating a new div inside row that's called port-card, and port-card will contain the data. It's working, but in my for loop I'm using jQuery's append and it's appending the data to EVERY single row, which means I'm adding the data twice (or however many rows there currently are) instead of just one time.
EDIT: Thanks to T.J. Crowder, I tried using .eq(n) and I've added a runnable snippet below. Now I'm trying to figure out how to keep the generated data in the first wordpress-plugins div rather than having the second iteration of the for loop add it to the second div.
var catList = ["WordPress Plugins", "Websites"];
var categories = [{cat: "WordPress Plugins", title: "Price Quote Plugin"}, {cat: "WordPress Plugins", title: "House Plan Search"}];
for (var i = 0; i < catList.length; i++) {
temp = catList[i];
temp = temp.replace(/\s+/g, '-').toLowerCase();
$('.projects').append('<div class="' + temp + '"><div class="container"><div class="row"></div></div></div>');
}
if ($('.wordpress-plugins')[0]) {
var rows = $(".row");
for (var i = 0; i < categories.length; i++){
var catNameTemp = categories[i].cat;
var projectTitle = categories[i].title;
if(catNameTemp == "WordPress Plugins"){
rows.eq(i).append('<div class="port-card"><h3>' + projectTitle + '</h3></div>');
}
}
}
.projects {
text-align: center;
margin-top: 5%;
}
.port-card {
background-color: #333;
width: 400px;
height: 800px;
}
h3 {
color: #fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="projects">
</div>
$('.row') will create a jQuery set with all elements with class row in it. If you want to access just a single element in that set, you can use .eq(n) to do so (n = the index, starting with 0).
So for instance, if you have as many rows as categories, you might do:
var rows = $(".row");
...before the loop, then rows.eq(i).append(...) within the loop.
Looking at the runnable snippet you added, you don't have a row-per-category, so the above wouldn't apply. See comments in the snippet:
var catList = ["WordPress Plugins", "Websites"];
var categories = [
{cat: "WordPress Plugins", title: "Price Quote Plugin"},
{cat: "WordPress Plugins", title: "House Plan Search"},
// Added this to show putting things in other category lists
{cat: "Websites", title: "Some Website"}
];
// A map of category names to the divs that represent them
var catDivs = Object.create(null);
// Look up the projects div once and reuse it
var projects = $(".projects");
for (var i = 0; i < catList.length; i++) {
var catName = catList[i];
var clsName = catName.replace(/\s+/g, '-').toLowerCase();
// Create and add the category div, remember it in the map
catDivs[catName] = $('<div class="' + clsName + '"><div class="container"><div class="row"></div></div></div>').appendTo(projects);
}
// Done with this
projects = null;
// Add categories to their container
for (var i = 0; i < categories.length; i++) {
var catDiv = catDivs[categories[i].cat];
if (catDiv) {
var projectTitle = categories[i].title;
catDiv.find(".row").append('<div class="port-card"><h3>' + projectTitle + '</h3></div>');
}
}
.projects {
text-align: center;
margin-top: 5%;
}
.port-card {
background-color: #333;
width: 400px;
height: 800px;
}
h3 {
color: #fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="projects">
</div>
Add a unique Id on the row that you want to append data in and then append data in that row only. Like shown below
for (var i = 0; i < catList.length; i++) {
temp = catList[i];
temp = temp.replace(/\s+/g, '-').toLowerCase(); //convert string to lower case and make spaces dashes to create class names
$('.projects').append('<div class="' + temp + '"><div class="container"><div class="row" id="uniqueId"></div></div></div>');
}
if ($('.wordpress-plugins')[0]) {
for (var i = 0; i < categories.length; i++){
var catNameTemp = categories[i].cat;
var projectTitle = categories[i].title;
if(catNameTemp == "WordPress Plugins"){
$('#uniqueId').append('<div class="port-card"><h3>' + projectTitle + '</h3></div>');
}
}
In this line of code $('.row').append('<div class="port-card"><h3>' + projectTitle + '</h3></div>'); notice how you wrote $('.row').append(.
This makes jQuery append your new div to the every instance of the class of "row".
What you need to do is be more specific about which row you want your new div to be appended to.

Continuously adding arrays to a 2D array

Every time I click on a cell in a grid, it logs an array of [rows,column] of the cell into a variable, either bla (for black) or whi (for white). However, the next time I click on a cell, it changes the variable. For example, I click on a cell and variable whi is [1,2] then I click on another cell, variable bla is [2,2] and after that, I click on a third cell and variable whi is changed from [1,2] (from the original click) to [3,2]. (I made up random numbers for this). I want to create two 2D arrays, one for the variable bla and one for the variable whi. Using my example, one of the 2D arrays should be [[1,2],[3,2]] (for the white cells) and the other one should be [[2,2]] (for the black cells)
Test out the code:
var white=true;
function generateGrid( rows, cols ) {
var grid = "<table>";
for ( row = 1; row <= rows; row++ ) {
grid += "<tr>";
for ( col = 1; col <= cols; col++ ) {
grid += "<td></td>";
}
grid += "</tr>";
}
return grid;
}
$( "#tableContainer" ).append( generateGrid( 10, 10) );
$( "td" ).click(function() {
$(this).css('cursor','default');
var index = $( "td" ).index( this );
var row = Math.floor( ( index ) / 10) + 1;
var col = ( index % 10) + 1;
var $td = $(this);
if ($td.data('clicked'))
return;
if (white===true){
var whi=[row,col]; //I want to log the array for whi into a 2D array
console.log("white coord is "+whi);
} else {
var bla=[row,col]; //I want to log this array into another 2D array
console.log("black coord is "+bla);
}
$td.data('clicked', true);
$td.css('background-color', white ? 'white' : 'black');
white = !white;
});
html{
background-color:#7189ea;
}
td {
border: 1px solid;
width: 25px;
height: 25px;
border-radius:100%;
}
table {
border-collapse: collapse;
}
<link type="text/css" rel="stylesheet" href="stylesheet.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div id="tableContainer"></div>
Initialize whi and bla as arrays and push [row,col] to them - see demo below:
var white = true;
var whi = [];
var bla = [];
function generateGrid(rows, cols) {
var grid = "<table>";
for (row = 1; row <= rows; row++) {
grid += "<tr>";
for (col = 1; col <= cols; col++) {
grid += "<td></td>";
}
grid += "</tr>";
}
return grid;
}
$("#tableContainer").append(generateGrid(10, 10));
$("td").click(function() {
$(this).css('cursor', 'default');
var index = $("td").index(this);
var row = Math.floor((index) / 10) + 1;
var col = (index % 10) + 1;
var $td = $(this);
if ($td.data('clicked'))
return;
if (white === true) {
whi.push([row, col]);
} else {
bla.push([row, col]);
}
$td.data('clicked', true);
$td.css('background-color', white ? 'white' : 'black');
white = !white;
});
$('#getarr').click(function(){
console.log("white arr: ", whi);
console.log("black arr: ", bla);
});
html {
background-color: #7189ea;
}
td {
border: 1px solid;
width: 25px;
height: 25px;
border-radius: 100%;
}
table {
border-collapse: collapse;
}
<link type="text/css" rel="stylesheet" href="stylesheet.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div id="tableContainer"></div>
<button id="getarr">Get array</button>

Categories