Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript Interactive Web Pages with JavaScript Traversing and Manipulating the DOM with JavaScript Perfect

editMode interactions

The UX may be questioned but regardless of that, I'm stumped on why the first solution does not work but the second solution does.

Interaction "requirement"

Set a method on editInput like .focus() or .select()

Seemingly simple but broken solution

This seemed to be the simplest, call something like editInput.select() in the containsClass else clause:

var editTask = function() {
  console.log("Edit task...");
  var listItem = this.parentNode;

  var editInput = listItem.querySelector("input[type=text]");
  var editButton = listItem.querySelector("button.edit")
  var label = listItem.querySelector("label");
  var containsClass = listItem.classList.contains("editMode");

  if(containsClass) {
    label.innerText = editInput.value;
    editButton.innerText = "Edit";
  } else {
    editInput.value = label.innerText;
    editButton.innerText = "Save";
    editInput.select();
  }
  listItem.classList.toggle("editMode");
}

Additionally, the above works to the extent that the class is added and the form continues to function. It just without any focus/select changes. No errors are thrown in the console.

Working solution, but why?

See comment at setFocus.

var editTask = function() {
  console.log("Edit task...");
  var listItem = this.parentNode;

  var editInput = listItem.querySelector("input[type=text]");
  var editButton = listItem.querySelector("button.edit")
  var label = listItem.querySelector("label");
  var containsClass = listItem.classList.contains("editMode");
  var setFocus = window.setTimeout(function(){editInput.select();}, 1);
  // setFocus came from: 
    // https://stackoverflow.com/questions/3090420/javascript-will-not-pass-focus-to-element
  // Sets delay timer of 1ms which then allows for .select() or .focus()... etc
  // Unclear why 

  if(containsClass) {
    label.innerText = editInput.value;
    editButton.innerText = "Edit";
  } else {
    editInput.value = label.innerText;
    editButton.innerText = "Save";
    setFocus;
  }
  listItem.classList.toggle("editMode");
}

Last question in this thread, is there a better way altogether?

2 Answers

Steven Parker
Steven Parker
229,786 Points

A testable environment (like a workspace snapshot) would have been helpful here, but based on my memory of this exercise:

The select in the first case probably doesn't work because the element is hidden.

I wasn't able to test it without the complete code, but I'd bet it would work if you just move it after the toggle and wrap it in another test:

  listItem.classList.toggle("editMode"); // <-- existing line
  if (!containsClass) {
    editInput.select();
  }

The tiny delay in the second example is probably long enough for the toggle to take effect before the select is performed.

Also, while it causes no problem, this line in the second example is silly (it does nothing):

    setFocus;

At that point, setFocus contains a timeoutID.

The bit of this that was particularly helpful was the comment about moving the method after the toggle and wrapping in a test. Thanks!

Mark Miller
Mark Miller
45,831 Points

On the stackoverflow site that you referenced, the answer is good. It explains that the natural flow of program control will move the focus to the next element at the end of processing, which will write over the command that you put inside of that function. So, the window.setTimeout() is being used to delay the command until after the execution of the function is completed. Apparently 1 millisecond is long enough!