Arrange div inside another div with Javascript - javascript

So if you have some free time:
This is a quite complex thing, or I'm just too naive, as I've been working for hours without getting the desired output/result, I wish you could help me if you have some free time.
Firstly this is the data I have, which is retrieved from a PHP newsfeed, so is not a static number of items:
<span class="dateclass">date1</span>
<span class="dateclass">date2</span>
<span class="dateclass">date3</span>
....and so on
<br>
<div class="contentclass">content1</div>
<div class="contentclass">content2</div>
<div class="contentclass">content3</div>
....and so on
I need to work with the classes and IDs, because is no php template engine so I can't call a single element, the code is distributed among several files, and the easier way to achieve what I need would be via javascript and their IDs / Classes
I need to get the following output by copying the data above and, with Javascript, tweak the data in order to achieve the final result, which should be:
<div class="frame">
<div class="timeline-badge"> <i class="fa fa-twitch"></i> </div>
<span class="timeline-date"> <span class="dateclass">date1</span> </span>
<div class="timeline-content"> <div class="contentclass">content1</div> </div>
</div>
<div class="frame">
<div class="timeline-badge"> <i class="fa fa-twitch"></i> </div>
<span class="timeline-date"> <span class="dateclass">date2</span> </span>
<div class="timeline-content"> <div class="contentclass">content2</div> </div>
</div>
<div class="frame">
<div class="timeline-badge"> <i class="fa fa-twitch"></i> </div>
<span class="timeline-date"> <span class="dateclass">date3</span> </span>
<div class="timeline-content"> <div class="contentclass">content2</div> </div>
</div>
The <div class="timeline-badge"> <i class="fa fa-twitch"></i> </div> ones don't exist as data in order to "transform", yet those are part of the style and I'd need them as well, but I haven't gotten that far to actually worry about those :(
I know, what a change!, yet I've been close to the result, I've been using different modified versions of the following code:
setTimeout(function() {
var element = document.getElementById("unique_ID");
element.innerHTML = "";
Array.prototype.forEach.call(document.querySelectorAll(".contentclass"), function(e) {
var example = element.appendChild(e.cloneNode(true));
});
}, 300);
I'm not posting all the versions I've made because none of them were going nowhere, and none of them work :/ I don't think I even have a copy of those
So what I've tried unsuccessfully so far has been:
Adding IDs to <span class="timeline-date"> and <div class="timeline-content"> so I can manipulate them with js
Using a different div setups in order to achieve the final result by manipulating the js code, this means using the following div/HTML arrangement in order to paste the cloneNode results there with some added elements, such as var div = document.createElement('div'); with div.className += "frame";, etc. Yet nothing works.
I've tried adding an ID via javascript to a div created in the same code, something like this:
.....(a previously defined variable for counter, of course)
var div = document.createElement('div');
div.id = "id_frame"+counter;
counter++;
Yet it didn't work when I tried to send the results with getElementById and the ID generated with the counter
I'm about to give up, it has been quite complicated for me ;P ... Any suggestions? :(
As far as I could get was to something like this:
<div id="ID_unique">
<div class="frame">
<span class="timeline-date">date1</span>
</div>
<div class=" timeline-content">content1</div>
<div class="frame">
<span class="timeline-date">date2</span>
</div>
<div class=" timeline-content">content2</div>
<div class="frame">
<span class="timeline-date">date3</span>
</div>
<div class=" timeline-content">content3</div>
</div>
Which isn't actually that far from the final result if it wasn't for those <div class="frame"> that should cover the content tags as well :(

First thing i think you should do is get all dateClasses and contentclass, and then create your frame one by one:
var dateClasses = $('.dateClass'); // array of all your dateClasses
var contentClasses = $('.contentClasses'); // array of all your contentClasses
for(var i=0; i< Math.min(dateClasses.length,contentClasses.length); i++) {
var frame = $("<div>", {class: "frame"}); // create your frame node
var timeLineDate = $("<div">,{class: "timeline-date"});
var timeLineContent = $("<div">,{class: "timeline-content"});
//Append DateClass to your timeline-data:
timeLineData.append(dateClasses[i]);
//Append ContentClass to your timeline-content:
timeLineContent.append(contentClasses[i]);
//Append all to your frame
frame.append(timeLineData);
frame.append(timeLineContent);
}
I didnt run it or test it tough, but hope it will give you an idea on how to achieve what you want.
Hope it helped.

Related

Add a Like + Sort Function to existing dynamic funcion

I wrote a function that dynamically creates a webpage for me based on a json database.
Now I want to add 2 functions:
If you click the like img (its got the id button) the like counter should increase on the webpage by 1. Pretty easy just a on(click) with jQuery variable++ and then .text(variable)
A sort function - based on the likes one item received, you should be able to sort it (most liked div first, 2nd, 3rd....
I can write it for each individually with individual variables when I give all the like buttons and outputs a separate id but I wanted to make it dynamic so if you add new data to json file it dynamically works with the like and sort function.
The likes are not saved anywhere for now.
Since sitting on it for 3h and google so much and so much stackoverflow I think I overloaded my brain with different stuff and now nothing seems to work ^^
function filmInsert(insert) {
$.each(film, function(i, data) { //.each statt loop
let box =
`<div class="boxwrapper">
<div class="imgbox">
<img src="${data.img}" alt="${data.titel}">
</div>
<div class="textbox">
<h3>${data.titel}</h3>
<p>${data.beschreibung}</p>
<p> <a id="button${data.id}">
<img src="img/budspencer_official.png"> Like
</a>
<span class="output${data.id}">${data.likes}</span>
</p>
</div>
</div>`;
insert.append(box);
});
}
I've added a container element for the boxwrapper items as I assume you have one and as it's better to have one instead of just adding the sorted items to the body of the HTML document.
$(document).on("click", ".textbox a", function() {
let likes = parseInt($(this).closest(".textbox").find("span").text());
$(this).closest(".textbox").find("span").text(likes + 1);
});
$("#sort").on("click", function() {
let divs = $(".boxwrapper")
let sorted = divs.sort(function(a, b) {
return $(a).find("span").text() < $(b).find("span").text() ? 1 : -1;
});
$(".container").html(sorted);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="boxwrapper">
<div class="imgbox">
<img src="example.gif" alt="Title">
</div>
<div class="textbox">
<h3>Titel</h3>
<p>Description</p>
<p> <a id="button1">
<img src="https://dummyimage.com/40x40/000/fff&text=1"> Like
</a>
<span class="output1">0</span>
</p>
</div>
</div>
<div class="boxwrapper">
<div class="imgbox">
<img src="example.gif" alt="Title">
</div>
<div class="textbox">
<h3>Titel 2</h3>
<p>Description 2</p>
<p> <a id="button2">
<img src="https://dummyimage.com/40x40/000/fff&text=2"> Like
</a>
<span class="output2">0</span>
</p>
</div>
</div>
</div>
<button id="sort">
Sort
</button>

Link simillary name classes so that when one is clicked the other is given a class

Basically, I'm asking for a way to optimize this code. I'd like to cut it down to a few lines because it does the same thing for every click bind.
$("#arch-of-triumph-button").click(function(){
$("#arch-of-triumph-info").addClass("active-info")
});
$("#romanian-athenaeum-button").click(function(){
$("#romanian-athenaeum-info").addClass("active-info")
});
$("#palace-of-parliament-button").click(function(){
$("#palace-of-parliament-info").addClass("active-info")
});
Is there a way to maybe store "arch-of-triumph", "romanian-athenaeum", "palace-of-parliament" into an array and pull them out into a click bind? I'm thinking some concatenation maybe?
$("+landmarkName+-button").click(function(){
$("+landmarkName+-info").addClass("active-info")
});
Is something like this even possible?
Thanks in advance for all your answers.
EDIT: Here's the full HTML.
<div class="landmark-wrapper">
<div class="page-content landmark">
<div class="heading span-after">
<span>Arch of Triumph</span>
</div>
<div class="landmark-button" id="arch-of-triumph-button"></div>
</div>
</div>
<div class="landmark-wrapper">
<div class="page-content landmark">
<div class="heading span-after">
<span>Romanian Athenaeum</span>
</div>
<div class="landmark-button" id="romanian-athenaeum-button"></div>
</div>
</div>
----------------------------------------------------------
<div class="landmarks-info-wrapper">
<div class="landmark-info" id="arch-of-triumph-info">
<div class="info-landmark section">
<span class="landmark-title">Arch of Triumph</span>
<span class="landmark-coord">44°28′1.99″N 26°4′41.06″E</span>
</div>
</div>
<div class="landmark-info" id="romanian-athenaeum-info">
<div class="info-landmark section">
<span class="landmark-title">The Romanian Athenaeum</span>
<span class="landmark-coord">44.4413°N 26.0973°E</span>
</div>
</div>
Assuming you're not able to modify your HTML markup (in which case with use of CSS classes would be cleaner), a solution to your question would be as shown below:
// Assign same click handler to all buttons
$("#arch-of-triumph-button, #romanian-athenaeum-button, #palace-of-parliament-button")
.click(function() {
// Extract id of clicked button
const id = $(this).attr("id");
// Obtain corresponding info selector from clicked button id by replacing
// last occurrence of "button" pattern with info.
const infoSelector = "#" + id.replace(/button$/gi, "info");
// Add active-info class to selected info element
$(infoSelector).addClass("active-info");
});
Because each .landmark-button looks to be in the same order as its related .landmark-info, you can put both collections into an array, and then when one is clicked, just find the element with the same index in the other array:
const buttons = [...$('.landmark-button')];
const infos = [...$('.landmark-info')];
$(".landmark-button").click(function() {
const i = buttons.indexOf(this);
$(infos[i]).addClass('active-info');
});
This does not rely on IDs at all - feel free to completely remove those from your HTML to declutter, because they don't serve any purpose now that they aren't being used as selectors.
Live snippet:
const buttons = [...$('.landmark-button')];
const infos = [...$('.landmark-info')];
$(".landmark-button").click(function() {
const i = buttons.indexOf(this);
$(infos[i]).addClass('active-info');
});
.active-info {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="landmark-wrapper">
<div class="page-content landmark">
<div class="heading span-after">
<span>Arch of Triumph</span>
</div>
<div class="landmark-button" id="arch-of-triumph-button">click</div>
</div>
</div>
<div class="landmark-wrapper">
<div class="page-content landmark">
<div class="heading span-after">
<span>Romanian Athenaeum</span>
</div>
<div class="landmark-button" id="romanian-athenaeum-button">click</div>
</div>
</div>
----------------------------------------------------------
<div class="landmarks-info-wrapper">
<div class="landmark-info" id="arch-of-triumph-info">
<div class="info-landmark section">
<span class="landmark-title">Arch of Triumph</span>
<span class="landmark-coord">44°28′1.99″N 26°4′41.06″E</span>
</div>
</div>
<div class="landmark-info" id="romanian-athenaeum-info">
<div class="info-landmark section">
<span class="landmark-title">The Romanian Athenaeum</span>
<span class="landmark-coord">44.4413°N 26.0973°E</span>
</div>
</div>
Older answer, without knowing the HTML: You can extract the ID of the clicked button, slice off the button part of it, and then select it concatenated with -info:
$(".landmark-button").click(function() {
const infoSel = this.id.slice(0, this.id.length - 6) + 'info';
$(infoSel).addClass('active-info');
});
A much more elegant solution would probably be possible given the HTML, though.

java script replace for html attributes

I have a html tag like the following:
<div id="slide1" class="mySlides" type="slide" index="1" duration="1100" style="display: block;">
<div id="page_number1" class="numbertext">1/2</div>
<div id="slide_content1"><p>First Slide</p>
</div>
<div id="slide_h1" class="slide_h1"></div>
<div id="slide_h2" class="slide_h2"></div>
<div id="playOptions{slide_number}" class="playOptions">|
<span id="remaining_slide_time{slide_number}"></span> |
<span id="remaining_time{slide_number}"></span>
</div>
</div>
</div>
I need to replace {slide_number} with an integer. Whatever I tried the result doesn't replace the {slide_number}
var str = template.replace("{slide_number}", i);
You can use attribute selector contains that will select all elements where id contains {slide_number} and you can replace that part of the id with the number.
document.querySelectorAll("[id*='{slide_number}']").forEach(function(e) {
e.id = e.id.replace("{slide_number}", 1)
})
<div id="slide1" class="mySlides" type="slide" index="1" duration="1100" style="display: block;">
<div id="page_number1" class="numbertext">1/2</div>
<div id="slide_content1">
<p>First Slide</p>
</div>
<div id="slide_h1" class="slide_h1"></div>
<div id="slide_h2" class="slide_h2"></div>
<div id="playOptions{slide_number}" class="playOptions">|
<span id="remaining_slide_time{slide_number}"></span> |
<span id="remaining_time{slide_number}"></span>
</div>
</div>
in javascript you can find them from
document.querySelector('[id$="{slide_number}"]').id;
and
document.querySelector('[id*="{slide_number}"]').id;
Please read this
If you use jquery then it can be done like below:
$('#playOptions').attr('id','playOptions88');
But I recommend you to use HTML data attribute to distinguish different element. It is a very nice thing to work with multiple elements that can be needed to change dynamically.
If you change your ID attribute dynamically adding some integer number then it may be harder to catch them. Instead, use data like below code.
You can make any element unique setting the data-SOMETHING.
If you write the code below:
$('#playOptions').data('roll','100');
Then the element will be
<div id="playOptions" data-roll="100" class="playOptions">
If you write the code below:
$('#playOptions').data('name','ahmad');
Then the element will be
<div id="playOptions" data-name="ahmad" class="playOptions">
You can then catch the element by the code below:
var name = $('#playOptions').data('name');
console.log(name) //Output should be 'ahmad'
Similarly,
var roll = $('#playOptions').data('roll');
console.log(roll) //Output should be '100'
To learn more about the data attribute please see the link
https://api.jquery.com/data/
This solution worked:
var find = '{slide_number}';
var re = new RegExp(find, 'g');
str = template.replace(re, i);

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

Jquery: How to clone <div> based on the count?

I am trying to use jquery clone() for displaying cards on my web page. When the page loads it has to clone card div based on the count of rooms in that particular location. I hardcoded count as roomcount. I tried using simple for loop as per https://stackoverflow.com/a/12835644/6915446, However it doubles the count of divs each time. Please provide me right inputs.
<div class="container-fluid">
<div class="row-fluid">
<div class="col-lg-2">
<div class="card">
<h6 class="card-header">NC001
<ul class="card-header-pills pull-xs-right">
<span class="badge badge-primary" aria-hidden="true">2</span>
<!-- <span class="glyphicon glyphicon-user" aria-hidden="true"></span> -->
</ul>
</h6>
<div class="card-block" id="scrollCard">
<h4 class="card-title"></h4>
<!-- <p class="card-text">ICU : 12.00 AM</p>
<p class="card-text">VEN : 1.00 AM</p> -->
</div>
</div>
<script>
var roomcount = 3;
$(document).ready(function() {
for(var i=0; i< roomcount; i++) {
$(".col-lg-2").clone().appendTo(".row-fluid");
}
});
</script>
</div>
Thanks.
When the count is 2, it clones to display 4 divs:
When the count is 3, it clones to displays 8 divs:
I think you might be cloning an array?
After you have cloned
$(".col-lg-2")
once it becomes an array, so when you clone it again you get 4?
Try using
$(".col-lg-2:first").
Tom
When you select an element by it's class name, jquery returns an array of all the matching objects.
So once you've cloned an item with the same class name, the next time you call $(".col-lg-2"); it will actually fetch 2 items and clone them, and the next time it will fetch 4 items and clone them etc.
To avoid it (and as a best practice) you should cache the element you are cloning:
var roomcount = 3,
$cloned = $('.col-lg-2');
for(var i = 0; i < roomcount; i++) {
$cloned.clone().appendTo('.row-fluid');
}
that way you always clone just that one object you cached.
NOTE: make sure you don't have an id on the cloned object since you'll be creating multiple items with the same id and id should be unique
The clone() method makes a copy of selected elements, including child nodes, text and attributes.
You can save the value of $(".col-lg-2") in a variable, and clone it, these way you are improving performance as you are not going to query the DOM multiple times:
var roomcount = 3,
$colLg2 = $('.col-lg-2');
for(var i = 0; i < roomcount; i++) {
$colLg2.clone().appendTo('.row-fluid');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row-fluid">
<div class="col-lg-2">
<div class="card">
<h6 class="card-header">NC001
<ul class="card-header-pills pull-xs-right">
<span class="badge badge-primary" aria-hidden="true">2</span>
<!-- <span class="glyphicon glyphicon-user" aria-hidden="true"></span> -->
</ul>
</h6>
<div class="card-block" id="scrollCard">
<h4 class="card-title"></h4>
<!-- <p class="card-text">ICU : 12.00 AM</p>
<p class="card-text">VEN : 1.00 AM</p> -->
</div>
</div>
</div>
</div>

Categories

Resources