Randy
Randy

Reputation: 9809

Can I trust setTimeout(fn, 0), or should I use an alternative?

While a lot of questions and answers tell me WHY and WHAT the setTimeout(0) is for, I cannot find a very good alternative for it.

My problem

I have a click handler, which executes a function that signals another class to update its status.

That click handler is on the parent element.

I have a checkbox inside that element, which gets checked or unchecked.

Because the click handler is on the parent element, that gets called first. But I need my checkbox to change status before the signal is send.

So I use setTimeout(0) to prevent the signal to be send before the checkbox is checked.

HTML

<div click.delegate="update()">
    <div class="checkbox">
        <label>
            <input checked.bind="group.validated" type="checkbox"> Visibility
        </label>
    </div>
</div>

JavaScript

update(){
    setTimeout(()=>{
        this.signaler.signal('refresh-groups');
    }, 0);
    return true;
}

Basically, what is happening, is that the return true; is executed before the this.signaler.signal function. That way, the checkbox gets checked before the signal is send. Note this won't happen in regular onclick methods where the checkbox status is updated first, but this is the way the Aurelia framework behaves.

I don't like the feeling that I create here. A timeout of 0 seconds means that the function is at the end of the callstack, nothing more. If anything would happen to my return true; statement causing it to wait 0.1 second, I face the same problem.

Is there any alternative that is more trustworthy? Simply using a Promise doesn't seem to do the trick here.

Upvotes: 1

Views: 1672

Answers (2)

Fabio
Fabio

Reputation: 11990

You could run this.signaler.signal() as Task. For instance:

import {BindingSignaler} from 'aurelia-templating-resources';
import { TaskQueue } from 'aurelia-task-queue';

export class App {

  static inject() { return [BindingSignaler, TaskQueue]; }

  constructor(signaler, taskQueue) {
    this.signaler = signaler;
    this.taskQueue = taskQueue;
  }

  update(){
    this.taskQueue.queueTask(() => {
        this.signaler.signal('refresh-groups');
    });

    return true;
  }
}

See this example https://gist.run/?id=88500143701dab0b0697b17a211af3a7

Upvotes: 0

Jeremy Danyow
Jeremy Danyow

Reputation: 26386

I think the primary issue is you're using the click event which fires before the input element's value changes. Use the change event instead.

https://gist.run/?id=863282464762b54c8cf67de541bac4d3

Upvotes: 1

Related Questions