# Loading indicator while Value Converter computes?

**URL:** <https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493>\
**Category:** Help Requests\
**Created:** [May 14, 2020, 9:22pm UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493 "2020-05-14T21:22:04Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![m0ngr31](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/m0ngr31/32/1535_2.png) [@m0ngr31](https://discourse.aurelia.io/u/m0ngr31)\
**Post date:** [May 14, 2020, 9:22pm UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/1 "2020-05-14T21:22:04Z")

</div>

I have a function that takes an array and does a bunch of calculations on it. It’s a pretty beefy calculation, so I moved it off to a web worker.

Previously I would have a `rendering` flag on the class that I would set to true before the function ran, and then I’d queue a “microTask” for setting it to false. This allowed me `show.bind=` on a loading spinner components and the array in my view. Once the `rendering` prop was flipped all the data would be there.

That worked great but now I’ve moved the logic into a Value Converter (with a custom binding behavior to allow the promise from the web worker), but now my trick no longer works… The task fires right after the async function finishes up instead of when it finishes rendering. Is there a way to accomplish what I was doing before?

Value converter:

```auto
export class TransformEntriesValueConverter {
    async toView(entries, day) {
        if (!entries) {
            return [];
        }

        return await mapEntries(entries, day);
    }
}

```

Binding behavior:

```auto
export class AsyncBindingBehavior {
    public bind(binding, _scope, callbackFn) {
        binding.originalupdateTarget = binding.updateTarget;

        binding.updateTarget = async a => {
            const d = await a;
            binding.originalupdateTarget(d);

            if (_.isFunction(callbackFn)) {
                callbackFn();
            }
        };
    }

    public unbind(binding) {
        binding.updateTarget = binding.originalupdateTarget;
        binding.originalupdateTarget = null;
    }
}

```

View:

```auto
<template>
  <timeline-container
        repeat.for="day of displayDays"
        if.bind="!day.hidden"
        loading.bind="day.isLoading || day.isRendering"
    >
        <time-entry
            repeat.for="entry of day.entries | transformEntries:day & async:dayLoading(day)"
            item.bind="entry"
            class="timeline-week"
        >
        </time-entry>
    </timeline-container>
</template>

```

ViewModel:

```auto
export class MyClass {
  ...
  public dayLoading(day) {
    this.taskQueue.queueMicroTask(() => {
        day.isRendering = false;
    });
  }
  ...
}

```

---

<div class="post-metadata">

**Author:** ![khuongduybui](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/khuongduybui/32/44_2.png) [@khuongduybui](https://discourse.aurelia.io/u/khuongduybui)\
**Post date:** [May 15, 2020, 4:39am UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/2 "2020-05-15T04:39:57Z")

</div>

This is an interesting question. I don’t have the time for a full-fledge solution now, but if you can make a simple example on [https://gist.dumber.app/](https://gist.dumber.app/) I will try to help you debug your example tomorrow.

---

<div class="post-metadata">

**Author:** ![m0ngr31](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/m0ngr31/32/1535_2.png) [@m0ngr31](https://discourse.aurelia.io/u/m0ngr31)\
**Post date:** [May 15, 2020, 5:11pm UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/3 "2020-05-15T17:11:01Z")

</div>

I’m having an issue getting it to work on that. Something about how it’s importing the CSS (from Webpack looks like?).

This is actually for an open source plugin, so maybe it’s easier to view the issue locally?

Here’s the branch I’m working on: [https://github.com/bindable-ui/bindable/tree/timeline-columns](https://github.com/bindable-ui/bindable/tree/timeline-columns)

If you launch the `dev-app`, the demo page is at [http://localhost:9000/#/components/timeline/demo](http://localhost:9000/#/components/timeline/demo)

If that doesn’t work for you, I can play more with the gist thing to figure it out.

---

<div class="post-metadata">

**Author:** ![zewa666](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/zewa666/32/19_2.png) [@zewa666](https://discourse.aurelia.io/u/zewa666)\
**Post date:** [May 15, 2020, 8:48pm UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/4 "2020-05-15T20:48:17Z")

</div>

Could you instead emit a custom event (either native or event-aggregator) or broadcast a signal from the Binding Behavior which you listen for to toggle the switch? Alternaively the VC could accept a callback as parameter where you’d set your toggle

---

<div class="post-metadata">

**Author:** ![m0ngr31](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/m0ngr31/32/1535_2.png) [@m0ngr31](https://discourse.aurelia.io/u/m0ngr31)\
**Post date:** [May 15, 2020, 9:20pm UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/5 "2020-05-15T21:20:15Z")

</div>

I have a callback in the custom binding behavior. I wouldn’t be able to put on in the VC because the value hasn’t been assigned until it returns.

I think an event would have the same issue as the binding behavior… It just fires in the awkward period between when it is assigned and before it is painted on the DOM.

---

<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:** [May 16, 2020, 3:58am UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/6 "2020-05-16T03:58:38Z")

</div>

There are a few ways to handle your requirement: connecting a value converter and a custom element instance.

In an Aurelia app, value converters are singleton, which means injecting them will give you the same instance that is used in binding expressions. So this gives us one way to do it: inject the value converter to the `App` instance, and let me app subscribe to the value converter and get notified whenever it is busying computing. Let’s call this point to point subscription (made up). How to make the value converter subscribe-able: via either making the value converter extend the `EventAggregator` class, or use:

```auto
import { EventAggregator, includeEventsIn } from 'aurelia-event-aggregator';

export interface MyValueConverter extends EventAggregator {}
export class MyValueConverter {
  constructor() {
    this.ea = includeEventsIn(this);
    // this.ea.publish
    // will be the same with this.publish now
  }
}

```

and in app:

```auto
@inject(MyValueConverter)
export class MyApp {
  constructor(myValueConverter) {
    myValueConverter.subscribe('busy', () => {
      this.loading = true;
    });
  }
}

```

With the above approach, you need to be careful, as you may accidentally introduce some circular dependency issues during large refactoring. It may catch you off guard and waste a good day. Example would be `App` requires value converter, value converter requires another services, and that services accidentally requires some semi private export from some other module that also requires this value converter (hypothetical scenario).

Another way to do it is to use a simple counter as change notifier within your app. A simple class looks like this:

```auto
// just a normal class, not custom element
export class BusyIndicator {
  busy = 0;

  on() {
    this.busy++;
  }

  off() {
    this.busy--;
  }
}

```

And then you would inject this class into any value converter, or binding behavior like this:

```auto
@inject(Busy)
export class AsyncBindingBehavior {
    constructor(busy) {
      this.busy = busy;
    }
}

```

Then whatever the complex things you do, you can simply solve it by ensuring every `this.busy.on()` is paired with a `this.busy.off()` call. That should give you good sleep. As loading indicator will be simply like this:

```auto
@inject(BusyIndicator)
export class App {
  constructor(busy) {
    this.busy = busy;
  }
}

```

```auto
<loading-indicator loading.bind="busy.busy > 0">

```

---

<div class="post-metadata">

**Author:** ![m0ngr31](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/m0ngr31/32/1535_2.png) [@m0ngr31](https://discourse.aurelia.io/u/m0ngr31)\
**Post date:** [May 18, 2020, 3:35pm UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/7 "2020-05-18T15:35:02Z")

</div>

Thanks for the response!

I think the problem would be that there could be up to 7 of the value converters running at once, so I’m not sure it’d work that way. And it’s not so much the calculating that’s having issues, it’s when it finishes rendering in the DOM.

---

<div class="post-metadata">

**Author:** ![zewa666](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/zewa666/32/19_2.png) [@zewa666](https://discourse.aurelia.io/u/zewa666)\
**Post date:** [May 18, 2020, 3:42pm UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/8 "2020-05-18T15:42:30Z")

</div>

But wouldn’t queuing a macrotask make sure you’re always after rendering is done? I see you’re using a micro task right now perhaps that’s the issue

---

<div class="post-metadata">

**Author:** ![m0ngr31](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/m0ngr31/32/1535_2.png) [@m0ngr31](https://discourse.aurelia.io/u/m0ngr31)\
**Post date:** [May 18, 2020, 3:47pm UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/9 "2020-05-18T15:47:20Z")

</div>

I’ve tried micro and macro and they both did the same thing

---

<div class="post-metadata">

**Author:** ![zewa666](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/zewa666/32/19_2.png) [@zewa666](https://discourse.aurelia.io/u/zewa666)\
**Post date:** [May 18, 2020, 4:18pm UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/10 "2020-05-18T16:18:38Z")

</div>

So it seems something else in there is delaying the rendering. Perhaps some of your codeparts make use of settimeout? On the other hand again that’s weird since you mentioned it used to work before …

---

<div class="post-metadata">

**Author:** ![m0ngr31](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/m0ngr31/32/1535_2.png) [@m0ngr31](https://discourse.aurelia.io/u/m0ngr31)\
**Post date:** [May 18, 2020, 4:24pm UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/11 "2020-05-18T16:24:12Z")

</div>

The only difference is I’m using the value converter now

---

<div class="post-metadata">

**Author:** ![m0ngr31](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/m0ngr31/32/1535_2.png) [@m0ngr31](https://discourse.aurelia.io/u/m0ngr31)\
**Post date:** [May 18, 2020, 4:25pm UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/12 "2020-05-18T16:25:08Z")

</div>

I’m wondering if it’s possible it could be something I changed with the rendering stuff that could make it not work? Something with my `show.bind`s

---

<div class="post-metadata">

**Author:** ![m0ngr31](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/m0ngr31/32/1535_2.png) [@m0ngr31](https://discourse.aurelia.io/u/m0ngr31)\
**Post date:** [May 18, 2020, 8:06pm UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/13 "2020-05-18T20:06:48Z")

</div>

Changed my `show.bind`s around and nothing changes.

Doing the processing before assigning the array works fine. So I need to figure out some other way to doing it if I want to keep the value converter as an option.

---

<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:** [May 18, 2020, 11:46pm UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/14 "2020-05-18T23:46:47Z")

</div>

@m0ngr31 you can easily do a debounce on the loading indicator binding in combination with the counter and it should work fine for you, maybe tried that? 😃

@huochunpeng had a small guide here [Tip: show spinner only when something is slow](https://discourse.aurelia.io/t/tip-show-spinner-only-when-something-is-slow/967)

---

<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:** [May 19, 2020, 12:08am UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/15 "2020-05-19T00:08:54Z")

</div>

Why not get rid of dayLoading callback, replace it with following?

```auto
export class TransformEntriesValueConverter {
    async toView(entries, day) {
       day.isRendering = true;
       let mappedEntries = [];
       try {
         mappedEntries = entries ? await mapEntries(entries, day) : [];
         day.isRendering = false;
       } catch(e) {
         console.error(e);
         day.isRendering = false;
       }
       return mappedEntries;
    }
}

```

Sure this introduces ugly side effect, but reduces the complexity of your implementation.

Working demo: [https://gist.dumber.app/?gist=9f334967c012f8b303f8cfa549eeb6dc&open=src%2Fapp.js&open=src%2Fapp.html](https://gist.dumber.app/?gist=9f334967c012f8b303f8cfa549eeb6dc&open=src%2Fapp.js&open=src%2Fapp.html)

---

<div class="post-metadata">

**Author:** ![m0ngr31](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/m0ngr31/32/1535_2.png) [@m0ngr31](https://discourse.aurelia.io/u/m0ngr31)\
**Post date:** [May 19, 2020, 3:51pm UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/16 "2020-05-19T15:51:06Z")

</div>

I tried reproducing your gist, and it wasn’t consistent enough with the debounce to be reliable.

---

<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:** [May 19, 2020, 10:31pm UTC](https://discourse.aurelia.io/t/loading-indicator-while-value-converter-computes/3493/17 "2020-05-19T22:31:02Z")

</div>

The debounce is decoupled from the value converter. What went wrong?

If you were talking about spinner not showing up every time, that’s debounce ignoring fast change. You can manually adjust the delay `debounce:500` to fine tune the timing.
