# Component lifecycle in relation with if.bind

**URL:** https://discourse.aurelia.io/t/component-lifecycle-in-relation-with-if-bind/3856
**Category:** Uncategorized
**Created:** [October 29, 2020, 10:45am UTC](https://discourse.aurelia.io/t/component-lifecycle-in-relation-with-if-bind/3856 "2020-10-29T10:45:28Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![elitastic](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/elitastic/32/1787_2.png) [@elitastic](https://discourse.aurelia.io/u/elitastic)
#### Post date: [October 29, 2020, 10:45am UTC](https://discourse.aurelia.io/t/component-lifecycle-in-relation-with-if-bind/3856/1 "2020-10-29T10:45:28Z")

</div>

Depending on if.bind or show.bind in root component, the lifecycle seems to be different in my component. Does someone have an explanation for that behaviour?

> **[Dumber Gist](https://gist.dumber.app/?gist=8b7a784311cf1073c30b56656a5bf161)**

---

<div class="post-metadata">

### Author: ![huochunpeng](https://avatars.discourse-cdn.com/v4/letter/h/49beb7/32.png) [@huochunpeng](https://discourse.aurelia.io/u/huochunpeng)
#### Post date: [October 29, 2020, 9:32pm UTC](https://discourse.aurelia.io/t/component-lifecycle-in-relation-with-if-bind/3856/2 "2020-10-29T21:32:13Z")

</div>

`if.bind` will append/remove that dom based on condition.  
`show.bind` will **always** render the dom the first time, never remove it from dom tree. It simply toggles a css class `aurelia-hide` on that element.

```css
.aurelia-hide {
display: none !important;
}

```

You can clearly see from dev console that your initial rendering contains one `<my-component>` (instead of zero) with `aurelia-hide` in its class attribute.

---

<div class="post-metadata">

### Author: ![elitastic](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/elitastic/32/1787_2.png) [@elitastic](https://discourse.aurelia.io/u/elitastic)
#### Post date: [October 30, 2020, 1:36pm UTC](https://discourse.aurelia.io/t/component-lifecycle-in-relation-with-if-bind/3856/3 "2020-10-30T13:36:13Z")

</div>

Thanks for your reply. I know this difference, but in my opinion this should not affect the behaviour of bind vs attached:

```
bind()
{
	this.value = 'item-1';
}

attached()
{
	this.divElement.style.backgroundColor = this.divElement.innerHTML == 'item-1'
		? '#0a0'
		: '#a00';
}

```

With show.bind, the bind process is done in attached cycle, with if.bind, the bind process is not yet done in attached cycle. Is this by design? Seems more like a bug to me 😕

---

<div class="post-metadata">

### Author: ![huochunpeng](https://avatars.discourse-cdn.com/v4/letter/h/49beb7/32.png) [@huochunpeng](https://discourse.aurelia.io/u/huochunpeng)
#### Post date: [October 30, 2020, 2:03pm UTC](https://discourse.aurelia.io/t/component-lifecycle-in-relation-with-if-bind/3856/4 "2020-10-30T14:03:33Z")

</div>

Oh, sorry, I totally overlooked your code.

**Bind is before attached, even for the element behind if bind** , you can add console.log in both bind and attached to see that.

But it seems the rendering is not, for the element behind if bind, although bind is before attached, the innerHTML is not yet updated to reflect the model change.

So yes, there must be some rendering timing difference due to the if.bind. @bigopon might know some details.

Aurelia 1 attached did have some quirky timing, Aurelia 2 did clear that up. In Aurelia 1 attached, if you want to make sure dom is ready (especially when it contains some other custom elements), you can use setTimeout inside attached.

```auto
  attached()
  {
    console.log('attached');
    setTimeout(() => {
      this.divElement.style.backgroundColor = this.divElement.innerHTML == 'item-1'
        ? '#0a0'
        : '#a00';
    });
  }

```

---

<div class="post-metadata">

### Author: ![elitastic](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/elitastic/32/1787_2.png) [@elitastic](https://discourse.aurelia.io/u/elitastic)
#### Post date: [November 2, 2020, 7:57am UTC](https://discourse.aurelia.io/t/component-lifecycle-in-relation-with-if-bind/3856/5 "2020-11-02T07:57:06Z")

</div>

Thanks for your help. I used taskQueue.queueMicroTask so far for such situations, could you explain the difference between setTimeout() and queueMicroTask()?

Is setTimeout working reliable here?

---

<div class="post-metadata">

### Author: ![huochunpeng](https://avatars.discourse-cdn.com/v4/letter/h/49beb7/32.png) [@huochunpeng](https://discourse.aurelia.io/u/huochunpeng)
#### Post date: [November 2, 2020, 8:58am UTC](https://discourse.aurelia.io/t/component-lifecycle-in-relation-with-if-bind/3856/6 "2020-11-02T08:58:24Z")

</div>

I use queueMicroTask before too, but moved to setTimout to avoid some DI code.  
There is no much obvious difference. Yes setTimeout is reliable in this case.

In browser without mutation observer api, task queue uses setTimeout.

> <https://github.com/aurelia/task-queue/blob/fe901c416bb6e3402dfea9e283b807ae6c6252b3/src/index.js#L88-L92>

> <https://github.com/aurelia/task-queue/blob/fe901c416bb6e3402dfea9e283b807ae6c6252b3/src/index.js#L19-L38>

---

<div class="post-metadata">

### Author: ![elitastic](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/elitastic/32/1787_2.png) [@elitastic](https://discourse.aurelia.io/u/elitastic)
#### Post date: [November 3, 2020, 3:55pm UTC](https://discourse.aurelia.io/t/component-lifecycle-in-relation-with-if-bind/3856/7 "2020-11-03T15:55:53Z")

</div>

Thanks for your feedback. Please have a look at the gist again (I added some more binding work to test the reliability)

> **[Dumber Gist](https://gist.dumber.app/?gist=661ab43f677e966b89283f13af73f057)**

After 100-150 repeats it stops working… Looks like setTimeout() does not wait for the whole binding process…

---

<div class="post-metadata">

### Author: ![huochunpeng](https://avatars.discourse-cdn.com/v4/letter/h/49beb7/32.png) [@huochunpeng](https://discourse.aurelia.io/u/huochunpeng)
#### Post date: [November 3, 2020, 9:57pm UTC](https://discourse.aurelia.io/t/component-lifecycle-in-relation-with-if-bind/3856/8 "2020-11-03T21:57:50Z")

</div>

Interesting finding.

But it’s not a setTimeout issue, because it can be reproduced with queueMicroTask. It could be an edge case between repeater and if bind.

```auto
import { bindable, autoinject, TaskQueue } from 'aurelia-framework';

@autoinject
export class MyComponent {
  @bindable
  xy: string;
  
  value: string;
  divElement: HtmlDivElement;
  taskQueue: TaskQueue;
  
  constructor(taskQueue: TaskQueue) {
    this.taskQueue = taskQueue;    
  }

  bind()
  {
    this.value = 'item-' + this.xy;
  }
  
  attached()
  {
    this.taskQueue.queueMicroTask(() => {
      this.divElement.style.backgroundColor = this.divElement.innerHTML.startsWith('item')
        ? '#0a0'
        : '#a00';
    });
  }
}

```

---

<div class="post-metadata">

### Author: ![elitastic](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/elitastic/32/1787_2.png) [@elitastic](https://discourse.aurelia.io/u/elitastic)
#### Post date: [November 4, 2020, 5:51am UTC](https://discourse.aurelia.io/t/component-lifecycle-in-relation-with-if-bind/3856/9 "2020-11-04T05:51:42Z")

</div>

I updated the gist, seems like its not due to repeat.for…

> **[Dumber Gist](https://gist.dumber.app/?gist=c773156ab7ab992f0707d59716f7742a)**

It’s very irregular, sometimes it works, sometimes not

---

<div class="post-metadata">

### Author: ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)
#### Post date: [November 6, 2020, 10:42pm UTC](https://discourse.aurelia.io/t/component-lifecycle-in-relation-with-if-bind/3856/10 "2020-11-06T22:42:33Z")

</div>

Here’s an example [https://gist.dumber.app/?gist=0def4fd948542fe32c574a7226bb0c11](https://gist.dumber.app/?gist=0def4fd948542fe32c574a7226bb0c11) with precise timing control & everything related to it. You can see there’ 2 parts:

- `.queueMicroTask()` instead of `.setTimeout()`

- `disableConnectQueue()`

- `.queueMicroTask()` is used, is to handle timing, it needs 1 “tick” after attached to process the binding, as the binding update of `${value}` is queued after `.attached`

- `disableConnectQueue()` is used, to remove an optimization case where startup would queue so many tasks that could slow down free the app for a short period.

* * *

Timing of `if` + `${value}`+ `attached` combo:

1. user clicks on the button, `.showComponent = true` -\> queue update all if bindings
2. Tick 1: `condition` property of `[if]`s receive `true`-\> queue change handler call (`conditionChanged`)
3. Tick 2: `conditionChanged` called, each `[if]` creates its view (includes `<my-component/>` instance), then call `.bind()` synchronously, `.attached()` immediately (synchronously).  
3.1 Calling `bind()` -\> set `value` to true -\> queue binding update for text `${value}`, so HTML is not rendered fully yet for `<my-component/>`, hence `div.innerHTML === ''`
4. Tick 3: `${value}` bindings update

* * *

You can see that step 3 is only 1 tick before step 4, hence we only need to do `.queueMicroTask()` in `attached`, instead of `.setTimeout()`. The `.disableConnectQueue()` is used to remove an optimization in [https://github.com/aurelia/binding/blob/master/src/connect-queue.js](https://github.com/aurelia/binding/blob/master/src/connect-queue.js) for handling extreme cases.

* * *

- If you control the source, then use the source data directly to manipulate, instead of waiting for the DOM to be updated, then get the outcome back to process your data.
- If you have to do so, `.setTimeout()` is a ok way to deal with this, as there could be nested if/repeat etc… Having your code in in a macro task with `setTimeout` will guarantee it runs after all have settled.
- in v2, we no longer employ a micro task queue to propagate binding changes, so you won’t get this issue in v2.
