Is there a way to dynamically call an Ember component using a variable?

Imagine having an array of widget objects stored in your controller, with each widget object containing a member variable assigned the name of a component class. How can you make your template call upon that specific component?

//widgets[0].widget.componentClass="blog-post"

{{#each widget in widgets}}
    {{widget.componentClass}}
{{/each}}

The example above simply displays strings representing the widget component classes. To actually invoke the components, you can utilize the following approach:

//widgets[0].widgets.viewClass="blogPost"

{{#each widget in widgets}}
    {{view widget.viewClass}}
{{/each}

In our previous setup, we used a custom {{renderWidget ...}} tag along with a Handlebars helper, which can be found detailed here. The default render helper encountered issues when trying to render based on a variable name. I am contemplating creating a custom component handlebars helper but unsure where to begin. Any guidance would be appreciated. Thank you.

Answer №1

After experimenting with this method, I discovered that it does indeed work. However, the process involved a fair amount of trial and error on my part:

Ember.Handlebars.registerHelper('renderComponent', function(componentPath, options) {
  var component = Ember.Handlebars.get(this, componentPath, options),
      helper = Ember.Handlebars.resolveHelper(options.data.view.container, component);

  helper.call(this, options);

});

To implement it, you can simply follow the same pattern:

{{#each item in items}}
  {{renderComponent item.componentType item=item}}
{{/each}}

Answer №2

With Ember 1.11, a revolutionary new component helper has been introduced, allowing for the following syntax:

{{#each widget in widgets}}
  {{component widget.componentClass}}
{{/each}}

Although Ember 1.11 is not yet officially stable as of Jan 19th, 2015, this functionality is available in the canary build.

Answer №3

It seems like we've encountered many of the same issues. All the components are registered as top-level helpers, so you can use a similar approach to the one you mentioned by creating a handlebars helper for performing the lookup. Here's an example code snippet:

Ember.Handlebars.registerHelper('lookup', function(component, options) {
  component = Ember.Handlebars.get(this, component, options);
  Ember.Handlebars.helpers[component].call(this, options);
});

Then in your template, you can use it like this:

{{#each widget in widgets}}
  {{lookup widget.componentClass}}
{{/each}}

Check out this jsbin with a demonstration: http://jsbin.com/ucanam/2482/edit

I hope this solution works for you!

-- updated --

Due to changes in handlebars, calling helpers from other helpers is no longer possible. Instead, you can access the template using the Ember.TEMPLATES global variable. I have revised the JSBin to reflect this method.

You can also retrieve the template using

options.data.view.templateForName(component)
, but it may be less reliable than using Ember.TEMPLATES.

-- latest update --

The method has been updated once again. Now, using Ember.Handlebars.resolveHelper is the recommended approach. Check out @StrangeLooper's answer for more details.

Answer №4

If you find yourself working with Ember CLI and Coffeescript, here's a customized solution for that scenario. Simply create a new file named

app/helpers/render-component.coffee
:

renderComponent = (componentPath, options)->
  helper = Ember.Handlebars.resolveHelper(options.data.view.container, componentPath)
  helper.call this, options

`export { renderComponent }`
`export default Ember.Handlebars.makeBoundHelper(renderComponent)`

After setting up the file, you can use {{render-component "foo-bar"}} in your template.

Keep in mind that the Ember framework is constantly evolving, and I have successfully tested this version with the following setup:

  • Ember-CLI v2.13.0
  • Ember v3.7.2
  • Handlebars 4.5.1

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing the require pattern to integrate JavaScript functionality into HTML

Have: project |- consume_script.js |- index.html Need index.html to be like: <html> <head> </head> <body> <script src="consume_script.js"></script> </body> </html> Issue: consume_script ...

What is the proper usage of a jwt token?

I'm completely new to this and I've dedicated all my time to figuring out how to create a mechanism for generating JWT tokens. These tokens are necessary for identifying the 'signed in' status of users. I opted for FastAPI, and after s ...

The canvas game's animation can only be activated one time

I am currently working on designing a straightforward canvas game: Here is the code snippet located on CodePen var canvas; var ctx; var x = 300; var y = 400; var r = 0; var mx = 0; var my = 0; var WIDTH = 600; var HEIGHT = 400; function circle(x,y,r) ...

Utilize dynamically generated form fields to upload multiple files at once

Currently, as I delve into learning the MEAN stack, I am encountering difficulties with file uploads. Specifically, within a company form: this.companyForm = this.fb.group({ trucks: this.fb.array([]), ... }); The 'trucks' field i ...

Warning: Unhandled Promise Rejection - Alert: Unhandled Promise Rejection Detected - Attention: Deprecation Notice

Encountering the following error message: (node:18420) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'name' of undefined at C:\Users\ohrid\Desktop\backend2\routes\categories.js:27:24 at Layer.han ...

Prevent infinite scrolling with JavaScript AJAX when the response is empty

I am currently implementing the infinite scroll functionality on my website. Whenever the page reaches the bottom, an ajax call is triggered to fetch a new set of data. However, I'm unsure how to handle stopping the ajax call if there is no more data ...

Is it possible to link to a .json file stored on my server and then create a template for it?

I have set up a Webserver on kasserver.com, and I have a PHP script that retrieves data from an API every 15 minutes and saves it on my Webserver. Now, I am looking to create a template for the saved JSON data, but I am having trouble accessing it locally. ...

Selecting Objects with a Mouse in Three.js

Thanks to the wonderful support from the stackoverflow community, I was able to successfully implement a basic object picking example. You can view the functional code here. However, it's important to note that this example specifically works when t ...

center the view on the specified element

Utilizing ReactJs, I am developing a horizontal timeline that showcases dates. For instance, there is a list of 100 elements, each containing a date and text content. The dates are displayed horizontally using flex-direction="row" and overflowX ...

Guide on How to Show Only the Initial Word of an H2 Header Using JavaScript or CSS

Is there a way to display only the first word from an h2 heading? For instance: In the website's source code, it would appear like this <h2> Stackoverflow is an Ideal Place</h2> But on the live website, it should be displayed like this ...

What is the best way to set an array as the value for an HTML form input?

I am attempting to set the value of an array to an input element in HTML. When I run the following code in my browser console, it works: let between0400am0800am = [1669352400000, 1669438800000]; document.getElementById("time400am800amEveryDay"). ...

If a user enters an incorrect path, the goal is to automatically redirect them to the homepage while displaying the correct URL in AngularJS

When the URL is manually edited, the webpage displays the same content with a different URL structure. For instance, http://www.example.com/# and http://www.example.com/#/abc both show identical content. I would like to implement a redirect for any edite ...

Find the total of values in an array that may be null or undefined

In this scenario, I have an array that looks like this: myData = [[2, null, null, 12, 2], [0, 0, 10, 1, null], undefined]; The goal is to calculate the sum of each sub-array, resulting in an array like this: result = [16, 11, 0]. The ...

Updating React markers dynamically on Google Maps issue

I'm currently developing a transportation app with React and the @react-google-maps/api library. The app includes a map component that displays the real-time location of delivery workers using custom icons. However, I've encountered an issue wher ...

Display HTML tags on an HTML page using TypeScript

In my angular application, I encountered an issue where I needed to call one component inside another component. Initially, I was able to achieve this by simply using the second component's selector in the HTML of the first component: html: <div&g ...

Unable to modify text or utilize any of the buttons within CKEDITOR

My goal is to have a div that, when clicked, will trigger the opening of CKEDITOR. The contents of the div should then be loaded into the editor. When I click outside of the editor, I want the contents of the editor to be displayed back in the div. Below ...

Navigating to the parent Vue component in a Vue3 project with Composition API structure in WebStorm

After transitioning to Vue3 and embracing the Composition API style, I find myself missing a small convenience that I had when developing in the previous Options API pattern. In WebStorm/IntelliJ IDE, I used to be able to command-click (Mac) on the "export ...

extract the field name from the json object

I need to send coordinates to the Google Maps API, but I'm struggling to remove the field name from my JSON object before sending the parameters. Object {TempPoints: "{lat: 51.478,lng: -3.192},{lat: 51.478,lng: -3.192…{lat: 51.47840998047034,lng: - ...

Enhancing the efficiency of a Puppeteer web scraping operation

app.get("/home", async (req, res) => { try { const browser = await puppeteer.launch(); const page = await browser.newPage(); const pageNumber = req.query.page || 1; await page.goto(`https://gogoanimehd.io/?page=${pageNumber ...

Interacting with objects in a loaded OBJ model using ThreeJS

I have an obj model representing a map with tree objects. After successfully loading the model, I am trying to access one specific tree object named Tree1. How can I achieve this? Currently, my code looks like this: loader.load( 'map.obj', fun ...