When is `this.args` not defined in `@action` method?

I was mocking up a component that has hooks into the didRender and willDestroy lifecycle but this.args does not seem to be defined. My understanding is that @action is what is required to bind the component context but it doesn’t seem to be working in this case. Any insight?

The component is intended to be used like:

<Block::ResizeAware @onResize={{ this.doSomeCalculations }} >
. . .
</Block::ResizeAware>

And the definition is something like:

import Component from '@ember/component';
import { action } from `@ember/object';

export default class BlockResizeAwareComponent extends Component {
  @action handleResize() {
    console.log("about to call passed in function...");
    this.args.onResize();
  }

  didRender() {
    super.didRender(...arguments);
    this.handleResize();
  }
}

This is currently resulting in a console error of:

Uncaught (in promise) TypeError: this.args is undefined
  handleResize resize-aware.js:35

@ember/component doesn’t have this.args, only @glimmer/component does. Also note that, @glimmer/component doesn’t have didRender.

1 Like

Thank you. I’ve been building an ember app for a few weeks now and that never clicked until now. To summarize:

If import Component from '@glimmer/component' use this.args but if import Component from '@ember/component' use @tracked value = something?

Anyway, to close the loop, refactoring to something like this worked fine:

import Component from '@ember/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';

export default class BlockRenderAwareComponent extends Component {
  @tracked onRender = null;

  @action handleRender() {
    console.log("about to call passed in function...");
    this.onRender();
  }

  didRender() {
    super.didRender(...arguments);
    this.handleRender();
  }
}

So @tracked is just stating that a value will participate in the autotracking system, and this can happen with classic or glimmer components (or any other arbitrary class as it turns out). The difference in args is that with classic components the args were “mixed in” to the backing class properties which was a source of confusion. For glimmer components they’re specifically captured in this.args.

I would strongly suggest not using classic components and instead use glimmer components going forward. Obviously that leaves the problem of the didRender hook. To handle that you could use ember-render-helpers or ember-render-modifiers, however that pattern is mostly discouraged. You could also write your own modifier and attach it to the tag or whatever.

2 Likes