DEV Community

Rabbi hasan
Rabbi hasan

Posted on

πŸš€ Rendering Dynamic Components in Ember.js with Embroider

Hey folks! πŸ‘‹

Today, I want to share a powerful technique for rendering dynamic components in Ember.js, especially when using Embroider, Ember's next-generation build system. This approach is particularly useful when the component names are retrieved from an API, and you need to render these components dynamically.

Why Dynamic Components?

Dynamic components allow you to build flexible and reusable applications. They enable you to determine which component to render at runtime, based on data or other conditions. This is particularly useful in scenarios like content management systems or dashboards, where the UI components can change based on user input or configuration.

Using Embroider for Dynamic Components

Embroider provides tools like importSync and ensureSafeComponent to help with dynamic component rendering. Here's how you can leverage these tools to render components dynamically in Ember.js.

Step-by-Step Implementation

1. Update ember-cli-build.js to Allow Unsafe Dynamic Components

First, ensure that your ember-cli-build.js file is configured correctly to allow unsafe dynamic components.

ember-cli-build.js

'use strict';
  const { Webpack } = require('@embroider/webpack');
  const EmberApp = require('ember-cli/lib/broccoli/ember-app');

  module.exports = function (defaults) {
    const app = new EmberApp(defaults, {
      ....
    });

    return require('@embroider/compat').compatBuild(app, Webpack, {
      .....
      allowUnsafeDynamicComponents: true,
    });
  };
Enter fullscreen mode Exit fullscreen mode

Explanation

  • allowUnsafeDynamicComponents: This option enables the use of dynamic components in your application, which is crucial for rendering components based on runtime data.

2. Create a Dynamic Component

First, create a dynamic component that will handle the rendering of other components based on the name provided.

app/components/dynamic-component.js

import Component from "@glimmer/component";
import { ensureSafeComponent } from "@embroider/util";
import { importSync } from "@embroider/macros";
import { tracked } from "@glimmer/tracking";

export default class DynamicComponent extends Component {
  get componentName() {
    return this.args.componentName || null;
  }

  get argsData() {
    return this.args.argsData || null;
  }

  get componentLabel() {
    if (this.componentName) {
      let module = importSync(`/components/${this.componentName}`);
      return ensureSafeComponent(module.default, this);
    }
    return null;
  }
}
Enter fullscreen mode Exit fullscreen mode

Explanation

  • importSync: This function allows synchronous dynamic imports. It ensures the component module is available at runtime.

  • ensureSafeComponent: This utility ensures that the component is safe to render, which is particularly important when dealing with dynamic components.

  • get componentName: This property holds the name of the component to be rendered which you passed as args. You can update this property based on the data received from an API.

3. Dynamic Component Template

Create the template for the dynamic component to render the desired component dynamically.

app/templates/components/dynamic-component.hbs

{{#if this.componentLabel}}
    <this.componentLabel @argsData={{this.argsData}} />
{{/if}}
Enter fullscreen mode Exit fullscreen mode

Explanation

  • this.componentLabel: This invokes the dynamically imported component.
  • @argsData: This passes any necessary data to the dynamically rendered component.

Example Usage

  • Here’s an example of how you might use this DynamicComponent in your application.

app/controllers/application.js

import Controller from "@ember/controller";
import { action } from "@ember/object";
import { tracked } from "@glimmer/tracking";

export default class ApplicationController extends Controller {
  @tracked dynamicComponentName = "component_one/nested_component";
  @tracked argsData = { key: "value" };

  @action
  updateComponentName(newComponentName) {
    this.dynamicComponentName = newComponentName;
  }
}
Enter fullscreen mode Exit fullscreen mode

app/templates/application.hbs

<DynamicComponent
  @componentName={{this.dynamicComponentName}}
  @argsData={{this.argsData}}
/>

<button
  {{on "click" (fn this.updateComponentName "component_two/another_component")}}
>Switch Component</button>

Enter fullscreen mode Exit fullscreen mode

Explanation

  • DynamicComponent: This component renders the dynamic component based on the componentName and argsData passed to it.
  • updateComponentName: This action updates the component name, demonstrating how you can switch components dynamically.

Conclusion

Rendering dynamic components in Ember.js using Embroider's utilities like importSync and ensureSafeComponent provides a flexible and powerful way to build dynamic and interactive applications. This approach is particularly beneficial in scenarios where component names are retrieved from an API or other dynamic sources.

Feel free to reach out if you have any questions or need further assistance with Ember.js and Embroider! 😊

Here's the complete code: Repo

Give a star to the repository if you find it helpful. Your support is greatly appreciated! 😊

Top comments (0)