Presenting user with options and executing a function based on user choice in Javascript I'm currently creating a text based game where the user navigates through the game via buttons and i'm trying to improve on my code because i'm pretty sure it could be alot better, the following is some code which i wrote to give the user some options (via html buttons) and then check what their selection is in order to execute the correct function.
class Room {
    
    constructor(description, options) {
        
        this.description = description;
        this.options = options;
        
    }
}

 var f1hallway = new Room(&quot;You see two rooms&quot;, [&quot;Room 1&quot;, &quot;Room 2&quot;]);

 var f1room1 = new Room(&quot;You find a letter on a table&quot;, [&quot;Read it&quot;, &quot;Exit&quot;]);
    
 var f1room2 = new Room(&quot;Nothing of interest here&quot;, [&quot;Exit&quot;]);

    whichArea = function(areaSelected) {
                 
                selectedArea = areaSelected;
                areaSelected();
                
              }
              
    function presentChoices(options) {
        
              choices.innerHTML = &quot;&quot;;
            
         for (var x = 0; x &lt; options.length; x++) {
                  
            choiceButton = document.createElement(&quot;button&quot;);
            choiceButton.setAttribute(&quot;class&quot;, &quot;choice-button&quot;);
            choices.appendChild(choiceButton);
            choiceButton.innerHTML = options[x];
            selectedChoiceIndex = x;
            choiceButton.setAttribute(&quot;id&quot;, x);
            
             choiceButton.onclick = function() {
        
                selectedChoice = this.innerHTML;
                chosenOptionId = this.id;
                whichArea(selectedArea);
                
             }
             
             
        }
    
    }

function f1hallwayFunc() {

        mainText.innerHTML = f1hallway.description;
        choices.innerHTML = &quot;&quot;;
        presentChoices(f1hallway.options);
        
        if (chosenOptionId == 0) {
     
            chosenOptionId = null;
            whichArea(f1roomOneFunc);
          
        
        }
        
        else if (chosenOptionId == 1) {
            
            chosenOptionId = null;
            whichArea(f1roomTwoFunc);
            
        }

function f1roomOneFunc() {

    mainText.innerHTML = f1room1.description;
    presentChoices(f1room1.options);
    
     if (chosenOptionId == 0) {
        
        chosenOptionId = null;
        mainTextWrap.innerHTML = &quot;You start reading the letter&quot;;
        
    }
    
    else if (chosenOptionId == 1) {
        
        chosenOptionId = null;
        whichArea(f1hallwayFunc);
        mainText.innerHTML = &quot;You exit the room and return to the hallway&quot;;
        
    }

}

function f1roomTwoFunc() {
    
    mainText.innerHTML = f1room2.description;
    presentChoices(f1room2.options);
    
     if (chosenOptionId == 0) {

        chosenOptionId = null;
        whichArea(f1hallwayFunc);
        mainText.innerHTML = &quot;You exit the room and return to the hallway&quot;;
        
    }
    
}

The code works fine but seems like a mess at the same time, each area that the user ends up in goes through this same process, can someone please tell me how this could be written better and any best practices i'm missing? I'm still quite new to programming and would appreciate any help, thanks!
I think a good way to approach this would be to integrate all the data (descriptions, options, and additional room choices) into an object indexed by room number or step name (since multiple things can be done in a single room). Starting at the first room, parse the data for that room to display the description and choices appropriately, and continue recursively whenever a new choice is made. Doing it this way means that, to set up the rooms, you only need to change around the object room numbers and strings instead of writing convoluted JavaScript logic.
For example, for the hallway and 2 rooms, you could have:
const steps = {
  hallway: {
    desc: 'You see two rooms',
    choices: ['Room 1', 'Room 2']
  },
  'Room 2': {
    desc: 'Nothing of interest here',
    // when the choice description and JS step name are not the same,
    // separate them
    choices: [{ desc: 'Exit', target: 'hallway' }]
  },
  'Room 1': {
    desc: 'You find a letter on the table',
    choices: [
      { desc: 'Read it', target: 'readLetter' },
      { desc: 'Exit', target: 'hallway', onChoiceDesc: 'You exit the room and return to the hallway' }
    ]
  },
  readLetter: {
    // ...
  },
}; 

Whenever a new step runs, if the choice that was just chosen had a onChoiceDesc property, display that. Otherwise, display the desc of the new step onto the page. Iterate through each choice to add a button, a button description, and a click handler.
To conditionally display a choice depending on program state, add a function to the choice object. Eg, if, after reading the letter, something becomes available in the hallway, you could add the following:
choices: ['Room 1', 'Room 2', { desc: 'Room 3', target: 'Room 3', showIf: () =&gt; hasReadLetter }]

readLetter: {
  desc: 'You start reading the letter. The letter informs you that Room 3 exists',
  choices: [
    { desc: 'Exit', target: 'hallway', onChoiceFn: () =&gt; hasReadLetter = true }
  ]
}

where onChoice gets invoked when the button is clicked (in addition to the default behavior of re-rendering the hallway step). (Make sure to have declared a hasReadLetter variable outside.)
That's the general idea - leave the manipulation of the DOM to the other code that parses through the steps object, while writing the meat of the game inside the steps object.

Although you'll probably be ditching most of it, some suggestions regarding your current code:
Classes are good for tying together data with methods related to the data. If all you have is plain data, a class doesn't help you. In your case, unless you were planning on adding methods later, using a plain object would make more sense for the Rooms.
Use consistent indentation so that you (and other readers of the code) can pick up on the { } blocks at a glance. Ideally, use an IDE that indents code properly and automatically. For example, this:
}
 var f1hallway = new Room(&quot;You see two rooms&quot;, [&quot;Room 1&quot;, &quot;Room 2&quot;]);
    whichArea = function(areaSelected) {
                selectedArea = areaSelected;

should be
}
var f1hallway = new Room(&quot;You see two rooms&quot;, [&quot;Room 1&quot;, &quot;Room 2&quot;]);
whichArea = function(areaSelected) {
    selectedArea = areaSelected;

Declare variables before using them - if you don't, you'll either be implicitly assigning to the global object (which is inelegant), or an error will be thrown if running in strict mode (and strict mode is recommended). Not declaring a variable before using it is a not-uncommon source of bugs when one finds that the variable isn't scoped as one expected it to be. The whichArea = should be let whichArea =.
Use modern syntax If you're going to write in ES6+ (which you are with the class, and as you should), never use var, it has too many gotchas to be worth using nowadays - use const instead when declaring variables, or use let when you have to reassign the variable.
Prefer IDL properties over setAttribute when feasible - IDL properties are usually more concise and easier to read and write. These two:
choiceButton.setAttribute(&quot;class&quot;, &quot;choice-button&quot;);
choiceButton.setAttribute(&quot;id&quot;, x);

can be
choiceButton.className = &quot;choice-button&quot;;
choiceButton.id = x;

(though, neither of those should be necessary at all: to target the button with CSS, you should be able to do .choices &gt; button, by giving the parent a class name instead. Dynamic IDs are quite a code smell too - to get the index inside a click handler, either check the child's index in an array of all siblings, or use a data attribute, or a Map - but not an ID. Or, even better, in this case, just use the closure in the click handler over the index being iterated over.)
Prefer .textContent over .innerHTML unless you're deliberately setting text content; .textContent is faster, safer, and more semantically appropriate.
Prefer strict equality - loose equality with == and != has a whole bunch of weird coercion rules that neither you nor others who happen to read the code should have to have memorized to understand what's going on. Use === and !== instead.