Overriding specific component args in glimmer

What’s the recommended way to override a component’s args in a sub-class? Normally composition is preferred by convention in glimmer/ember, but here’s a case where it gets a bit crazy:

Here I have a complex BaseComponent, and the desire is to specialize only one argument ("@arg12") but to do so, I need to pass through all 46 (potentially missing new additions to the underlying component) just to override the one argument.

Ideally there would be a “splarguments” (like “splattributes”) where I could do so with …@args or something, but I don’t see how to get around this, except potentially to import @glimmer/runtime and use curry explicitly to manufacture a CurriedValue, but that seems like a very technical lift.

  {{!-- MySubClassComponent/template.hbs --}}
  <BaseComponent
    @arg1={{@arg1}}
    ...
    @arg12={{this.someSpecialOverrideTrackedProp}}
   ...
    @arg46={{@arg46}}
  />

Here is the component.js where I’d like @arg12 to be provided as a dynamic input:

  // MySubClassComponent/component.js
  export default class MySubClassComponent extends BaseComponent {
    constructor(owner, args) {
      // What I would like to do here is provide an alternate dynamic argument
      super(owner, {...args, arg12: mySpecialOverride });
    }
  }

Haven’t tried this out, personally… but won’t something like this work?

This should pass all the args to the base class…

No, it won’t because then the “shape” of the args on the base is not the same as the subclassed component. In your example, we have:

class BaseComponent extends Component<{
  subClassArgs: {
    baseClassArg1: whatever;
  };
}>

and

class MySubClassComponent extends Component<{
  baseClassArg1: whatever;
}>

…i.e. you are forcing the args to be a wrapped structure in the base component. This would work technically, but that embeds all args to the base class, so on its own it would always have to be invoked by wrapping all of its args into the single @subClassArgs parameter.

Yes… unfortunately, I can’t think of any other way to pass the args to the base class without changing the code everytime the BaseClass adds another argument.

Splarguments have been a frequent request from what I understand. This response from @chriskrycho in another thread about it is probably still the best summary of the status (there hasn’t been much movement on the RFC). I’d love to see something like this land personally.

(also if you do any exploring of manual curry please share!)

@dknutsen - we did make a try at CurriedValue… got something working but it was a yard sale at best and a poor use of duct tape at worst - mostly just in getting CurriedValue injected and “fooling Glimmer/Ember” into believing it was self generated. Learned a lot… mostly about the glimmer VM and what not to do with duct tape…

The RFC is exactly what we need - not sure how I missed it so thanks for referencing it here - I should have googled splarguments - that’s not a word you hear every day. :beers:

1 Like

Yeah, unfortunately the pattern you showed of passing modified args to super doesn’t work. @args is very optimized and controlled by glimmer from the “outside” of the component, so you can’t easily manipulate it.

I agree this is a gap and we need a javascript API for currying arguments. And splarguments in templates too.

1 Like

First, it sounds like the Interface used by the base component is lacking. I think considering that you’ve recognized that the args in use are more dynamic then originally anticipated it might be best to change the base component’s interface to accept a POHO/Hash instead of a list of @args.

With that you now have far more flexibility to graft extensions to the original interface. You could even make the change incremental.

// Base component
get subArgs() {
  return { ...this.args, arg12: mySpecialOverride };
}

Have the template use this.subArgs instead of @….