uhhuh
uhhuh

Reputation: 27

How can I write HTML code in my script tag?

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

Answers (3)

Jon P
Jon P

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

AuxTaco
AuxTaco

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.)


The better way

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

Devin Olsen
Devin Olsen

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

Related Questions