Best way to get attrs only

Hi! I’m working on my first Ember addon and I needed a way to separate the attrs from the rest of the component object. I came across warnings against using this.attrs directly. What I came up with is:

const getComponentAttrs = that => Object.keys(that.attrs)
    .reduce((attrs, attrName) => {
        attrs[attrName] = that[attrName];

        return attrs;
    }, {});

invoked like so:

didUpdateAttrs() {
    this._super(...arguments);

    const attrs = getComponentAttrs(this);

    // and so on...
},

Any thoughts on this approach? Is there a better or common method?

Hey @xiwcx! So, the attrs object in classic components is something that we generally don’t recommend using, in part because it is confusing and not well defined or documented, and technically has never been public API. I believe it is considered “intimate” API though, which means that we will not be making breaking changes. If you need to write a component today, in an existing app, that gets all of the component’s arguments dynamically, I do think this is one of the only ways to accomplish that (outside of writing a custom component manager).

In the near future, we’re going to be putting the finishing touches on Ember Octane, and shipping Glimmer Components. When that happens, the recommended way for getting all of the arguments will be to use a Glimmer Component:

import Component from '@glimmer/component';

export default class MyComponent extends Component {
  get argNames() {
    return Object.keys(this.args);
  }
}

In Glimmer Components, all arguments to the component are assigned to the args property of the component automatically, instead of directly to the component. This makes it much easier to get all of the argument values :smile:

Glimmer Components are available today, in a prerelease package (I believe the current version is 0.14.0-alpha.13), so you could adopt the functionality a little early. We’re working on getting the final v1.0.0 release out presently, so definitely stay tuned!

Note: The Ember community took some time to figure out what we wanted to call values that are passed into a component. They were initially called attrs or props sometimes, but after some debate we landed on arguments for JS values that are passed into a component (the same thing that attrs on Classic Components represent). The reasoning is that components are similar to functions, they receive JS values, and they output DOM.

This also allows us to refer to plain HTML attributes separately. Arguments are JS values passed to a component, attributes are HTML attributes like class, role, etc. In modern Ember, we have a new way of writing components with Angle Bracket syntax that allows us to distinguish these visually as well:

<MyComponent @arg={{this.someValue}} data-attr="some-value" />

In this example, the @arg argument will be available in the component class at this.args.arg (or in it’s template directly via {{@arg}}), while the data-attr value will instead be applied directly to the HTML of the component. To learn more about this, checkout the Arguments and Attributes section of the new Octane guides.

4 Likes

thanks for your thorough reply!

1 Like