1

I have two tab controls: one to insert HTML text and the other to insert CSS text. Then I have a Preview to view the output (HTML + CSS). The problem is that in the preview I only display the HTML of the content, but I don't also display the CSS of the content.

enter image description here

I am using this function in JavaScript:

 function showPreview() {
    var htmlContent = document.getElementById("editor").innerText;
    var cssContent = "<style>" + document.getElementById("cssContent").value + "</style>";
    var frame = document.getElementById("preview-window");
    // var jsContent = "<scri" + "pt>" + document.getElementById("jsCode").value + "</scri" + "pt>";

    // Create a data URL with the HTML content
    var dataURL = "data:text/html;charset=utf-8," + encodeURIComponent(htmlContent + cssContent);
  
    // Set the iframe src attribute to the data URL
    frame.src = dataURL;
  }
  
  showPreview()

What am I doing wrong? How to solve?

Code Snippet

function showPreview() {
  var htmlContent = document.getElementById("editor").innerText;
  var cssContent = "<style>" + document.getElementById("cssContent").value + "</style>";
  // var jsContent = "<scri" + "pt>" + document.getElementById("jsCode").value + "</scri" + "pt>";
  var frame = document.getElementById("preview-window");

  // Create a data URL with the HTML content
  var dataURL = "data:text/html;charset=utf-8," + encodeURIComponent(htmlContent + cssContent);

  // Set the iframe src attribute to the data URL
  frame.src = dataURL;
}

showPreview()
#editor,
#cssContent {
  width: 456px;
  height: 267px;
  padding: 10px;
  background-color: #d8d8d8;
  color: rgb(0, 0, 0);
  font-size: 14px;
  font-family: monospace;
  white-space: pre;
}
<!-- Bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://getbootstrap.com/docs/5.3/assets/css/docs.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>


<div class="container">

  <ul class="nav nav-tabs" id="myTab" role="tablist">
    <li class="nav-item" role="presentation">
      <button class="nav-link active" id="home-tab" data-bs-toggle="tab" data-bs-target="#home" type="button" role="tab" aria-controls="home" aria-selected="true">HTML</button>
    </li>
    <li class="nav-item" role="presentation">
      <button class="nav-link" id="profile-tab" data-bs-toggle="tab" data-bs-target="#profile" type="button" role="tab" aria-controls="profile" aria-selected="false">CSS</button>
    </li>
  </ul>

  <div class="tab-content" id="myTabContent">
    <div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">
      <div id="editor" contenteditable="true" oninput="showPreview();">&lt;div>This is a Div&lt;/div>
      </div>
    </div>


    <div class="tab-pane fade" id="profile" role="tabpanel" aria-labelledby="profile-tab">
      <div id="cssContent" contenteditable="true" oninput="showPreview()">&ltstyle&gt div { background-color: blue; color: white; } &lt/style&gt

      </div>
    </div>


  <h3>PREVIEW</h3>
  <div class="preview-area">
    <iframe id="preview-window"></iframe>
  </div>

</div>

4
  • But more importantly, why are you using .innerText to get the HTML, but .value to (fail at) get(ting) the CSS? Commented Jan 4, 2024 at 23:29
  • @RokoC.Buljan You are right. The Javascript tab is not needed. It's only for figurative reasons, because initially I also wanted to add js, so html+css+js, but then I preferred to summarize the question and the code. In a few minutes I will delete it and edit it :) Commented Jan 4, 2024 at 23:34
  • @Mike 'Pomax' Kamermans I'm new, i've only been using Javascript, so please excuse me. I found this code on the web. .innerText was already present in the code I found. Initially it worked well and correctly. The problem arose when they advised me to use a data url, because previously I used a frame with open, write and close. In frame.write I used frame.write(htmlCode + cssCode) and everything worked fine. However, can you explain yourself better please? Should I NOT use .innerText and should I not use .value for the css? Commented Jan 4, 2024 at 23:40
  • The reason I asked is because you have two identical divs, but you're using two different ways of getting the content. That should get you thinking. One of those is probably wrong, probably the one that's not doing what you want (but possibly even both) Commented Jan 5, 2024 at 0:47

1 Answer 1

2

Modified the tabs IDs and aria labels to match what you're building.
Don't hardcode <style> in the editor and again when porting it to css. Use those tags only in the variable. Otherwise you'll end up having <style><style> twice.
Make proper use of Element.textContent instead of .innerText or .value (since you're using contenteditable attribute on DIV Elements). Not thoroughly tested but should give you a firm point to move forward:

const elHTML = document.querySelector("#html");
const elCSS = document.querySelector("#css");
const elJS = document.querySelector("#js");
const elPreview = document.querySelector("#preview");

function showPreview() {
  const html = elHTML.textContent;
  const css = `<style>${elCSS.textContent}</style>`;
  const js = `<scr` + `ipt>${elJS.textContent}</scr` + `ipt>`;
  const dataURL = "data:text/html;charset=utf-8," + encodeURIComponent(css + html + js);

  elPreview.src = dataURL;
}

showPreview()
.container-fluid {
  display: flex;
}

#editor {
  flex: 1;
}

#html,
#css,
#js {
  padding: 1rem;
  height: 160px;
  background-color: #d8d8d8;
  color: rgb(0, 0, 0);
  font-size: 14px;
  font-family: monospace;
  white-space: pre;
}

#preview {
  display: block;
  width: 100%;
}
<!-- Bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://getbootstrap.com/docs/5.3/assets/css/docs.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>


<div class="container-fluid">

  <div class="area" id="editor">
    <ul class="nav nav-tabs" id="myTab" role="tablist">
      <li class="nav-item" role="presentation">
        <button class="nav-link active" id="html-tab" data-bs-toggle="tab" data-bs-target="#html" type="button" role="tab" aria-controls="html" aria-selected="true">HTML</button>
      </li>
      <li class="nav-item" role="presentation">
        <button class="nav-link" id="css-tab" data-bs-toggle="tab" data-bs-target="#css" type="button" role="tab" aria-controls="css" aria-selected="false">CSS</button>
      </li>
      <li class="nav-item" role="presentation">
        <button class="nav-link" id="js-tab" data-bs-toggle="tab" data-bs-target="#js" type="button" role="tab" aria-controls="js" aria-selected="false">JAVASCRIPT</button>
      </li>
    </ul>

    <div class="tab-content" id="myTabContent">

      <div id="html" class="tab-pane fade show active" role="tabpanel" aria-labelledby="html-tab" contenteditable="true" oninput="showPreview();">&lt;div>This is a DIV&lt;/div>
      </div>

      <div id="css" class="tab-pane fade" role="tabpanel" aria-labelledby="css-tab" contenteditable="true" oninput="showPreview()">* { margin: 0; box-sizing: border-box; }
div {
  background-color: blue;
  color: white;
}</div>

      <div id="js" class="tab-pane fade" role="tabpanel" aria-labelledby="js-tab" contenteditable="true" oninput="showPreview();">addEventListener("click", () => {
    alert("hello!");
});</div>
    </div>
  </div>
  
  <div class="area">
    <h3>PREVIEW</h3>
    <div class="preview-area">
      <iframe id="preview"></iframe>
    </div>
  </div>
</div>

Also you might find interesting: Make a simple code editor

Sign up to request clarification or add additional context in comments.

7 Comments

Wow, thanks for your reply. Great! I've seen you use $ several times. I'm new to Javascript and still learning, so forgive the trivial question: have you used jQuery? I ask because I've seen that $ is used often with jQuery. I'm 99% sure it's not jQuery (which I've never used), but I'd rather ask you.
@Nodigap no, that's not jQuery (you can see I did not included the jQuery library) the $ is the first stop character for a Template Literal (String) `Hello, ${planetVariable}!` - notice the backticks: ` This format eases the interpolation of variables into strings without the need to produce clumsy and unreadable string concatenations using + like "Hello, " + planetVariable + "!"
Ok, thanks. Sorry for the trivial question, but being new, I just wanted to be sure. Excuse me. What's the difference between using Element.textContent and .innerText anyway? Also, why was my .value incorrect? Thank you
.value is used to get the property value from an Form action Element like input textarea etc. The HTMLElement DIV does not inherits that property therefore you use either Element.textContent or the less preferred Element.innerText. Find out about the difference here: innerText vs textContent (read also the comments on the provided answers!).
OK perfect. A thousand thanks. I vote and accept your question. Thank you. You're great. Very kind :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.