[Aurelia 2] Use value converter inside custom element

I am witnessing a strange behavior of value converters when used from a custom element.

This is a simple app:

<import from="./test-element"></import>
<import from="./test-converter"></import>
<div class="message">${message}</div>
<test-element></test-element>
<div textcontent.bind="'hello from my-app' | testConverter"></div>

TestElement:

import { customElement, ICustomElementViewModel } from '@aurelia/runtime-html';
import template from './test-element.html';

@customElement({
  name: 'test-element',
  template: template,
})
export class TestElement implements ICustomElementViewModel {
  constructor() {}
}
<import from="./test-converter"></import>
<p>test element</p>
<!-- <div textcontent.bind="'hello from test-element' | testConverter"></div> -->

And TestConverter:

import { valueConverter } from '@aurelia/runtime-html';

@valueConverter('testConverter')
export class TestConverter {
  toView(value: string) {
    return value.toUpperCase();
  }
}

This code creates the following output:

Hello World!

test element
HELLO FROM MY-APP

But when I uncomment value converter usage in TestElement, the page stops rendering the TestElement at all!

Hello World!
HELLO FROM MY-APP

Am I missing something? I started to investigate this issue because in my code I have a similar issue, when value converter works from some page when imported locally via <import from> tag, but cannot be found from the custom element inside that page with error message “[DEV:aurelia] Cannot retrieve value converter with name testConverter” but works ok when registered globally in main.ts.

Here is a stackblitz example

Hi @graycrow! Here is a working example: discourse VC issue - StackBlitz.

1 Like

Thank you very much! I see that your code does not use decorators. Is it now considered bad practice to use decorators, or were they used incorrectly?

Nope. Using decorator is the vanilla way; that is, when you don’t want to use the convention. However, when using convention, it might make more sense to stick to the convention. As in your SB-example, you did it like this:

import { customElement, ICustomElementViewModel } from '@aurelia/runtime-html';
import template from './test-element.html';

@customElement({
  name: 'test-element',
  template: template,
})
export class TestElement implements ICustomElementViewModel {
  constructor() {}
}

only the template string got imported, ignoring the imported dependencies in your HTML. If you want to specify a name for your custom element that is different from the conventional name, you can use something like below.

import { customElement, ICustomElementViewModel } from '@aurelia/runtime-html';

@customElement('foo-bar')
export class TestElement implements ICustomElementViewModel {
  constructor() {}
}

That way, the convention kicks-in and registers the imported dependencies correctly.

1 Like

This is very valuable info, it may explain many of the weird issues I’m experiencing during the migration process, thanks again.

1 Like