Reputation: 1605
I'm currently using Angular2 (Dart) to create a reusable search box component, which includes a suggestion box.
The trouble I'm running into is that I'm not sure how to make the suggestion box extensible by supporting richer suggestion types, such as suggestions with icons, suggestions with multiple lines of text, varying styles on the text, animations, etc.
Currently the suggestion box HTML (stripped down) looks a bit like this:
<div class="suggestion-box-container">
<div class="suggestion" *ng-for="#suggestion of model.suggestions">
{{ suggestion.text }}
</div>
</div>
And the Dart code looks sort of like this:
@Component(
selector: 'suggestion-box'
)
@View(
templateUrl: 'suggestion_box.html',
directives: const [NgFor]
)
class SuggestionBox {
final SuggestionModel model;
// ...
}
class SuggestionModel {
List<Suggestion> suggestions = [];
// ...
}
class Suggestion {
String text;
// ...
}
I'm wondering how I can modify this design so that a user can extend Suggestion
and write their own corresponding suggestion component.
I considered something like
<basic-suggestion *ng-if="suggestion.type == 'basic'"></basic-suggestion>
<icon-suggestion *ng-if="suggestion.type == 'icon'"></icon-suggestion>
...
But of course that would get out of hand quickly as more suggestion types are supported, and would also require duplicating the (^hover)
and (^click)
handlers to each type of suggestion. Worse yet, it would require modifying the original library rather than just using it in a modular way.
Is there an elegant solution to this sort of thing? Or would users simply be better off writing their own suggestion box entirely if they wanted richer suggestions? I'm hoping to avoid that since I want to bake in a bunch of accessibility functionality into the search box/suggestion box that the user shouldn't need to rewrite.
EDIT: based on Gunter's answer I've managed to improve this by a little bit:
<suggestion-box>
<div *ng-for="#suggestion in suggestions">
<suggestion suggestion-instance="suggestion">
<!-- Custom suggestion code goes here.
The following is an example -->
<img src="{{suggestion.iconSrc}}"></img> {{suggestion.text}}
</suggestion>
</div>
</suggestion>
I have a new suggestion
component that looks a bit like this:
@Component(
selector: 'suggestion',
properties: const ['suggestion: suggestion-instance']
)
@View(
template: '''
<div (^click)="handleClick(suggestion)"
(hover)="handleHover(suggestion)">
<content></content>
</div>
'''
)
class SuggestionComponent {
final SuggestionModel model;
final Suggestion suggestion;
// ...
}
This is a bit nicer now because the user now gets accessibility/keyboard control/mouse control out of the box. But this still isn't ideal. I'd somehow like the template to automatically determine the appropriate component to use based on the actual subclass of the suggestion
. I suppose I could define a method in each component like getTemplate()
but that probably wouldn't be a very Angular-esque way of doing it.
Upvotes: 2
Views: 1210
Reputation: 657118
I haven't really used Angular2 but I think there are at least two ways to do it
- You should be able to extend a component (just create a derived class and specialize the behavior
- Use composition with the <content>
tag of the shadow DOM. I found some docs here https://www.airpair.com/angularjs/posts/creating-components-p3-angular2-directives
- Or a combination of the two
update
Support for extending components is coming with version 3.2.
Annotations like @HostBinding()
, @HostListener()
, @ViewChild()
, @ContentChild()
will be recognised on subclasses, so will be interfaces for OnInit
and other lifecycle callbacks
There are different ways beside inheritanc to make a component customizable.
You can pass component types to be instantiated by your search box using DynamicComponentLoader,
pass children to be displayed at <ng-content>
locations,
or pass <template>
content to be added dynamically by your search component, and probably others.
Upvotes: 1