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:
export class TransformEntriesValueConverter {
async toView(entries, day) {
if (!entries) {
return [];
}
return await mapEntries(entries, day);
}
}
Binding behavior:
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:
<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:
export class MyClass {
...
public dayLoading(day) {
this.taskQueue.queueMicroTask(() => {
day.isRendering = false;
});
}
...
}