Given the model for the page section, which contains several fields and will be filled with data such as:
{ "fields": [ { "id": 1, "type": "text", "caption": "Name", "value": "Bob" }, { "id": 2, "type": "bool", "caption": "Over 24?", "value": 0 }, { "id": 3, "type": "options", "options" : [ "M", "F"], "caption": "Gender", "value": "M" } ] }
I would like to have a general “Component” section that does not know about the different types of fields that it could wrap in order to avoid a lot of conditional logic in the section template and create new views / components of the field type that are added by dumping in an offline file, and not to modify an individual component.
My ideal would be for the component selector specific enough so that I can accomplish this by selecting an element in the parent Component template based on the attribute values associated with the model. For example: (sorry for any syntax problems, since I encoded this in the SO window, the main part that you need to pay attention to is the selector on BooleanComponent.ts
SectionComponent.ts
@Component({ selector: 'my-app' }) @View({ template: ` <section> <div *ng-for="#field of fields"> <field type="{{field.type}}"></field> </div> </section> `, directives: [NgFor] }) class SectionComponent { fields: Array<field>; constructor() { this.fields =
FieldComponent.ts:
BooleanComponent.ts:
// specific field component to use for boolean fields @Component({ selector: 'field[type=bool]' }) @View({ template: `<input type="checkbox" [id]="id" [checked]="value==1"></input>` }) class BooleanComponent { constructor() {} }
... and over time I will add new components to provide special patterns and behavior for other specific types of fields or even fields with specific headers, etc.
This does not work because component selectors must be the simple name of the element (at least in .26 alpha and .27 alpha). My research on github conversations led me to believe that this restriction was relaxed, but I can’t determine if what I want to do is really supported.
Alternatively, I saw the mentioned DynamicComponentLoader, although now I can not find the example that I thought was in the angular.io manual. However, I do not know how it could be used to dynamically load a component that does not know the name or matching criteria.
Is there a way to accomplish my task of decoupling specialized components from their parents, using either a technique similar to the one I tried, or some other technique that I don't know about in Angular 2?
UPDATE 2015-07-06
http://plnkr.co/edit/fal9OA7ghQS1sRESutGd?p=preview
I thought it was better to show the errors that I encounter more explicitly. I turned on the plunger with some sample code, but only the first of these three errors will be visible, since each of them blocks the other, so you can only show one at a time. I am hardcoded to get around No. 2 and No. 3 at the moment.
- Will my selector in the BooleanComponent
selector: 'field[type=bool]' or selector: '[type=bool]' , I get an error stack from Angular asThe "BooleanComponent" component can only have an element selector, but has "[type = bool]"
<field [type]="field.type"></field> does not bind the value of my field.type value to the type attribute, but gives me this error (which, fortunately, now appears in alpha 28. In alpha 26, I was previously turned on, it did not pass silently). I can get rid of this error by adding a type property to my FieldComponent and a derived BooleanComponent and connecting it to the @Component property collection, but I don't need this for anything in the components.You cannot bind to a "type", since this is not a know property of the "field" element, and there are no corresponding directives with the corresponding property
- I have to list FieldComponent and BooleanComponent in the list of directives of my SectionComponent View annotation, otherwise they will not be found and applied. I read the design discussions from the Angular team, where they made this conscious decision in favor of an explanation in order to reduce cases of collisions with directives in external libraries, but this breaks the whole idea of the drop-in components I'm trying to achieve.
At this point, I'm struggling to understand why Angular2 is even worried about having selectors. The parent component should already know which child components it will have, where they will go, and what data they need. Selectors are currently completely redundant, it could also be a class matching agreement. I do not see abstractions between the components that I need to separate them.
Due to these limitations in the ability of the Angular2 structure, I make my own component registration scheme and place them through DynamicComponentLoader, but I would still be very interested to see the answers for people who have found the best way to achieve this.