AU1 to AU2 differences with gloabl registration?

I’m working on converting a part of my application that allows 3rd party developers to create their own form. I was moving right along when I hit a roadblock that doesn’t make sense to me.

The concept itself isn’t groundbreaking in anyway . I unfortunately can’t share the code but I’m going to do my best to explain and show what I can. Where I’m stuck is with a nested generation.

 controls: [
                    {
                        type: 'label',
                        label: 'Test Label',
                        id: 'label1',
                        value: '<span style="color:blue">Hello World!</span>'
                    },
                    {
                        type: 'string',
                        label: 'Test String Control',
                        id: 'string1',
                        value: 'Initial Value',
                        description: "test",
                        validation: {
                            required: true,
                            minLength: 2,
                            maxLength: 10
                        }
                    },
                    {
                        type: 'numeric',
                        label: 'Test Numeric Control',
                        id: 'numeric1',
                        defaultValue: 5,
                        description: "A numeric control",
                        validation: {
                            min: 5,
                            max: 20
                        }
                    },
                    {
                        type: 'string',
                        label: 'Test String Control 2',
                        id: 'string2',
                        value: 'Good one',
                        description: "test",
                        helpText: "This is some help text for the control.",
                        validation: {
                            required: true,
                            minLength: 2,
                            maxLength: 10
                        }
                    }]

This JSON will render this and all is well, everything works as intended.


Now if someone were to nest my groupCheckbox. The JSON now looks like this.

[
            {
                type: "groupCheckbox",
                label: "Test Group Checkbox Control",
                id: "groupcheckbox1",
                controls: [
                    {
                        type: 'label',
                        label: 'Test Label',
                        id: 'label1',
                        value: '<span style="color:blue">Hello World!</span>'
                    },
                    {
                        type: 'string',
                        label: 'Test String Control',
                        id: 'string1',
                        value: 'Initial Value',
                        description: "test",
                        validation: {
                            required: true,
                            minLength: 2,
                            maxLength: 10
                        }
                    },
                    {
                        type: 'numeric',
                        label: 'Test Numeric Control',
                        id: 'numeric1',
                        defaultValue: 5,
                        description: "A numeric control",
                        validation: {
                            min: 5,
                            max: 20
                        }
                    },
                    {
                        type: 'string',
                        label: 'Test String Control 2',
                        id: 'string2',
                        value: 'Good one',
                        description: "test",
                        helpText: "This is some help text for the control.",
                        validation: {
                            required: true,
                            minLength: 2,
                            maxLength: 10
                        }
                    },
                    {
                        type: "groupCheckbox",
                        label: "Nested Group Checkbox Control",
                        id: "nestedgroupcheckbox1",
                        controls: [{
                            type: 'string',
                            label: 'Test String Control 2',
                            id: 'string3',
                            value: 'Good one',
                            description: "test",
                            helpText: "This is some help text for the control.",
                            validation: {
                                required: true,
                                minLength: 2,
                                maxLength: 10
                            }
                        }]
                    }
                ]
            }
        ]

At runtime I am getting the ‘ couldn’t find a custom element with name “groupCheckbox-control”, did you forget to register it locally or globally?’ error when the first groupCheckbox tries to render itself. The control is registered globally otherwise the first level groupcheckbox wouldn’t render.

The primary rendering is done in a view that looks like this. The screencap above the migrated code working, it only fails in the nested case for some reason. Groupcheckbox is registered the same as the string and numeric with the difference being that group checkbox can render children.

<template repeat.for="control of controlSet.controls">
    <au-compose component="${control.type}-control" model.bind="control"></au-compose>
</template>

And when the groupCheckbox is being rendered, it looks very similar

 <template repeat.for="control of config.controls">
            <div>
                <au-compose if.bind="!control.hidden && control.isVisible" model.bind="control"
                    component="${control.type}-control"></au-compose>
            </div>
  </template>

1 Like

Thanks for reporting it @elitemike , it looks like it should just work. Though is groupCheckbox what you have in your app? normally custom element name shouldn’t have uppercase letters in them so I’m not sure how to understand it.

I prepared a basic stackblitz here Aurelia app - conventions - Vite (duplicated) - StackBlitz

Can you help use it to create a repro?

Thanks for responding. Good catch on the naming. That is actually a recent change to support my new folder structure. In my AU1 one project I have my separate views/elements in a subfolder that is /views/string/control/control.html or /view/groupCheckbox/control/control.html ect. I changed it up because I was tired of seeing control.html files open and getting confused which one I have open at quick glance. For AU1 compose I relied on a getter. the actual element name is group-checkbox

public get viewModel(): string {

    return \`@control-set/ui/views/${this.type}/control/control\`;

}

I guess it works in AU2 since I’m explicitly naming it and not doing it by convention? @customElement({ name: 'groupCheckbox-control', template }) I updated it in my project and I’m still running into the nested issue though. I’ll have to come up with a way to have an extra name mapping as I have to accept the word groupCheckbox in the JSON to support what has been used for years now. I just need to come up with a clean way to have the dynamic component string created with the mapping. Does AU2 have a helper function to take a camelcase into hyphenated?

I’ll work on a minimal repo soon, I’m starting vacation/holiday soon so it may take me some time. To do this right I need to recreate my pnpm workspace which has the “views” in one package and the all the builder logic in another while also having a common package. I don’t think the workspace is the issue, I’d expect it to fail at first level as well.

you can also just call toLowerCase() in your template. It should allow you to register component with name groupcheckbox-control for example, even though the json returns is groupCheckbox-control

1 Like

I ended up creating a property called safeType that just does a regex. this.type.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(); I figure I might have some use for this later anyways