1

I have a problem with javascript code. I have to make local html which displays lines of text from .txt file. I found a code like this, which does it:

 <script>
 var fileInput = document.getElementById('inputfile');
 fileInput.addEventListener('change', function(e) {
     var file = fileInput.files[0];
     var reader = new FileReader();
     reader.onload = function(e) {
         document.getElementById('output').innerText = reader.result;
 };
     reader.readAsText(file);   
 });
 </script>

However, I need those to be displayed like in this code:

<script type="text/javascript">
    var arr = ['Heading 1','Para1','Heading 2','Para2','Heading 3','Para3'];
    var result = arr.map((val, i) => i%2===0 ? `<h2>${val}</h2>` : `<p>${val}</p>`).join('');
    document.getElementById('test').innerHTML = result ;
</script>

No matter how I try to combine this two, it doesnt seem to work (nothing gets displayed at all). I am rather green with regards to javascirpt, so could someone help me with that and, if possible, explain in rather simple language how is that supposed to be done?

.txt file would look something like:

Position1
description1 
position2 
description2 
pozition3 
...

1 Answer 1

2

Your reader.result in the first example is a single multi-line string. For your second snippet to work, you need an array of strings, one-per-line.

Here's how you can split your multi-line text file in to an array of lines:

const txtFile = `Position1
description1 
position2 
description2 
pozition3`;

const lines = txtFile.split("\n");

console.log(lines);

Once you have these lines, you can proceed as you already showed. One warning: by using innerHTML you run in to the risk of injecting stuff in to your document you might not want. In most cases, it's better to construct the HTML elements in code and use innerText:

const txt = `Hello
This is a paragraph
Heading
Injected scripts! <img src=x onerror="console.log(1234)">`;

const lines = txt.split("\n");

// "Safe" approach: display contents as text
// This will _not_ log 1234
lines.forEach(
  (content, i) => {
    const el = document.createElement(i % 2 === 0 ? "h2" : "p");
    el.innerText = content;
    document.body.appendChild(el);
  }
);

// "Unsafe" approach: use innerHTML
// This _will_ log 1234
lines.forEach(
  (content, i) => {
    const tag = i % 2 === 0 ? "h2" : "p";
    document.body.innerHTML += `<${tag}>${content}</${tag}>`
  }
)

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

5 Comments

So as far as I understood, my "reader.result" is not yet an array, but only a multi line string, so instead of printing it, I should save into array by cutting it line by line using "split" and THEN print it. Right?
You can basically chain everything together: ...innerHTML = reader.result.split("\n").map((val, i) => i%2===0 ? <h2>${val}</h2> : <p>${val}</p>).join(''). I think it's clearer to split it up in to steps like I did above. So if you paste that inside the onload function and replace txt with reader.result it should work.
Another question, in Your second snippet, what does exactly "injected srcipt" does, and why is it also displayed as text?
When you inject HTML on your page by using innerHTML =, the browser will parse it. If the .txt file your user selects contains snippets of HTML, those can mess with your page. So the safest bet is to just display any HTML as text. More info here.
I improved the example in my last snippet: my suggested way shows the <img> tag. The way that's closer to your original approach shows a broken image and logs something to the console. It depends on what you're trying to do whether that's a problem, I just felt the responsibility to mention it. 🙂

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.