How can I invoke an ember component dynamically via a variable?

Asked
Active3 hr before
Viewed126 times

7 Answers

component
90%

Thanks for contributing an answer to Stack Overflow!,Lets say I have an array of widget objects on my controller and each widget object has member variable that is assigned the name of a component class. How can I get my template to invoke that component?,In Ember 1.11, the new component helper allows you to do this:, Stack Overflow Public questions & answers

I tried this and it seems to work, but its just a lot of guesswork 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);

});

and you use it the same way:

{
   {
      #each widget in widgets
   }
} {
   {
      renderComponent widget.componentClass widget = widget
   }
} {
   {
      /each}}
load more v
88%

Lets say I have an array of widget objects on my controller and each widget object has member variable that is assigned the name of a component class. How can I get my template to invoke that component?,In fact, this is not Ember idiomatic. From what I know, and what I have learnt from Tom Dale himself, here are some remarks about that code:,Obviously the above example just spits out a series of string versions of the widget component classes. This however does work (as long as you got everything set up right):,Finally, Ember's controllers are not aimed to contain behavior as they rather are value-added wrappers, holding mainly computed properties. If you nevertheless want to factorize primitives, maybe the model can be a good place, or a third party context, but certainly not the Controller.

Lets say I have an array of widget objects on my controller and each widget object has member variable that is assigned the name of a component class. How can I get my template to invoke that component?

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

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

Obviously the above example just spits out a series of string versions of the widget component classes. This however does work (as long as you got everything set up right):

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

{
   {
      #each widget in widgets
   }
} {
   {
      view widget.viewClass
   }
} {
   {
      /each}
load more v
72%

This looks like it will solve your problem: http://stackoverflow.com/questions/18972202/how-can-i-invoke-an-ember-component-dynamically-via-a-variable,So essentially I need to be able to set the value and required properties and the content between the {{form-input}} block tags dynamically from the renderComponent helper in the stackoverflow answer.,@rlivsey I know Ember 2.0 is moving towards components, and that they’re taking a bigger and bigger role. So, ember-dynamic-component is great. However, I can’t wrap my head around my use case.,Here’s how I render it regularly, in a non-dynamic way:

Initially I just had a bunch of {{#if...}} statements like:

{
   {
      #if isBlue
   }
} {
   {
      blue - item item = item...
   }
} {
   {
      /if}} {
         {
            #if isRed
         }
      } {
         {
            red - item item = item...
         }
      } {
         {
            /if}} {
               {
                  #if isGreen
               }
            } {
               {
                  green - item item = item...
               }
            } {
               {
                  /if}}

I’ve tried to tidy this by creating a helper which renders the right component type:

Ember.Handlebars.registerBoundHelper 'component-for-type', (type, options) - >
   name =
   switch type
when 'red'
then "red-item"
when 'blue'
then "blue-item"
when 'green'
then "green-item"
else throw new Ember.Error("no component found for '#{type}'")

helper = Ember.Handlebars.resolveHelper(options.data.view.container, name)
helper.call(this, options)

That means I can replace all the {{if}}'s with one:

{
   {
      component -
         for -type item.type
      item = item
      selectedItem = selectedItem
      onSelect = "select"
      onChange = "change"
         ...
   }
}
load more v
65%

To define a component, run:,Picking different components to render in response to the data allows you to have different template and behavior for each case. The {{component}} helper is a powerful tool for improving code modularity.,handlebars {data-filename=app/templates/components/bar-component.hbs},handlebars {data-filename=app/templates/components/foo-component.hbs}

To define a component, run:

ember generate component my - component - name

A sample component template could look like this:

<article class="blog-post">
  <h1>{{title}}</h1>
  <p>{{yield}}</p>
  <p>Edit title: {{input type="text" value=title}}</p>
</article>

Given the above template, you can now use the {{blog-post}} component:

{
   {
      #each model as | post |
   }
} {
   {
      #blog - post title = post.title
   }
} {
   {
      post.body
   }
} {
   {
      /blog-post}} {
         {
            /each}}

javascript {data-filename=app/routes/index.js} export default Ember.Route.extend({ model() { return this.store.findAll('post'); } });

Each component, under the hood, is backed by an element. By default
Ember will use a `<div>` element to contain your component's template.
To learn how to change the element Ember uses for your component, see
[Customizing a Component's Element](./customizing-a-components-element/).


## Defining a Component Subclass

Often times, your components will just encapsulate certain snippets of
Handlebars templates that you find yourself using over and over. In
those cases, you do not need to write any JavaScript at all. Just define
the Handlebars template as described above and use the component that is
created.

If you need to customize the behavior of the component you'll
need to define a subclass of `Ember.Component`. For example, you would
need a custom subclass if you wanted to change a component's element,
respond to actions from the component's template, or manually make
changes to the component's element using JavaScript.

Ember knows which subclass powers a component based on its filename. For
example, if you have a component called `blog-post`, you would create a
file at `app/components/blog-post.js`. If your component was called
`audio-player-controls`, the file name would be at
`app/components/audio-player-controls.js`.

## Dynamically rendering a component

The `{{component}}` helper can be used to defer the selection of a component to
run time. The `{{my-component}}` syntax always renders the same component,
while using the `{{component}}` helper allows choosing a component to render on
the fly. This is useful in cases where you want to interact with different
external libraries depending on the data. Using the `{{component}}` helper would
allow you to keep different logic well-separated.

The first parameter of the helper is the name of a component to render, as a
string. So `{{component 'blog-post'}}` is just the same as using `{{blog-post}}`.

The real value of `{{component}}` comes from being able to dynamically pick
the component being rendered. Below is an example of using the helper as a
means of choosing different components for displaying different kinds of posts:

{{post.body}}

javascript {data-filename=app/routes/index.js} export default Ember.Route.extend({ model() { return this.store.findAll('post'); } });

load more v
75%

Returns a jQuery object for this component's element. If you pass in a selector string, this method will return a jQuery object, using the current element as its buffer.,For example, calling component.$('li') will return a jQuery object containing all of the li elements inside the DOM element of this component.,Class name bindings can also refer to object values that are found by traversing a path relative to the component itself:, LinkComponent

import Component from '@ember/component';
load more v
40%

https://stackoverflow.com/questions/18972202/how-can-i-invoke-an-ember-component-dynamically-via-a-variable,Render helper for Ember.js ( Allow render components dynamically ), 🐹🎭 Render helper for Ember.js ( Allow render components dynamically ) , 🐹🎭 Render helper for Ember.js ( Allow render components dynamically )

{
   {
      render - component 'image-component'
      src = ""
      class = "image"
   }
}

{
   {
      #render - component 'btn-component'
      action = "addSection"
   }
}

{
   {
      #render - component componentName _param = 'btn-component'
      action = "addSection"
   }
}
load more v
22%

The action name that should be invoked when the user clicks on the button is passed into the band-list-item component, and becomes the value of its faveAction property.,When the user clicks the “Fave this” button, the faveBand action gets triggered, which fires the component’s faveAction that was passed in (setAsFavorite, in the above case), on its parent component, band-list.,So in the above case, the band-list component would have to re-fire the action received from band-list-item in order to bubble it up to the controller or route.,This way, mutation does not happen in the components, and since the only app specific part is the handling of the action in the route, the component’s reusability does not suffer.

Let’s assume we have the following routes in our application:

Router.map(function() {
   this.route('band', {
      path: 'bands/:id'
   }, function() {
      this.route('songs');
   });
});
load more v

Other "component-undefined" queries related to "How can I invoke an ember component dynamically via a variable?"