0

I have an focus and keydown events. Everytime the input element is out of focus or an enter key is pressed, I update the page to reflect the changes.

The Render class rerenders the currently selected page.

The issue here is that when I update the page with the enter key, both the focusout and kedown events are fired. This code seems to work only if I give the event's callback a timeout.

The question is, is it possible to sovle this "event colission" without setTimeout and why does that happen?

// Page content class
const descriptionInput = document.createElement('textarea');
const handleDescription = function(e){
            if( (e.key === "Enter" && !e.shiftKey) || 
            (e.type === "focusout")
            ){
                task.description = this.value;
                storage.updateTask(task.id, task);
                (new Render).refreshPage()
            }
        }
descriptionInput.addEventListener('keydown', handleDescription)
descriptionInput.addEventListener('focusout', handleDescription)
// Render class
renderPage(contentFunction){
        const pastContent = document.querySelector('.content');
        if(pastContent) this.pageContainer.removeChild(pastContent);
        this.pageContainer.appendChild(contentFunction());
    }
refreshPage(){
    const currentPage = document.querySelector('.sidebar li[selected]');
    switch (currentPage.getAttribute('name')) {
        case 'Active Task':
            this.renderPage(activeTasks);
            break;
        case 'Complete Task':
            this.renderPage(completeTask);
            break;
    }
}
// No error snippit
if( (e.key === "Enter" && !e.shiftKey) || 
        (e.type === "focusout")
        ){
            setTimeout(() => {
                task.description = this.value;
                storage.updateTask(task.id, task);
                (new Render).refreshPage()
            }, 100)
        }
i5x
  • 15
  • 3
  • Why do you need both event listeners? Pressing Enter in an input causes focus to leave, so the `focusout` event will occur automatically. – Barmar Aug 13 '23 at 03:17
  • @Barmar Because I need dynamic input – i5x Aug 13 '23 at 03:24

2 Answers2

0

As stated in this thread, focusout is fired when an input is removed from the DOM. What worked for me is removing the event listener.

const handleDescription = function(e){
            if( e.key === "Enter" && !e.shiftKey ){
                descriptionInput.removeEventListener('focusout', handleDescription);
                task.description = this.value;
                storage.updateTask(task.id, task);
                (new Render).refreshPage()
            }
            if(e.type === "focusout")
            {
                task.description = this.value;
                storage.updateTask(task.id, task);
                (new Render).refreshPage()
            }
        }
i5x
  • 15
  • 3
0

When you focusout by pressing the key. You call function handleDescription twice. To solve this problem, you can use a flag and as long as it is true, the function will not be called again. now you can remove setTimeout.

const descriptionInput = document.createElement('textarea');

let descIsUpdating = false;

const handleDescription = function(e) {

    if (descIsUpdating) {
      return false;
    }

    if ((e.key === "Enter" && !e.shiftKey) ||
        (e.type === "focusout")
       ) {
        descIsUpdating = true; // start updating
        task.description = this.value;
        storage.updateTask(task.id, task);
        (new Render).refreshPage();
        descIsUpdating = false; // updating is finished
    }
};

descriptionInput.addEventListener('keydown', handleDescription);
descriptionInput.addEventListener('focusout', handleDescription);