3

I have a component called button-search which has a dropdown with search options:

<button-search> 
    <item type="identifier">Identifier</item>
    <item type="title">Title</item>
    <item type="city">City</item>
    <item type="town">Town</item>
    <item type="address">Address</item>
    <item type="postal">Postal</item>
    <item type="divider"></item>
    <item type="clear">Clear Search</item>
</button-search>

The item component is not supposed to render anything directly and is rather for passing complex params into the button-search component so that the button-search component can render those dropdown items the way it should be rendered.

Item is defined as follow:

@Component(
    selector: 'item',
    template: '')
class Item {

    @Input() String type = "type-goes-here";

}

ButtonSearch is defined as follow:

@Component(
    selector: 'button-search',
    directives: const[Item],
    template: '''
       ... enormous template ...    
    ''')
class ButtonSearch {

    ButtonSearch(@ViewChildren(Item) QueryList<Item> items){

        print(items);

    }
}

Instead of seeing a list of 9 items being printed to the console, all I'm seeing is [].

I've tried using a String param instead of an object, but it still gives me null.

ButtonSearch(@ViewChildren('item') QueryList<Item> items){
  1. What am I missing to make @ViewChildren get all the items and print something other than []

  2. Is there something special that needs to be done to get the text between <item> and </item> or will @ViewChild work for that ?

Update: Changing the template to include <ng-content></ng-content>:

template: '''
          <ng-content></ng-content>
           ... enormous template ...    
        ''')

I can see the following being printed in the browser as part of the button-search component:

Identifier, Title, City, Town, Address, Postal, Clear Search

So at least I know the page I'm on does have items in its button-search component.

Jan Vladimir Mostert
  • 12,380
  • 15
  • 80
  • 137
  • 1
    Please check if the `Item` components get instantiated. You can't query for `Item` if the elements are not upgrade to actual Angular components. – Günter Zöchbauer Jun 04 '16 at 12:08

1 Answers1

5

It should be

@Component(
    selector: 'button-search',
    directives: const[Item],
    template: '''
       <ng-content></ng-content>
       ... enormous template ...    
    ''')
class ButtonSearch implements AfterContentInit{
    @ContentChildren(Item) QueryList<Item> items;

    ngAfterContentInit() {
        print(items);
    }    
}

See also https://stackoverflow.com/a/35209681/217408

There is also the @Query() annotation which allows to constructor-inject references to child elements but it is marked deprecated.

<ng-content>
If you pass "content" as children to your component, then you can query them using @ContentChildren() instead of @ViewChildren(). If you want them to be displayed in the DOM you also need to add the <ng-content></ng-content> tag as a target for the transclusion. You can also have multiple <ng-content></ng-content> tags where a select=".someCssSelector" can be used to transclude a subset of content at a specific target location. There should be only one <ng-content></ng-content> without the select attribute though. The first without select will target all content that doesn't match other selectors.

Plunker example

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • I've got it exactly like that now and it's still printing `[]` – Jan Vladimir Mostert Jun 04 '16 at 11:37
  • `print(items)` is still printing out `[]` and `print(items.length)` is printing out `0`, so the items are still not getting into the ButtonSearch class. What I'm trying to do is to get a Dart list representation of all the child items of type `Item` so that I can do `print(item.type)` and `print(item.content)` after which I'm expecting a list in my console of `identifier`, `title`, ..., `clear` `` is printing out all the text inside the items, so at least I'm sure that the search button I'm looking at does have items. – Jan Vladimir Mostert Jun 04 '16 at 11:58
  • [**Plunker example**](https://plnkr.co/edit/CmsdHpAnRZb42E8Hnh2j?p=preview) in TypeScript, but should be easy to translate. Maybe you're missing the `Item` class in `directives` where you use it. – Günter Zöchbauer Jun 04 '16 at 12:04
  • Ah, didn't know I had to add the `Item` directive in two places. That fixes it :-D – Jan Vladimir Mostert Jun 04 '16 at 12:08
  • 1
    You only need it at one place to directives in your example. There is no need to add them to `directives` in the `ButtonSearch` component. – Günter Zöchbauer Jun 04 '16 at 12:09