Reputation: 27
Im struggling to write certain parts of my html code to my file in the middle of my script tag.
I have document.Write currently but it does not pass through my validator and need a solution that would. Ive tried creating a text node and appending, and also innerHTML but neither seem to work, any help?
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
New Perspectives on JavaScript, 2nd Edition
Tutorial 3
Case Problem 2
Congressional Election Results
Author:
Date:
Filename: election.htm
Supporting files: back.jpg, logo.jpg, results.css, votes.js
-->
<head>
<title>Congressional Races</title>
<link href="results.css" rel="stylesheet" type="text/css" />
<script src="votes.js" type="text/javascript"></script>
<script src="barchart.js" type="text/javascript"></script>
<script>
function totalVotes(votes) {
var total=0;
for (var i=0; i<votes.length; i++) total+=votes[i];
return total;
}
function calcPercent(item, sum) {
return Math.round(100*item/sum);
}
function createBar(partyType, percent) {
switch (partyType) {
case "D": barText="<td class='dem'> </td>";break;
case "R": barText="<td class='rep'> </td>";break;
case "I": barText="<td class='ind'> </td>";break;
case "G": barText="<td class='green'> </td>";break;
case "L": barText="<td class='lib'> </td>";break;
}
for (var j=1; j <= percent; j++) document.write(barText);
}
function showResults(race, name, party, votes) {
var totalV=totalVotes(votes);
document.write("<h2>"+race+"</h2>");
document.write("<table>");
document.write("<tr><th>Candidate</th><th class='num'>Votes</th><th class='num'>%</th></tr>");
for (var i=0; i < name.length; i++) {
document.write("<tr>");
document.write("<td>"+name[i]+" ("+party[i]+")</td>");
document.write("<td class='num'>"+votes[i]+"</td>");
var percent = calcPercent(votes[i],totalV);
document.write("<td class='num'>("+percent+"%)</td>");
createBar(party[i], percent);
document.write("</tr>");
}
document.write("</table>");
}
</script>
</head>
<body>
<div id="intro">
<p><img src="logo.jpg" alt="Election Day Results" /></p>
<a href="#">Election Home Page</a>
<a href="#">President</a>
<a href="#">Senate Races</a>
<a href="#">Congressional Races</a>
<a href="#">State Senate</a>
<a href="#">State House</a>
<a href="#">Local Races</a>
<a href="#">Judicial</a>
<a href="#">Referendums</a>
</div>
<div id="results">
<h1>Congressional Races</h1>
<script type="text/javascript">
showResults(race[0],name1,party1,votes1);
showResults(race[1],name2,party2,votes2);
showResults(race[2],name3,party3,votes3);
showResults(race[3],name4,party4,votes4);
showResults(race[4],name5,party5,votes5);
</script>
</div>
</body>
</html>
Upvotes: 0
Views: 195
Reputation: 19772
Unless you are writing a fully fledged javascript web component, keep your HTML as HTML. When you want to change layout it's easier to deal with HTML in an HTML editor when it isn't buried in javascript.
I'm going to use the <template>
element. Note that if you need to support IE you will need to use a pollyfill or <script type="text/template>
, which requires a little extra work.
function showResults(race, name, party, votes) {
//Clone the template
var clone = document.importNode(document.getElementById("templateRace").content, true);
//To update the clone we need to move it to a temporary item
var holder = document.createElement('div');
holder.appendChild(clone);
//replace the simple data
holder.innerHTML = holder.innerHTML
.replace(/{{race}}/g, race);
var totalVotes = votes.reduce(function(acc, curr) {
return acc + curr
});
//Add Rows
for (var i = 0; i < name.length; i++) {
//Clone the row template
var rowClone = document.importNode(document.getElementById("templateRow").content, true);
var percent = 100 * votes[i]/totalVotes;
var partyClasses = {
"D": "dem",
"R": "rep",
"I": "ind",
"G": "green",
"L": "lib"
}
//To update the clone we need to move it to a temporary item
var rowHolder = document.createElement('tbody');
rowHolder.appendChild(rowClone);
//replace the simple data
rowHolder.innerHTML = rowHolder.innerHTML
.replace(/{{name}}/g, name[i])
.replace(/{{party}}/g, party[i])
.replace(/{{votes}}/g, votes[i])
.replace(/{{percent}}/g, percent)
.replace(/{{percWidth}}/g, parseInt(percent * 2, 10))
.replace(/{{partyClass}}/g, partyClasses[party[i]]);
//Add the row to the tbody
holder.querySelector("tbody").appendChild(rowHolder.querySelector("tr"));
}
//Add the full details
document.getElementById("res").appendChild(holder.querySelector("section"));
}
showResults("Race 1", ["Bill", "Ben", "Brian", "Betty"], ["D", "R", "I", "G"], [15, 25, 10, 50]);
//showResults(race[0],name1,party1,votes1);
/*showResults(race[1],name2,party2,votes2);
showResults(race[2],name3,party3,votes3);
showResults(race[3],name4,party4,votes4);
showResults(race[4],name5,party5,votes5);*/
.dem {background-color: red;}
.rep {background-color: blue;}
.ind {background-color: yellow;}
.green {background-color: green;}
.lib {background-color: black;}
.party {display:inline-block;}
<body>
<div id="intro">
<p><img src="logo.jpg" alt="Election Day Results" /></p>
<a href="#">Election Home Page</a>
<a href="#">President</a>
<a href="#">Senate Races</a>
<a href="#">Congressional Races</a>
<a href="#">State Senate</a>
<a href="#">State House</a>
<a href="#">Local Races</a>
<a href="#">Judicial</a>
<a href="#">Referendums</a>
</div>
<div id="results">
<h1>Congressional Races</h1>
<div id="res">
</div>
<template id="templateRace">
<section>
<h2>{{race}}</h2>
<table>
<thead>
<tr>
<th>Candidate</th><th class='num'>Votes</th><th class='num'>%</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</section>
</template>
<template id="templateRow">
<tr>
<td>{{name}} ({{party}})</td>
<td class="num">{{votes}}</td>
<td class="num">{{percent}}</td>
<td class="party {{partyClass}}"><div style="width:{{percWidth}}px; height:100%"> </div> </td>
</tr>
</template>
</div>
Upvotes: 0
Reputation: 5171
You've told the parser "this is a XML document, specifically one that follows the rules of XHTML; please treat it as such" by including the boilerplate at the top of the document:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
But then you switch to an entirely different language that isn't legal XML:
<script>
function totalVotes(votes) {
var total=0;
for (var i=0; i<votes.length; i++) total+=votes[i];
The XML parser hums along (noting that you're missing the required type
attribute in your <script>
tag) until it sees i<votes.length;
. It thinks <votes.length
is the start of a tag, gets very confused, and starts throwing out errors left and right. To tell the parser "just ignore this part; it's not for you", add CDATA tags (and comment them out for when your page gets served up as HTML instead of XHTML):
<script type="text/javascript">
/*<![CDATA[*/
function totalVotes(votes) {
var total=0;
for (var i=0; i<votes.length; i++) total+=votes[i];
return total;
}
/*]]>*/
</script>
(This will validate, but not work, because document.write
doesn't work in XML for compliance reasons. That's okay, because you really shouldn't be using document.write
to begin with. Just use your innerHTML
solution.)
Dealing with XML and XHTML is a headache, and unless you specifically need to (which you don't), you're better off using modern HTML5. The boilerplate gets a lot shorter:
<!doctype html>
<html>
That's it. No DTDs, no namespaces, no CDATAs. It just works.
Upvotes: 1
Reputation: 862
I would suggest you don't use document.write, as each subsequent document.write overwrites the previous one. Instead I suggest you dig into template literals: https://www.youtube.com/watch?v=NgF9-pdTDGs and document.body.innerHTML.
const variableExample = 'Heading content';
document.body.innerHTML = `
<div>
<h1>${variableExample}</h1>
<p>I am some content!!</p>
</div>
`;
Upvotes: 2