Strange behavior of t.bind in Aurelia 2

While migrating my apps to Aurelia 2, I noticed strange behavior with the binding for the translation attribute, t. Here is simplified example:

<div if.bind="obj">
    <span t.bind="obj.property"></span>
</div>

If the object (obj) disappears, i.e., if it is set to null, the binding (t.bind ) throws the error: “AUR0203: Trying to retrieve a property or build a scope from a null/undefined scope”. I thought that if.bind on the parent element would take care of that, meaning div would be removed from the DOM and binding would not happen if there is no obj, as was the case in Aurelia 1.

It works if I use the same expression in the getter in the view-model, and bind the t attribute to that getter. However, this approach is much less flexible. I don’t understand what’s going on or how to make it work as before. I would appreciate any help. Thanks!

[Edit] Another real world example. This code throws the AUR0203:

<span t.bind="invitation.relationTypeId | userType"></span>

And this works:

<span>${invitation.relationTypeId | userType | t}</span>
1 Like

This is likely because t binding (translation binding) doesnt stop after its owner (view created by if has been deactivated. Can you help with a gh issue and possibly a small repro (preferrably stackblitz) @graycrow ?

1 Like

As always, everything works when I created a minimal case at stackblitz, but not in my actual project, which has many nested components and asynchronous requests. I will try to isolate the issue and either fix my code or file a bug.

This is the stackblits exampe, just for reference, it works as intended.

1 Like

@graycrow if you are still seeing it can you grab the trace when it happens?

@bigopon sorry, it took me a while but I think I found a bug in aurelia/i18n. Long story short, the handleChange() method of the TranslationBinding class is missing the check for when it is unbound:

        if (!this.isBound) {
            return;
        }

Look at this sample code:

<span if.bind="obj.condition">
    <span t.bind="obj.value"></span>
</span>

If the value of obj.condition in this code becomes falsy, the SubscriberRecord instance from the aurelia/runtime notifies all subscribers. In my case, there are two subscribers: an instance of PropertyBinding for if.bind and an instance of TranslationBinding for t.bind. During the PropertyBinding.handleChange() run, the TranslationBinding instance becomes unbound, and its _scope becomes undefined, but then its handleChange() function still tries to handle that change via a few astEvaluate() calls finally leading to the “AUR0203” error because of missing scope.

A comment in the SubscriberRecord class states that isBound should probably be checked. However, this is missing from the TranslationBinding.handleChange() method, but it exists, for example, in the similar PropertyBinding.handleChange():

            /**
             * Note: change handlers may have the side-effect of adding/removing subscribers to this collection during this
             * callSubscribers invocation, so we're caching them all before invoking any.
             * Subscribers added during this invocation are not invoked (and they shouldn't be).
             * Subscribers removed during this invocation will still be invoked (and they also shouldn't be,
             * however this is accounted for via $isBound and similar flags on the subscriber objects)
             */

In my case, modifying the “aurelia/i18n” im my project’s node_modules by inserting this condition

        if (!this.isBound) {
            return;
        }

in the top of TranslationBinding.handleChange()method in /node_modules/@aurelia/i18n/dist/esm/index.mjs fixes all translation binding issues for me. However, no matter what I do, I can’t reproduce this bug in the simplest stackblits project, so I’m resisting submitting a proper bug report to GitHub.

Hi @graycrow, I think this bug is fixed already and should be out with the beta.24 release. If you are still facing the issue with the beta.24 version, let us know. In that case, you may also open a new issue and/or submit a PR.

@Sayan751 Unfortunately it’s happening in beta-24, I would create a new issue.

1 Like

I created a simple example. Previously, I used the Vite example, but my project uses Webpack. Surprisingly, it functions properly in Vite, but it throws an exception only when it is bundled by Webpack.
Here is example to reproduce the bug: stackblitz (Webpack). The same code in Vite works: stackblitz (Vite)