How do I assign a key when using split()

Thanks - I’m getting comfortable with the standard for loop but I haven’t tried it with the “in” keyword.

Would converting the text into JSON format work? I suppose it would just be [ { “really long string…” } ]. Then I could use fetch() and also remove the input button so as not to lose the data. I could maybe add a small button in the footer t add the input field back for a new file upload.

That only means that the selector for the input field doesn’t work. In my example, the input had no class, in yours, it has a class of .fileupload:

<input type="file">

let input = document.querySelector('input');

With a class selector:

<input type="file" class="fileupload">

let input = document.querySelector('.fileupload');

You already have the content in the variable file, you can log it out with console.log(file), or split the whole string up into separate words with let words = file.split(' ')… you can do anything you want with it.
In your code (I’ve changed some variable names because you had declared file twice):

let input = document.querySelector('.fileupload')

input.addEventListener('change', () => {

  const file = input.files[0];

  let reader = new FileReader();

  reader.onload = (e) => {
    const fileContent = e.target.result;
    console.log(fileContent) //<!-- here is your text string
  };
  reader.onerror = (e) => alert(e.target.error.name);
  reader.readAsText(file);
});

That does essentially the same as the code as I posted above: Read the file, and put it in a variable fileContent.

Let me check the code I have for that file variable repeated. I did change your element selectors to my class selectors but maybe I made a mistake.

I should probably start a new thread. I’m pulling in the text and calling it user-input or something like that. I have to sort by count then start outputting onto the page. But I really need to figure out how to get a user’s text into a js variable. That is the subject of the post I should do to end this thread. Either from a file upload or submit the content in a textarea , etc. Thanks!

I’m not sure what else I can say, I posted a full working solution including HTML and script above. This was the script:

    const input = document.querySelector('input');

    input.addEventListener('change', async () => {
      let file = input.files[0];
      const fileContent = await file.text();
      console.log(fileContent) //<-------the content of the file is in this variable
    })

If your input has a class, you just change the input selector (the dot at the beginning is important):

const input = document.querySelector('.your-class-here');

That’s probably it then. I did forget the dot for the code I found and then added it. I may have done the same for yours but forgot to test it again with the dot.

That’s what it was - works now, sorry to suggest that it didn’t but what do you expect from someone at my level? My bad. I added return fileContent instead of console.log. How would I get that file content? Would I turn the event listener into a variable?

let userContent = input.addEventListener…

No worries, FCC doesn’t really teach DOM manipulation, it’s something very different than algorithms and handling arrays and objects.

Now for your script: When you open a website, the whole JavaScript will be executed top to bottom right away. Long before the user has entered anything. So when you need to wait for some user input to process that input later, all the code that needs this input has to go inside the curly braces of the event listener callback function.

Some code with comments to make it clearer:

// all the top level code runs immediately, for example:

const myArray = [1, 2 ,3];
let myString = 'abc';
// and so on

const input = document.querySelector('input');

input.addEventListener('change', async () => { // <---- opening curly brace
  let file = input.files[0];

  const fileContent = await file.text();
  
  const words = fileContent.split(' '); //     the fileContent is only available
  // and so on                          //     inside this block of the script,
                                        //     between the curly braces
}) // <--- closing curly brace

As you can see, most of your code will go inside that block, because outside of it, the variable fileContent is just not defined (yet) and cannot be used for anything. If that seems weird - it’s not, it’s completely normal. A lot of JavaScript code on a website will only run after some event has occured, like a button click, or a file upload.

Yeah, I thought of that and noticed it as a problem for some of the things I was doing. So basically, everything I have so far needs to go inside the addEventListener function. WOW, that’s a lot. Right now I’m working with hard-coded words so I work on the text editor box, a copy button for that, dropdown menus with the words, etc.

To be clear, you can define functions outside of the listener. And then call them later after the fileContent is availabe. For example, a function to sort the words can be defined outside:


function sortWords(words){
  // sort the words
}
// and other functions


const input = document.querySelector('input');

input.addEventListener('change', async () => {
  let file = input.files[0];
  const fileContent = await file.text();

  const words = fileContent.split(' ');
 
  const sortedWords = sortWords(words) //<-- defining it outside is no problem
})

My mind has been musing a bit over your idea, and I was thinking that maybe you’re making it more complicated than it needs to be, and also less user-friendly. If I had to use a web interface to speak, I’d prefer if the words weren’t sorted by how often I use them, but in strict alphabetical order. I can’t say if I use the word “house” more often than the word “hand”. Maybe I do, but “house” coming before “hand” in the list would make it difficult to find it. I’d literally have to go through the whole list.

It makes sense to give the most common words (“the”, “a”, “this”, “that”, “get”, “go”) a special place in a section at the top. Maybe you can also make a section with a few words that the user has marked as “favourite”. For the rest - considering how many words exist - sorting them by how often they’re used might just complicate the interface.

Don’t mind me, I’m just thinking out loud .

Ok, of course just call them in the event listener. I haven’t done much this week because it’s been hot and I work outside. I should get a lot done this weekend.

I’ll let my aunt be the final judge, but I was already thinking of how many words to include on the page and the articles (a, an, the) and conjunctions and common pronouns would be the ones I would choose - probably 4, maybe 5, characters in length max. As for the other words, they would definitely be in alpha order under a flyout of some sort, or an accordion., maybe popup.

And since she went to Villanova, I would assume that word would be on the special list. I have to think of the size of her monitor and where to put the “common” short words, and the keyboard, as well as the actual text area. I’m going to try a few different formats, but I’m thinking left-sidebar for common words, right for “special” words, and the links for the alphabet letters above or below the text area. Once it’s working, I could probably do a few different formats with little effort. And then I would create a mock email editor for her to copy into Gmail: addresses, subject, body.

Here is a link to a CodePen I created with a limited text source if you want to see what I was visualizing. I can’t figure out how to sort by word after sorting by count so I hard-coded the most common words as my input text. I also can’t figure out how to grab the upload file. Right now if you click on the word “and” under the A link, then that gets added to the textarea field. I have the same functionality for the letter Q but you have to make some changes in the code.

Does appendChild() tack on the “value” without overwriting the content that is there? I think that is what I need because right now I only get a single “and” or “Q”. I have to figure out how to have Shift and Caps work in tandem with the keyboard characters.

Last question: do I need to use a for loop of Switch/Case to loop through each alphabet letter? Right now I have if / if-else statements but that seems like a lot of redundant code. So does a lot of switch & case statements. Do I somehow link 2 arrays or compare one array to another to return what I want?

Right now I have 20+ let variables so I’m sure you’ll get a laugh from that. Thanks for your help and if you could reply with topics or methods I should look into, then I would be very grateful!

That project has grown quite a lot, looks good. I’ll start with your pageOutput function - you’re right, you don’t need tons of if/elses or a switch. All the ul for each letter have a uniform id lettera, letterb and so on. So you can use that to find the right ul by looking at the first letter of a word.

I’ve changed the way you append the word-buttons to the uls a bit (see below why):

function pageOutput(arr) {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i].count > 0 && arr[i].word != "") {

      // create a <li> element, fill it with the right text content and
      // give it a class, for later reference
      let textButton = document.createElement('li');
      textButton.textContent = arr[i].word;
      textButton.classList.add('text-btn'); 

      
      // find the right ul for this word
      let firstLetter = arr[i].word.charAt(0);
      let id = `letter${firstLetter}`;
      let ul = document.getElementById(id);


      // The if statement only prevents possible errors, 
      // caused by the last ul with id letterxyz
      if (ul){
        ul.insertAdjacentHTML("beforeend", outputHTML);
      }
    }
  }
}

That function now takes all your words and puts them into the <ul> where they belong. You can tweak it a bit to account for the fact that the x, y and z words are a special case.


Now for how to put the words into the textarea when you click on them. Each of the text-buttons now has a class, which can be targeted by using .getElementsByClassName or .querySelectorAll (doesn’t matter which). You can loop over them, give them all an event listener, so when you click on a word, it’ll append that text to the text-box. Right now you’re using innerHTML, which will completely override everything that’s already in the text box, so instead, you can take the text that’s already in there, and just append the new word to it. In code:

const textBox = document.getElementById("text-box");
const textBtns = document.getElementsByClassName('text-btn');

for (let i=0; i < textBtns.length; i++){
  textBtns[i].addEventListener('click', e => {
      const word = e.target.textContent;
      textBox.textContent = textBox.textContent + word + " ";
  })
}

As for reading the file, it does work - I tried to upload a test text file and it correctly logged out the file content. I’m not sure if I would worry much about this, because analysing the text is a separate task. You can’t build the page (append all the buttons) unless the words are already available in your script. I also see nothing wrong in hard-coding the most common/most used words. Anyway, that was already a lot to digest… get back if something didn’t make sense.

Wow, that’s a lot of great help. I forgot about using “+” to append but then I think that is recursion which is confusing to me. All that helps a lot - THANKS!

jsdisco, thanks for all the help so far. I would like the user to somehow be able to upload a file, but I think the link of words should be kept to a minimum. Though I could probably do an analysis on the frequency of each word and the length of each word and add the words that have high frequency and lots of letters. But that is for later. I have a few more problems if you don’t mind. Here is my CodePen link again, but now I have:

  1. Backspace button working using slice() but ONLY at the end of the text-box string
  2. Caps button working
  3. Spacebar working but ONLY at the end of the text-box string

I really need to figure out how to

  1. create a line break when the Enter button is clicked.
  2. it would be nice to see a cursor in that editable div, especially when you do break to a new line.

I’ll try to figure out how to select and delete all the text later but that is something else I would like and then it should be good enough to use for my Aunt.

On a side note, what do you think about creating a portfolio main page, and other pages like for this app, using .html extensions? I’m sure I can add files into my public_html folder alongside my WordPress files. Do you think it would be bad for a potential employer to see html file extensions? If so, do I just save my files as .php and upload them that way? Also, what would be the job title BELOW Jr. Front End Developer?

Anyway, if you could point me in the right direction for the line break that would be great - and thanks again.

I’m currently taking a break from coding so I’ll bump this, and hopefully someone else will answer (or you can open a new thread, since the topic has moved quite a bit from what the title suggests).

Got it - I’ll start a new post