How to use JS object/classes to save repeating html - javascript

First I'm brand new to JS but have an idea that object classes are what I should be looking into, yet I can't find a straightforward tutorial that doesn't shoot off into arrays,arguments or silly alert boxes! All I'm looking for is something like this:
<head>
<Script Language="JavaScript">
function Class (color, bodypart, item)
Var1 =newClass ('red', 'hand', 'ball')
Var2 =newClass ('green', 'foot, 'bat')
btw I have hundreds of these Vars to write, this is the reason for looking into this method
then put these Vars into some HTML:
('<div><span style="color:'+color+';>'+bodypart+'</span><br/>'+item+'</div><br/>');</script></head>
now in the body I want to call one of the Vars (e.g. Var1) and put it (with the HTML) into a div so it would automatically generate:
<div><span style="color:red;">hand</span><br/>item</div><br/>
My question:what exactly do I put in the head and body to make this happen??
I'm guessing something to do with GetElementById, Classes, etc but I can't find the right syntax to make a simple example work.
Aaaaany help would be fantastically appreciated for such a noob! (p.s. I have spent the last full 2 days reading tutorials and forum posts but they keep losing me in far more complex things than I can grasp)

You sound like you're in over your head at this point, and if you plan on doing a lot of javascript, you're much better off finishing off those tutorials on arrays and such.
Having said that, to help you jump ahead a little, here's what you need to do:
Go to http://www.jquery.com and follow the instructions on how to include jQuery onto your page
Write a javascript function that uses jQery to transform a javascript array into your html
That function might look something like:
var parts = [
['red', 'hand', 'ball'],
['green', 'foot', 'ball']
];
makePart = function(part){
var div = $('<div />');
var span = $('<span />').css({color:part[0]}).text(part[1]);
div.append( span );
div.append( $('<br />') );
div.append( part[2] );
$('body').append( div ).append( $('<br />') );
}
// this next line makes all your parts
$.each( parts, function(index, part) { makePart(part); } );
// while this would only make the first part
makePart( parts[0] );

There are a number of templating libraries around that will turn arrays of data into DOM structures. However, if your requirements are simple then you can put the data into an array and iterate over it to generate HTML or DOM elements:
var data = [
['red', 'hand', 'ball'],
['green', 'foot', 'bat']
];
function genElements(data) {
var frag = document.createDocumentFragment();
var div = document.createElement('div');
var span = document.createElement('span');
var br = document.createElement('br');
var b, d, s, x;
for (var i=0, iLen=data.length; i<iLen; i++) {
x = data[i];
d = frag.appendChild(div.cloneNode());
s = d.appendChild(span.cloneNode());
s.style.color = x[0];
s.appendChild(document.createTextNode(x[1]));
div.appendChild(br.cloneNode());
frag.appendChild(br.cloneNode());
alert(frag.childNodes.length);
}
}
Alternatively you can generate HTML and insert that:
function genElements(data) {
var html = [];
var x;
for (var i=0, iLen=data.length; i<iLen; i++) {
x = data[i];
html.push('<div><span style="color:' + x[0] + '">' +
x[1] + '</span><br>' + x[2] + '</div><br>');
}
return html.join('');
}
Then insert it wherever is appropriate. But you could do exactly the same logic on the server and just send the HTML, avoiding all the issues with client side scripting. Overall it would be much more efficient and robust.

Related

page doesn't display anything

so I wrote a script to display 5 random arrays, but the page doesn't display anything.
here's the code:
<html>
<head>
<script>
function start(){
var arr(5),result;
result=document.getElementById("arraying");
result="<p>";
for(var i=0; i<5;i++){
arr[i]=Math.floor(Math.random()*10);
result+="arr["+i+"]= "+arr[i]+"</p><p>";
}
result+="</p>";
}
window.addEventListener("load",start,false);
</script>
</head>
<body>
<div id="arraying"></div>
</body>
</html>
I tried removing result=document.getElementById and write document.getElementById.innerHTML=result in the end of the function but didn't work. what's the error?
You cannot use the same variable for different purposes at the same time. First you assign a DOM element to result, and immediately on the next line you overwrite result with a string.
Build a string htmlStr inside your loop, and when that is done, assign this string to result.innerHTML property:
function start() {
let arr = [],
result, htmlStr = '';
result = document.getElementById("arraying");
htmlStr += "<p>";
for (let i = 0; i < 5; i++) {
arr[i] = Math.floor(Math.random() * 10);
htmlStr += "arr[" + i + "]= " + arr[i] + "</p><p>";
}
htmlStr += "</p>";
result.innerHTML = htmlStr;
}
window.addEventListener("load", start, false);
<div id="arraying"></div>
Looking at the code you seem to be missing some basic javascript concepts.
array size
This is probably your main issue:
var arr(5)
This does not make sense in javascript. Array length does not need to be predefined since all arrays are of dynamic length. Simply define an array like this:
var arr = []
Then later when you want to append new elements use push like this:
arr.push( Math.floor(Math.random()*10) )
adding html using innerHTML
There are different ways to dynamically inject html into your page. (It looks like) you tried to append the html as a string to the parent element. This is not possible.
You said you tried using innerHTML. That should work if used correctly.
A working implementation would work like this:
function start() {
var arr = []
var result = "<p>"
for(var i = 0; i < 5; i++) {
arr.push( Math.floor(Math.random()*10) ) // Btw this array isn't actually needed.
result += "arr[" + i + "] = " + arr[i] + "</p><p>"
}
document.getElementById("arraying").innerHTML = result
}
window.addEventListener("load", start, {passive: true});
adding html using createElement
A generally better way of dynamically adding html elements is via createElement.
This way you dont have to write html and are therefore less prone for making errors. It is also more performant and easier to integrate into javascript.
I think the best explaination is a commented implementation:
function start() {
var myDiv = document.getElementById("arraying") // get parent node
var arr = []
for(var i = 0; i < 5; i++) {
arr.push( Math.floor(Math.random()*10) )
var p = document.createElement("p") // create p element
p.innerText = "arr[" + i + "] = " + arr[i] // add text content to p element
myDiv.append(p) // append p element to parent element
}
}
window.addEventListener("load", start, {passive: true});
small tips
The let keyword works mostly the same as the var keyword, but is generally preferred because of some edge cases in which let is superior.
Fusing strings and variables using the plus operator is generally considered bad practice. A better way to do the string concatenation would have been
result += `arr[${i}] = ${arr[i]}</p><p>`

Refactoring Nested JavaScript Loops as CoffeeScript Comprehensions

I have the following JavaScript that I'd like to translate to CoffeeScript:
function initPage() {
var tr = document.getElementsByTagName('tr')[0];
labs.forEach(function(lab) {
var td = document.createElement('td');
// Create a header for each lab.
var h2 = document.createElement('h2');
h2.innerHTML = lab.name;
td.appendChild(h2);
// Create a div for each machine in a given lab.
for(i = lab.first; i <= lab.last; i++) {
var machine = ((i < 10) ? "0" : "") + i;
var div = document.createElement('div');
div.setAttribute('id', lab.name + "-" + machine);
div.setAttribute('class', 'Grey');
div.innerHTML = machine;
td.appendChild(div);
}
// Append the new table data element to the table row.
tr.appendChild(td);
});
}
Right now my CoffeeScript translation looks something like this:
initPage = () ->
tr = document.getElementsByTagName('tr')[0]
labs.forEach (lab) ->
td = document.createElement 'td'
# Create a header for each lab.
h2 = document.createElement 'h2'
h2.innerHTML = lab.name
tr.appendChild h2
# Create a div for a machine given the machine number
createDiv = (i) ->
machine = if i < 10 then "0#{i}" else "#{i}"
div = document.createElement 'div'
div.setAttribute 'id', "#{lab.name}-#{machine}"
div.setAttribute 'class', 'Grey'
div.innerHTML = machine
td.appendChild div
# Create a div for each machine in a given lab
createDiv machine for machine in [lab.first..lab.last]
# Append the new table data element to the table row.
tr.appendChild td
Is there a better, more idiomatic way to create the divs for each lab? Would it be better to avoid the createDiv function and do something like:
for i in [lab.first..lab.last]
machine = if i < 10 then "0#{i}" else "#{i}"
div = document.createElement 'div'
div.setAttribute 'id', "#{lab.name}-#{machine}"
div.setAttribute 'class', 'Grey'
div.innerHTML = machine
td.appendChild div
The CoffeeScript language reference says
Most of the loops you'll write in CoffeeScript will be comprehensions over arrays, objects, and ranges.
and
Comprehensions should be able to handle most places where you otherwise would use a loop, each/forEach, map, or select/filter
I'm new to the idea of list comprehensions and want to make sure that I'm translating this code in a way that leverages the strengths of CoffeeScript appropriately.
Would it be better to avoid the createDiv function and just inline it?
Yes, that function looks a bit superfluous.
I'm new to the idea of list comprehensions and want to make sure that I'm translating this code in an appropriate way
The aim of list comprehensions is to build new lists, like map and filter would do it. And for which loops or (inappropriately) forEach was used often, manually pushing to an array.
However, your aim is not to create an array, but a DOM element only. Comprehensions don't help here, you will need to use them as loops to execute side effects.

adding line breaks to array values javascript

Here is my javascript array:
var quizArray = [
'When the weather is agreeable what do you prefer to do the most?~Something outside...Obviously!~I tend to enjoy things that aren\'t dependent on weather.~Read, possibly outside if I can find my sunscreen.~Do what I always do, which is whatever I want.~Try something new, like Planking.~~~','It\'s a weeknight and friend invites you to an orchestra. You would?~Kindly refuse. It\'s just not my thing.~Go, unquestionably. I love all art forms.~Ask who the composer is, then read all about them before going.~Confuse Orchestra with Opera and begin singing in Latin.~Go if the tickets are free, otherwise no.~~~',]
When I load my html it won't display line breaks after each answer. I've tried adding a .join(<\br>) after split, but that breaks up every single word, here is the code I have:
function displayQuiz(ent, qnum) {
perPage++;
var qna = quizArray[qnum].split('~');
var od = []; for (var i = 1; qna[i] != null && qna[i] != ''; i++) od.push(i); od.sort( randOrd ); od.sort( randOrd );
var newF = document.createElement("form");
var newDq = document.createElement("div");
newDq.className = 'question';
newDq.appendChild(document.createTextNode(Number(qnum+1)+ ': ' +qna[0]));
newF.appendChild(newDq);
newDq = document.createElement("div");
newDq.className = 'answers';
for (var i = 1; qna[i] != null && qna[i] != ''; i++) {var newDa = document.createElement("label"); newDa.htmlFor = 'a'+qnum+i; /*#cc_on #if (#_jscript) var newR = document.createElement("<input name='a"+qnum+"'>"); #else */
var newR = document.createElement("input");
newR.name = 'a'+qnum; /* #end #*/
newR.type = 'radio';
newR.id = 'a'+qnum+i;
newR.value = od[i-1];
newDa.appendChild(newR);
newDa.appendChild(document.createTextNode(' '+qna[od[i-1]]+' '));
newDq.appendChild(newDa);}
newF.appendChild(newDq);
document.getElementById('quiz'+perPage).appendChild(newF);
}
I'll try my best to post additional info if needed. I did use this as a snippet and am very novice on Javascript. Not opposed to learning on my own but I've poured over the interwebs and cannot find my answer.
to make an array of Strings its better if you put your complete string in a var and after make a split(), and for add you can use a join() or a for()
It's better put this way the code
var quizArray = 'When the weather is agreeable what do you prefer to do the most?~Something outside...Obviously!~I tend to enjoy things that aren\'t dependent on weather.~Read, possibly outside if I can find my sunscreen.~Do what I always do, which is whatever I want.~Try something new, like Planking.~~~';
function displayQuiz(ent, qnum) {
perPage++;
var qna = quizArray.split('~');
var res = qna.join(" <br> ");
return res;
}
Here is the approach that I took, using .join to add the br element. I think you weren't specifying what to split on originally, if it added br after every word.
var string = 'When the weather is agreeable what do you prefer to do the most?~Something
outside...Obviously!~I tend to enjoy things that aren\'t dependent on weather.~Read, possibly outside if I can find my sunscreen.~Do what I always do, which is whatever I want.~Try something new, like Planking.~~~';
var quizArray = string.split('~');
var finalString = quizArray.join('<br/>');
document.getElementById('yourIdHere').innerHTML = finalString;
Here's a fiddle: http://jsfiddle.net/brettwlutz/Q35J2/1/
i thought arrays were made as so:
var arr = [val1, val2, val3];
you can use arr.push to append more values or arr.unshift to add values to the beginning of the array
http://jsfiddle.net/h_awk/K3kEv/
<script>
var arr = [1, 2, 3, 4], i;
for( i=0; i<arr.length; i++ )
{
document.write(arr[i] + '<br />');
}
</script>
First, to answer your question. The above code should work and make the variable qna contain the new, split array. Your solution of adding .join("") should then turn that new array into a single string with html newlines. That is, unless you want t JS newline, in which case you should instead use .join("\n").
My question for you is, why are you starting with an array with only one element? A string can be split into an array and joined back into a string the same way. Also, it may be easier to, instead of using the tilde ~ to seperate the statements you want to split, just use a form of proper array syntax, then get rid of the "split" and just use the joining:
var quizArray = ["When the weather is agreeable what do you prefer to do the most?", "Something outside...Obviously!, I tend to enjoy things that aren\'t dependent on weather.", "Read, possibly outside if I can find my sunscreen.", "Do what I always do, which is whatever I want.", "Try something new, like Planking."];
My only possible understanding is that you are still learning JS and this is just an example for learning how to split arrays, but this is not really a real-life application, which is why this post seems questionable to Stack Overflow users.

Testing function that creates a list of DOM components

I have a function which creates an Array of components. Each component is an outer div with a few inner divs.
function createDivs(quizQuestions) {
var returnElements = new Array();
$.each(quizQuestions.questions, function(i, val){
// create the div.
quizDiv = $('<div class="questionContainer radius">')
questionDiv = $('<div class="question"><b><span>QuestionText</span></b></div>');
quizDiv.append(questionDiv);
// Now change the question div text.
questionDiv.text = val.question;
answerDiv = $('<div class="answers">');
// ...
// ...
// Now the answers.
questionDiv.append(answerDiv);
returnElements[i] = quizDiv;
});
return returnElements;
I pass JSON such as:
{questions:[{"question":"Name the best Rugby team?",
"answers":["Leinster", "Munster", "Ulster", "Connaught"],
"correct_answer":"Leinster"},
{"question":"Name the best DJ?",
"answers":["Warren K", "Pressure", "Digweed", "Sasha"],
"correct_answer":"Leinster"}]};
I'd like to write a simpe unit test so that I could test the array of div returned made sense
Any tips?
Also, are my better to return a DOM component or just text? The latter would be easier to test.
Thanks.
Not sure exactly what you want to test but it is far more performant to create as much html in strings as you possibly can to reduce function calls. Also append is expensive so ultimately making one string for all the new content represented by the JSON will be the biggest performance gain.
In my opinion it also makes code more readable since fragments are in same order as the would be in html editor
Example(my preferece is creating an array of all the string fragments, concatenation also commonly used):
var newcontent = [];
$.each(quizQuestions.questions, function(i, val) {
newcontent.push('<div class="questionContainer radius">');
newcontent.push('<div class="question"><b><span>' + val.question + '< /span></b > < /div>');
$.each(val.answers, function(idx, answer) {
newcontent.push('<div class="answers">' + answer + '</div > ')
})
newcontent.push(' </div></div > ');
});
Then to add content to DOM:
$('#someDiv').append( newcontent.join(''));
disclaimer: Not fully checked for proper closing/nesting of tags.

Sorting li's in jQuery loaded divs

I make a 3 language website, where I need to sort the comments from all the 3 languages, that they are visible on every language's pages. http://www.polinapasztircsak.com/guestbook/
I tried loading with jQuery .load method, and it works, but the problem is that it loads the separate languages in divs (I didn't know other way to load and append it) and I can't sort the comment lis outside their divs. Here is the code:
var commEng = $('<div></div>').load('../guestbook/ .comment');
var commHun = $('<div></div>').load('../vendegkonyv/?lang=hu .comment');
var commIta = $('<div></div>').load('../libro-ospiti/?lang=it .comment');
$(".commentlist").empty().append(commEng).append(commHun).append(commIta);
Do you have some other suggestion how I could load in the lis, that I have them together in the same ul, and then which method or plug-in to use for sorting that.
You can try using $.get or any other ajax functions to load the comments, then sort them using Javascript's sort function. The code would look something like this:
var loaded = 0,
sites = 3,
comments = [];
function getComments(url){
$.get(url, function(data){
comments[loaded++] = ($(data).find('.comment'));
if(loaded === sites){
var insert = comments[0];
for(var i = 1; i < comments.length; i++){
insert = insert.add(comments[i]);
}
$('.commentlist').append(insert.sort(function(a, b){
var dateA = new Date($.trim($(a).find('.comment-meta:first a').text()).replace('at', '') + ' GMT'),
dateB = new Date($.trim($(b).find('.comment-meta:first a').text()).replace('at', '') + ' GMT');
return dateB.getTime() - dateA.getTime();
}));
}
});
}
getComments('../guestbook/');
getComments('../vendegkonyv/?lang=hu');
getComments('../libro-ospiti/?lang=it');
This will sort the jQuery element received through ajax with sort() by passing in a function that will compare the dates of the comments scraped from the comment meta. Also remember that divs in ul unordered list is not valid HTML.

Categories