Demystifying ember-render-modifiers
Tags: javascript, ember, webdev
Published: 2020-07-28 16:35:16

Ember modifier is one of the coolest features that I see in ember octane. Many ember addons are based on ember modifiers. [ember-render-modifier](https://github.com/emberjs/ember-render-modifiers) is one of those addons which provides element modifiers that can be used to **hook into specific portions of the rendering lifecycle.**

One key point that fascinates me about ember-render-modifiers is using this, we can access the basic lifecycle hooks of a component without creating a class for it. That is, we can access them in a template(.hbs) file.

While I stumbled upon this addon, I wanted to explore more. So, I did it and like to share my learnings with you all.

## How ember-render-modifier works behind the scene?

Behind the scenes, `ember-render-modifiers` is nothing but the `customModifierManager` API which was a low-level API designed especially for addon developers to create and manage custom modifiers.

To know more about **Custom Modifier Manager** and how they are used to manage ember modifiers, feel free to check out my previous blog.
{% link https://dev.to/_raja_sk_/how-do-ember-modifiers-get-to-be-managed-internally-1i40 %}

## How does a `customModifierManager` look like?

Each modifier manager has four life-cycle methods.
1. createModifier - creates an instance of the modifier.
2. installModifier - runs when a modifier is installed on a DOM element.
3. updateModifier - runs when the arguments passed to the modifier element changes.
4. destroyModifier - runs just before the element is to be destroyed.

The skeleton of a `customModifierManager` API looks like

```js
import { setModifierManager, capabilities } from '@ember/modifier';

export default setModifierManager(
  () => ({
    capabilities: capabilities('3.6'),

    createModifier(factory, args) {
      return factory.create(args.named);
    },

    installModifier(instance, element, args) {
      // installation logic...
    },

    updateModifier(instance,args) {
      //re-render logic
    }

    destroyModifier(instance, args) {
      // teardown logic...
    }
  }), class BaseClass {}
);
```

## What are the modifiers provided by `ember-render-modifiers`?

1. did-insert - runs when the element is inserted in the DOM.
2. did-update - runs when the element's arguments changes
3. will-destroy - runs when the element is destroyed.


Along with this, if we see the `customModifierManager` API's skeleton, we can able to understand how `ember-render-modifiers` are implemented.

Each modifier in this addon uses its respective lifecycle method of the `customModiferManager` API and runs the function passed to the modifier within that method itself.

* did-insert => installModifier
* did-update => updateModifier
* will-destroy => destroyModifier

Let's take the `did-insert` modifier.

```js
export default setModifierManager(
  () => ({
    capabilities: capabilities('3.13', { disableAutoTracking: true }),

    createModifier() {},

    installModifier(_state, element, args) {
      let [fn, ...positional] = args.positional;

      fn(element, positional, args.named);
    },

    updateModifier() {},
    destroyModifier() {},
  }),
  class DidInsertModifier {}
);
```
Here, the main logic lies inside the `installModifier` and the other two lifecycle methods are left empty.

Similarly, in the `did-update` modifier, the logic lies inside the `updateModifier` and the state maintenance is done by `installModifier`

```js
export default setModifierManager(
  () => ({
    capabilities: capabilities('3.13', { disableAutoTracking: true }),

    createModifier() {
      return { element: null };
    },
    installModifier(state, element) {
      // save element into state bucket
      state.element = element;
    },

    updateModifier({ element }, args) {
      let [fn, ...positional] = args.positional;

      fn(element, positional, args.named);
    },

    destroyModifier() {},
  }),
  class DidUpdateModifier {}
);
```

Also, in the `will-destroy` modifier, the logic lies inside the `destroyModifier` and `installModifier` is used to maintain state.

```js
export default setModifierManager(
  () => ({
    capabilities: capabilities('3.13', { disableAutoTracking: true }),

    createModifier() {
      return { element: null };
    },

    installModifier(state, element) {
      state.element = element;
    },

    updateModifier() {},

    destroyModifier({ element }, args) {
      let [fn, ...positional] = args.positional;

      fn(element, positional, args.named);
    },
  }),
  class WillDestroyModifier {}
);
```

Among several addons that are based on ember modifier, this `ember-render-modifier` is one of its kind and easy to understand the implementation.

There are so many ways to play with ember modifiers. This addon is a small drop that **ember modifiers** can do. You can also play with your thoughts on ember modifiers and create some custom modifiers.

<hr>

> Hope you find my learnings on `ember-render-modifiers` informative. See you all in my next blog! 👋