How do I use JavaScript/jQuery to populate multiple divs dynamically? - javascript

I apologise in advance, I'm not allowed to post images until I have 10 reputation. So, I hope that my description would be enough to get across the idea I have.
So, say I have three columns; a, b, and c. And when there's too much content to be hosted in just a, b, and c, I'd want new off-screen columns to be made, d, e, and f. - This goes on until all the content is used.
So, my current setup has the "hidden-text" div play host to all the content, and then I'd have a JavaScript function, or jQuery function to dynamically populate each of the divs, and create divs where needed along with buttons to then get to the new divs it creates.
The way it determines which to populate is simply grabbing the content and putting it into column a. Column a is full when the content reaches the bottom of the screen. Then it grabs the rest of the content and puts it in b, until b is full and so on until all the content available is used.
I really hope I'm being clear enough, I have no idea if anyone is going to even remotely understand what I'm trying to say... Any help at all is much appreciated!
Here's a code snippet of how the HTML is structured, maybe it'll help someone understand what I mean... Thanks again, everyone!
<div id="parent-div">
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
</div>
<div id="hidden-text">
This is the content I would like to have displayed across the three divs above.
</div>
Here is some JS that I have so far and I'm rather stuck on where to go from here:
function Populate(){
//paragraph is equal to all of the content in the hidden-text div
var paragraph = document.getElementById('hidden-text').innerHTML;
var newParagraph = "";
//the variable div would play host to the names of each of the divs in the HTML
var div = "";
//words stores each character of paragraph and passes them into the new paragraph
var words = "";
for (words in paragraph)
{
newParagraph += paragraph[words];
}
//the column with the name equal to the value of the div variable gets populated by the value of newParagraph
document.getElementByClassName(div).innerHTML = newParagraph;}

I think it should be something like this:
var divs = ['a', 'b', 'c'];
var word_limit = 50;
var paragraph_words = paragraph.split(' ');
for (var i = 0, div_index = 0; i < paragraph_words.length && div_index < divs.length; i++) {
newParagraph += ' ' + paragraph_words[i];
if (i > 0 && i % word_limit == 0) {
document.getElementsByClassName(divs[div_index])[0].innerHTML = newParagraph;
div_index++;
newParagraph = '';
}
}
if (newParagraph) { // If we didn't fill up the last DIV
document.getElementsByClassName(divs[div_index])[0].innerHTML = newParagraph;
}

Related

Appending more than two child elements to an element gives a strange behaviour

I have a very strange behaviour and I don't know what causes it.
I loop through all of the id's which javascript can find within my html page. Every time when the 'id' startsWith a specific label, it goes into my if statement.
Within this if-statement I am creating several elements such as P,H1 and HR. Within my 'html'-page I've got 3 unique id's which are DIV's and should go into the if statement. This worked well(picture left [ 1]), until...
I tried to append more than two child elements to those DIV elements. The first two DIV elements are extended as expected. The last one has not been extended though. At the moment that there are more than two elements added to the parent, the 3th DIV (standardArticle3) does not pass the if statement. (picture right [2])
Hopefully the code and scenario picture can make this story clearer:
home.component.ts
var allElements = document.getElementsByTagName("*");
console.log(allElements);
for (var i = 0, n = allElements.length; i < n; ++i) {
var el = allElements[i];
var foundElementId = el.id;
console.log(foundElementId);
if (foundElementId.startsWith("standardArticle"))
{
var standardArticleElement = this.jsonReaderService.getStandardArticleContent(foundElementId.substring(15, foundElementId.length));
var titleElement = document.createElement("h1");
var titleText = document.createTextNode(standardArticleElement.title);
titleElement.appendChild(titleText);
var contentElement = document.createElement("p");
contentElement.innerHTML = standardArticleElement.content;
var thematicBreak = document.createElement("hr");
thematicBreak.style.borderTopColor = "black";
var thematicBreakTwo = document.createElement("hr");
thematicBreakTwo.style.borderTopColor = "black";
// Child elements are all being appended the right way, but the last DIV will never be extended
el.appendChild(titleElement);
el.appendChild(thematicBreak);
el.appendChild(contentElement);
el.appendChild(thematicBreakTwo);
}
}
home.component.html
// other content
<div id="standardArticle1" class="col-sm-6">
</div>
// other content
<div id="standardArticle2" class="col-sm-6 pull-right">
</div>
// other content
<div id="standardArticle3" class="col-sm-6">
</div>
Scenario's 1 and 2.
Does anybody have an idea why this is happening?
document.getElementsByTagName() returns a live HTMLCollection, and your collection includes every element on the page. This means that when you append new elements, these elements get included in the collection but since you iterate up to the original length of the collection, you'll miss the last elements of the collection (the same number of elements as the number of elements you added).
It seems like a better solution to your problem would be to add a class to all elements you want to find and just get those ones with document.getElementsByClassName():
var allElements = document.getElementsByClassName("standard-article");
... and then you add your class name to your HTML:
// other content
<div id="standardArticle1" class="standard-article col-sm-6">
</div>
// other content
<div id="standardArticle2" class="standard-article col-sm-6 pull-right">
</div>
// other content
<div id="standardArticle3" class="standard-article col-sm-6">
</div>
With this approach you don't need your id.startsWith("standardArticle") if statement either.
I think I know what your problem is. Let's see what happens when you loop over all the elements on the page: for (var i = 0, n = allElements.length; i < n; ++i)
If there are 10 elements on the page, then n is set to 10. But then as you reach your if statement and add elements, n is still equal to 10 but you now have additional elements on the page. It looks like Mikael Lennholm said those more concisely and provided a good solution.

Javascript string.slice() with negative values

I am trying to hide or show divs based on the title of the page. This is only required because I can't figure out a better way of passing a value into the page.
Here's the current code in the HTML file:
function toggle(divId) {
var divArray = document.getElementsByTagName("div");
for(i = 0; i < divArray.length; i++){
if(divArray[i].id == divId){
if(divArray[i].style.display != 'none'){
divArray[i].style.display = 'none';
}else{
divArray[i].style.display = '';
}
}
}
}
function togglePayLink() {
var h1Array = document.getElementsByTagName("h1");
for(i = 0; i < h1Array.length; i++){
if(h1Array[i].id == 'Title'){
var title = h1Array[i].innerHTML;
title = title.slice(1);
title = title.slice(-4);
toggle('descr'+ title);
}
}
}
Also in the HTML file is a header with the page title. The %%GLOBAL_PageTitle%% is replaced in server side code that I don't have access to. However, the values will be "$100 Fee" (with different numbers).
<h1 id="Title" class="TitleHeading">%%GLOBAL_PageTitle%%</h1>
Finally, I have a set of hidden divs with id's in the format descr + a number, so if the page title is "$100 Fee" I want to show the div with the id "descr100".
<div id="descr100" style="display:none;width: 75%;"></div>
When the script above runs, I get no error (I'm using chrome's console), but the div does not show. I know the toggle function works because it was previously being used with only a single div on the page that had to be toggled. I wrote the togglePayLink function, which I assume is the issue, but I have no idea how to debug this. I was wondering if the dollar sign in the title could be causing issues, but I would think I would get an error if that were the case.
EDIT: Changed the togglePayLink function to use var instead of string, but I'm getting a typeError when slice() is called.
Going forward, you should probably just assign a unique class to the page using %%GLOBAL_PageTitle%%. This way you can show/hide elements using CSS.
<div class="page %%GLOBAL_PageTitle%%">
For pages that BigCommerce doesn't give access to the HTML of the h1 for each individual page (ex. Web Pages, Account, Cart), I usually run this script on page load to strip the page title of spaces and other characters, and assign a specific class to the page element.
var catName = $('.TitleHeading').text();
var catName = catName.replace(/ /g, '');
var catName = catName.replace(/'/g, '');
var catName = catName.replace(/&/g, '');
var catName = $.trim(catName);
$('.page').addClass(''+catName+'');
The way your doing it seems a bit over the top, but if it was setup this way by someone else, I understand.
The problem is here:
String title = h1Array[i].innerHTML;
In Javascript, all variables are set with var (except for functions, which can be set other ways). So it would be:
var title = h1Array[i].innerHTML;
Additionally, you probably have to define it outside the for loop, in which case you would omit the "var" when you are setting it in the for loop:
<script language="javascript">
var title;
function togglePayLink() {
var h1Array = document.getElementsByTagName("h1");
for(i = 0; i < h1Array.length; i++){
if(h1Array[i].id == 'Title'){
title = h1Array[i].innerHTML;
title = title.slice(1);
title = title.slice(-4);
toggle('descr'+ title);
}
}
}
</script>
Edit: If you only use it in the for loop, but use it in different iterations, then I'm not sure if it can be defined locally. I'd still define it globally, though.
title.slice(-4) was giving me the last four digits of the string instead of everything before the last four digits like I thought it would. toggling the non-existent 'descrFee' div was not doing anything.

Is there an easy way to add multiple javascript images together via `imgCounter.src =`

In photoshop I created images 0.png thru 9.png and know I can change each digit to simulate a counter by changing each picture of each digit as it counts down.
IDEA 1:
One way I thought would be to have multiple lines of
HTML:
<div align="right"><img src="graphics/odometers/1.png" /id="digit1">
<img src="graphics/odometers/2.png" /id="digit2">
<img src="graphics/odometers/3.png" /id="digit3"></div>
JAVASCRIPT:
var imgCounter = document.getElementById('digit1');
imgCounter.src = "graphics/odometers/white and blue with black background/1.png"; // shows the digit 1
var imgCounter = document.getElementById('digit2');
imgCounter.src = "graphics/odometers/white and blue with black background/2.png"; // shows the digit 2
// etc for as many digits as I want to show
and change the digits in javascript by each ID. It's not hard but for flexibility can I have 1 image ID and string 3 .png's together in javascript? Like this...
IDEA 2: Not sure if this is possible.
HTML:
<div align="right"><img src="" /id="formtimer"></div>
JAVASCRIPT:
// somehow show 3 graphics in a row 123 without having 3 ID tags, only 1 ID tag
var imgCounter = document.getElementById('formtimer');
imgCounter.src = "graphics/odometers/white and blue with black background/1.png";
I know the example above only shows the digit 1 and doesn't do all 3 digits... (because I don't know if it's possible).
Is there a way to display 3 pictures together? lol. Easily? I know anything can technically be done the hard way...
If it's a big pain in the butt I'm ok with IDEA 1 but it's less "freedom" because I have to encode the HTML with multiple ID tags which is tedius...
Just curious what you all think and if you have a solution. :) Much appreciated.
ALSO:
Is it ok to leave the img src="" as a NULL or empty string if I'll later be sticking an image in via javascript?
You don't need to include the <img> elements in the source html at all, you can add them with JavaScript and not even give them ids.
At the point in your source where you want the counter just put an empty div with an appropriate id.
When the counterSet() function below is called with the id of the container div and a value it creates new child <img> elements in the div with src set appropriately, but reuses any existing child <img> elements that are there from any previous value that was set. If the new value has fewer digits than the last than the function removes the leftover <img> elements:
<div id="counter1"></div>
<script>
function counterSet(counterId, val) {
var c = document.getElementById(counterId),
i,
d;
for (i = 0; i < val.length; i++) {
// if the container already had enough child img elements
// for current digit set current img's src, otherwise add
// new img to end
if (i < c.childNodes.length)
c.childNodes[i].src = "graphics/odometers/" + val.charAt(i) + ".png";
else {
d = document.createElement("img");
d.src = "graphics/odometers/" + val.charAt(i) + ".png";
c.appendChild(d);
}
}
// if the container already had too many child img elements
// (from a previous value) remove the leftover digits
while (c.childNodes.length > val.length)
c.removeChild(c.childNodes[val.length]);
}
counterSet("counter1","218");
</script>
I would just use three separate ids.
You can use something like this to set the src attributes:
for (i = 1; i <= NUMBER_OF_IMAGES; i++) {
var img = document.getElementById('img_' + i);
imgr.src = 'images/image_' + i + '.png";
)

Generating random divs multiple times on load

let me just give a quick story. I have made a page. (VERY simple - two divs with a different background image, see here.)
Anyway, I need to make it so that when a new page loads, the two divs that I have load in a random order over and over, filling the entire screen content. So there's no pattern of the first div and then the second, it's just randomly generated. Sort of like a huge grid, with the two divs repeated with no pattern.
My question is...is that possible? I assume I'd need to know PHP, but I have no knowledge of it.
Thanks guys, I appreciate all help!
http://jsfiddle.net/uYPRq/
jquery
var div1 = '<div class="one">';
var div2 = '<div class="two">';
var len =
Math.floor(window.innerWidth/30)*Math.floor(window.innerHeight/30);
for (x = 0; x < len; x++) {
if ( Math.random() > 0.5 ) {
$(div1).appendTo('body');
}
else {
$(div2).appendTo('body');
}
}
css
div.one, div.two {
height:30px;
width:30px;
float:left;
}
div.one { background-color:#EBE1E4; }
div.two { background-color:#F0F5DF; }
edit:
changed screen.availWidth to window.innerWidth
Something like so? Just loop through how ever many times you like and add elements in.
for (i = 0; i < 300; i++) {
var type1 = document.createElement("div");
var type2 = document.createElement("div");
type1.innerHTML = "div1";
type2.innerHTML = "div2";
type1.setAttribute("class", "type1");
type2.setAttribute("class", "type2");
document.body.appendChild(type1);
document.body.appendChild(type2);
}
No PHP needed. This can be done client-side using Javascript (Jquery might be easier).

Any way to shuffle content in multiple div elements

I'm relatively new to Javascript and was wondering if there's a quick way to shuffle content that is contained in multiple <div> tags. For example
<div id='d1'>
<span>alpha</span>
<img src='alpha.jpg'>
</div>
<div id='d2'>
<span>beta</span>
<img src='beta.jpg'>
</div>
<div id='d3'>
<span>gamma</span>
<img src='gamma.jpg'>
</div>
<button onclick='shuffle_content();'>Shuffle</button>
After clicking on the button, I'd like the content in d1, d2, d3 to change places (for example maybe d3 would be first, then d1, then d2).
A quick way to kind of move things around is to copy the first div element (d1), then put it at the very end (after d3), and then delete the original d1. But that doesn't really randomize things. It just makes things go in the cycle (which might be ok).
Any suggestions would be appreciated. Thanks.
are you ok with using a javascript library like jQuery? here's a quick jQuery example to accomplish what you're after. the only modification to your HTML is the addition of a container element as suggested:
<div id="shuffle">
<div id='d1'>...</div>
<div id='d2'>...</div>
<div id='d3'>...</div>
</div>
and javascript:
function shuffle(e) { // pass the divs to the function
var replace = $('<div>');
var size = e.size();
while (size >= 1) {
var rand = Math.floor(Math.random() * size);
var temp = e.get(rand); // grab a random div from our set
replace.append(temp); // add the selected div to our new set
e = e.not(temp); // remove our selected div from the main set
size--;
}
$('#shuffle').html(replace.html() ); // update our container div with the
// new, randomized divs
}
shuffle( $('#shuffle div') );
A recent question was just closed as duplicate of this, but I feel I've got a better answer than any here. This method is very direct. There's no mucking with copying HTML, thus preserving changes to the DOM, styles, event handlers, etc.
To shuffle all the children of some parent element, select a random child and append it back to the parent one at a time until all the children have been re-appended.
Using jQuery:
var parent = $("#shuffle");
var divs = parent.children();
while (divs.length) {
parent.append(divs.splice(Math.floor(Math.random() * divs.length), 1)[0]);
}
Demo: http://jsfiddle.net/C6LPY/2
Without jQuery it's similar and just as simple:
var parent = document.getElementById("shuffle");
var divs = parent.children;
var frag = document.createDocumentFragment();
while (divs.length) {
frag.appendChild(divs[Math.floor(Math.random() * divs.length)]);
}
parent.appendChild(frag);
Demo: http://jsfiddle.net/C6LPY/5/
Edit: Here's a break down of the code:
// Create a document fragment to hold the shuffled elements
var frag = document.createDocumentFragment();
// Loop until every element is moved out of the parent and into the document fragment
while (divs.length) {
// select one random child element and move it into the document fragment
frag.appendChild(divs[Math.floor(Math.random() * divs.length)]);
}
// appending the document fragment appends all the elements, in the shuffled order
parent.appendChild(frag);
You can grab the content of each div
c1 = document.getElementById('div1').innerHTML
c2 = document.getElementById('div2').innerHTML
c3 = document.getElementById('div3').innerHTML
Then determine a new order for them randomly .. and then put each content in the new destination
say for instance, the randomness gave:
c1_div = 'div2'
c2_div = 'div1'
c3_div = 'div3'
then you just:
document.getElementById(c1_div).innerHTML = c1
document.getElementById(c2_div).innerHTML = c2
document.getElementById(c3_div).innerHTML = c3
Expanding on the nice answer by #gilly3, using jQuery one can actually avoid appending randomly-chosen elements of divs in a loop, by randomly sorting divinstead and appending them all at once:
$(function() {
var parent = $("#shuffle");
var divs = parent.children();
divs.sort(function(a, b) {
return 0.5 - Math.random();
});
parent.append(divs);
});
Demo: http://jsfiddle.net/ey70Lxhk/
Note however that this technique is not accurate in terms of randomness, and relies on sort which does not scale linearly with the number of elements.
I'd use server side code to accomplish this. I know this isn't really an answer to your question, but it is an alternative implementation.
Best Regards, Frank
I'd wrap the divs in an outer div, then pass its id to shuffle_content().
In there, you could create a new div, cloning the wrapper div's nodes in a random order to fill it, then replace the wrapper div with the new div.
For your HTML, the short answer to your question is:
function shuffle_content() {
var divA = new Array(3);
for(var i=0; i < 3; i++) {
divA[i] = document.getElementById('d'+(i+1));
document.body.removeChild(divA[i]);
}
while (divA.length > 0)
document.body.appendChild(divA.splice(Math.floor(Math.random() * divA.length),1)[0]);
}
To get there I wrote the following, which I think works better:
<html>
<div id="cards">
<div id="card0">Card0</div><div id="card1">Card1</div>
<div id="card2">Card2</div><div id="card3">Card3</div>
<div id="card4">Card4</div><div id="card5">Card5</div>
<div id="card6">Card6</div><div id="card7">Card7</div>
<div id="card8">Card8</div><div id="card9">Card9</div>
</div>
<button id="shuffle">Shuffle</button>
<script language="javascript">
<!--
document.getElementById('shuffle').onclick = function () {
var divCards = document.getElementById('cards');
var divCardsArray = new Array(
document.getElementById('card0'),
document.getElementById('card1'),
document.getElementById('card2'),
document.getElementById('card3'),
document.getElementById('card4'),
document.getElementById('card5'),
document.getElementById('card6'),
document.getElementById('card7'),
document.getElementById('card8'),
document.getElementById('card9')
);
return function() {
var mDivCardsArray=divCardsArray.slice();
while (divCards.childNodes.length > 0) {
divCards.removeChild(divCards.firstChild);
}
while (mDivCardsArray.length > 0) {
var i = Math.floor(Math.random() * mDivCardsArray.length);
divCards.appendChild(mDivCardsArray[i]);
mDivCardsArray.splice(i,1);
}
return false;
}
}()
//-->
</script>
</html>
I was trying to pack down that last while statement to:
while (mDivCardsArray.length > 0) {
divCards.appendChild(
mDivCardsArray.splice(
Math.floor(Math.random() * mDivCardsArray.length)
,1)[0]
);
}
but this is pretty hard to read and prone to error.
Going with jQuery or Prototype you could follow the same basic structure and get the result you're looking for.
Personally, I think it looks even better if you add 2 more divs to the cards stack, expand the divCardsArray, insert the following style block, and add this code right after the divCardsArray definition.
<html>
...
<style>
html,body{height:100%;width:100%;text-align:center;font-family:sans-serif;}
#cards,#cards div{padding:5px;margin:5px auto 5px auto;width:100px;}
</style>
...
<div id="cardA">CardA</div><div id="cardB">CardB</div>
...
var colorCardsArray = new Array(
'#f00', '#f80', '#ff0', '#8f0', '#0f0', '#0f8',
'#0ff', '#08f', '#00f', '#80f', '#f0f', '#f08' );
for(var i=0;i<divCardsArray.length;i++)
divCardsArray[i].style.backgroundColor=colorCardsArray[i];
...
</html>
I would suggest you randomize the content, not the actual Divs themselves. You could accomplish this by putting the content in separate html pages - no header info or body, just the content.
Then use a function on page load to randomly assign which div gets what content and use this to change the DIV's content:
<script type="text/javascript">
function ajaxManager(){
var args = ajaxManager.arguments;
if (document.getElementById) {
var x = (window.ActiveXObject) ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
}
if (x){
switch (args[0]){
case "load_page":
if (x)
{
x.onreadystatechange = function()
{
if (x.readyState == 4 && x.status == 200){
el = document.getElementById(args[2]);
el.innerHTML = x.responseText;
}
}
x.open("GET", args[1], true);
x.send(null);
}
break;
case "random_content":
ajaxManager('load_page', args[1], args[2]); /* args[1] is the content page, args[2] is the id of the div you want to populate with it. */
break;
} //END SWITCH
} //END if(x)
} //END AjaxManager
</script>

Categories

Resources