Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

consider a component helper for dynamic component loading. #5007

Closed
stefanpenner opened this issue Jun 11, 2014 · 30 comments
Closed

consider a component helper for dynamic component loading. #5007

stefanpenner opened this issue Jun 11, 2014 · 30 comments

Comments

@stefanpenner
Copy link
Member

{{component nameOfComponentButBound 
                      actions=objectOfActionNameToSubscribedName
                      properties=objectOfPropertiesToBindTo}}

this would be quite handy for building very dynamic pages, that generate various components based on dynamic data.

This may be addon material...

@rwjblue
Copy link
Member

rwjblue commented Jun 11, 2014

I've been using component-lookup:main along with the {{view}} helper. The downside to this is that the view is not torn down when the dynamic property is changed.

I have a local branch where I am work on on making the view helper handle this properly.

@stefanpenner
Copy link
Member Author

Seems like view being bound and tore down would be great. But a component helpers dedicated to component lookups would also be good

@endash
Copy link
Contributor

endash commented Jun 11, 2014

@rjackson the fix workaround for the view not being torn down/reset on property change (that a bunch of us set upon one day on irc) is to wrap the {{view}} in {{#with}}

@stefanpenner
Copy link
Member Author

I kinda feel like this isn't addon material as it enables better core composition

@stefanpenner
Copy link
Member Author

I would be pretty happy if someone had time to implement this. I will gladly provided feedback and advocate for it

@machty
Copy link
Contributor

machty commented Jun 11, 2014

This seems related to stuff I've wanted for the link-to helper; right now link-to has half-ass support for dynamically linking to a controller property that contains a changing link name, but you're unfortunately stuck using a fixed number of contexts/models to pass to that target route, so there's no way to elegantly dynamically switching b/w a link to a dynamic route and a non-dynamic route, because one expects a model and the other not.

Perhaps there's a better overall primitive to consider, something like a Render Descriptor, which is best described by example:

SomeController.extend({
  thingToRender: function() {
    if(this.get('wat')) {
      return {
        params: ['link-to', 'articles', 123]
      };
    } else {
      return {
        params: ['link-to', 'about']
      };
    }
  }.property('wat')
});

// something.hbs
{{dynamic-render thingToRender}}

And this of course would extend to free to dynamic component renderings, but should be possible to render anything from a helper to a component to a view to a link.

@igorT
Copy link
Member

igorT commented Jun 11, 2014

We used something like this for dynamic input elements. Had to have an observer call render when the bound property changed. @jcollins1991

@machty
Copy link
Contributor

machty commented Jun 11, 2014

@igorT tell me more, curious

@machty
Copy link
Contributor

machty commented Jun 11, 2014

I want something like this for Ember (one exists for angular), and the one thing that's missing is easily swappable render parameters for overriding certain fields.

@igorT
Copy link
Member

igorT commented Jun 11, 2014

Don't have access to the code anymore, but it was basically a wrapper component that had a type property, which would then instantiate the correct components inside itself and rerender whenever type changed. @jcollins1911

@jcollins1991
Copy link
Contributor

could you elaborate on "the one thing that's missing is easily swappable render parameters for overriding certain fields" @machty ?? We have a few dynamic components in our codebase using slightly different techniques, could explain better if I knew your use case.

@machty
Copy link
Contributor

machty commented Jun 11, 2014

@jcollins1991 I'm saying if you have {{x-foo somethingFooSpecific=bar}}, even if you made x-foo swappable you don't want to be forced to always provide a value for every last hash option, or in the case of link-to, if you want to make it possible to swap b/w {{link-to 'article' someArticle}} and {{link-to 'about'}}, this isn't doable in the present day because one invocation provides a model someArticle and the other doesn't.

@rlivsey
Copy link
Contributor

rlivsey commented Jun 12, 2014

Would love to have something like this, I've hacked around it with a ContainerView which extends _Metamorph as discussed in this discourse thread.

@crismali
Copy link

@rjackson do you have your branch of this using the views up somewhere? @tonycoco and I don't want to get too deep into this if some of the legwork has already been done.

Attached here is a JSBin trying this out with an Ember View.

NOTE: This does not work... yet.

@stefanpenner
Copy link
Member Author

i think this is a good idea, but not really an issue. If someone wants to follow up with a PR that would be great

@green-arrow
Copy link
Contributor

I'd like to suggest re-opening this issue. See here for some background: http://discuss.emberjs.com/t/programmatically-rendering-ember-components/6986/2.

Basically, we have been able to, in the past, create a helper that renders a component based on a bound property, however the internals of this 'render-component' helper have changed with individual releases of Ember, and as of 1.9 (possibly 1.8), it no longer functions (again, see the link above for background).

@green-arrow
Copy link
Contributor

I very quickly wrote what I believe is a simple solution to this problem. I am not intimately familiar with the inner workings of Ember though, so I could be way off base here. What I did is add a new helper in ember-htmlbars/lib/helpers/component.js and register it.

import Ember from "ember-metal/core"; // Ember.assert
import lookupHelper from "ember-htmlbars/system/lookup-helper";

/**
 @module ember
 @submodule ember-htmlbars
 */

/**
 @method component
 @for Ember.Handlebars.helpers
 @param {String} componentName the name of the component to render
 */
export function componentHelper(params, hash, options, env) {
  Ember.assert('You can only one argument to the `component` helper, which should be ' +
               'a bound property whose value is the component to render.', params.length === 1);

  var helper = lookupHelper('loading-animation', env.data.view, env);
  return helper.helperFunction.call(this, [], hash, options, env);
}

I did a quick test in my application and it seemed to work correctly. Thoughts?

@rwjblue
Copy link
Member

rwjblue commented Dec 27, 2014

@green-arrow - That would work for a single one time lookup of a component from a bound property, but would not tear down and set up a new component if the bound property changed (this is roughly the same limitation as the {{view}} helper).

@green-arrow
Copy link
Contributor

@rwjblue - ah, I figured it couldn't be that the easy. Is this acceptable? Or would somebody else be interested in making this happen / pointing me in the right direction on making it happen?

@mmun
Copy link
Member

mmun commented Dec 28, 2014

@green-arrow @rwjblue I am fine with an dynamic, unbound component helper. We can assert if a stream is passed to the helper. So {{component foo}} would throw an assertion (until it is implemented) but {{unbound component foo bar=baz}} and {{component (unbound foo) bar=baz}} would work as expected.

@lukemelia
Copy link
Member

@mmunoz Would taking a similar approach to the partial helper be
appropriate? I.e when a stream is provided as the first parameters to the
view helper, create a metamorph view that subscribes to the stream and
tears down and appends a new child view when it changes.

On Sunday, December 28, 2014, Martin Muñoz [email protected] wrote:

@green-arrow https://github.com/green-arrow @rwjblue
https://github.com/rwjblue I am fine with an dynamic, unbound component
helper.


Reply to this email directly or view it on GitHub
#5007 (comment).

@mmun
Copy link
Member

mmun commented Dec 28, 2014

@lukemelia Yes, definitely.

@lukemelia
Copy link
Member

@mmunoz cool. I have some work in progress and should be able to pull
together a PR early this week.

On Sunday, December 28, 2014, Martin Muñoz [email protected] wrote:

@lukemelia https://github.com/lukemelia Yes, definitely.


Reply to this email directly or view it on GitHub
#5007 (comment).

@mmun
Copy link
Member

mmun commented Dec 28, 2014

@lukemelia I think we want to assert that the first argument is always a string name to be looked up in the container, so we don't make the same mistakes as the view helper. At least initially.

@lukemelia
Copy link
Member

@mmunoz makes sense. I was planning to start by making the view helper get
this behavior and then implement the component helper similarly but with
the restriction you mention.

On Sunday, December 28, 2014, Martin Muñoz [email protected] wrote:

@lukemelia https://github.com/lukemelia I think we want to assert that
the first argument is always a string name to be looked up in the
container, so we don't make the same mistakes as the view helper.


Reply to this email directly or view it on GitHub
#5007 (comment).

@rwjblue
Copy link
Member

rwjblue commented Dec 28, 2014

@lukemelia - ❤️

@mmun has made this much better/easier with his recent refactorings of the view helper.

@green-arrow
Copy link
Contributor

@lukemelia - Let me know if you'd like any help.

You all are awesome 😄

@rlivsey
Copy link
Contributor

rlivsey commented Dec 29, 2014

👍 for being able to kill ember-dynamic-component and having it built-in.

@lukemelia
Copy link
Member

My initial pass is up at #10093

@sreenaths
Copy link

Hi All,
Like in the first comment, is there some way for me to do "properties=objectOfPropertiesToBindTo". I'm trying to use component helper with dynamic properties.
Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests