I have following code:
search.component.ts
import { CoreComponent } from './../../core/components/core.component';
import { SearchDropDownComponent } from './search.dropdown.component';
import { Component,Input,EventEmitter, Output, ViewChild} from "@angular/core";
@Component({
selector:'search',
templateUrl:'app/templates/search.component.html',
styleUrls:['app/templates/css/search.component.css']
})
export class SearchComponent
{
@Input() core : CoreComponent;
@Output() onSearch : EventEmitter<any> = new EventEmitter();
@ViewChild(SearchDropDownComponent) dropdown: SearchDropDownComponent;
private searchText:String="";
search(event:any) : void
{
if (+event.keyCode==13 || event.type=="click")
{
this.onSearch.emit(event);
return;
}
}
}
search.component.html
<div class="input-group" id="search">
<input class="form-control kblue-background-pale" [(ngModel)]="searchText" (keypress)=search($event) placeholder="Search" list="search-dropdown" type="text">
<search-dropdown [core]="this.core" [typed]="this.searchText"></search-dropdown>
<div class="input-group-btn">
<div class="btn-group" role="group">
<button (click)="search($event)" type="button" class="btn kblue-background-pale">
<span class="glyphicon glyphicon-search kblue" aria-hidden="true">
</span>
</button>
</div>
</div>
</div>
search.dropdown.component.ts
import { CoreBase } from './../../core/components/core.base';
import { ComponentFactoryService } from './../../services/services/component.fac';
import { SearchResultComponent } from './search.result.component';
import { CoreComponent } from './../../core/components/core.component';
import { Component,
Input,AfterViewInit ,
ContentChildren,ContentChild,
Output,Inject,forwardRef,OnChanges,ElementRef,ViewChild,ViewContainerRef,ViewChildren,QueryList } from "@angular/core";
@Component(
{
selector:'search-dropdown',
templateUrl:'app/templates/search.dropdown.component.html',
styleUrls:['app/templates/css/search.dropdown.component.css']
}
)
export class SearchDropDownComponent implements AfterViewInit , OnChanges
{
@Input() core : CoreComponent;
@ViewChild('searchresult', {read: ViewContainerRef}) p: ViewContainerRef;
@ViewChildren(SearchResultComponent) t: QueryList<any>;
@ViewChild('parent', {read: ViewContainerRef}) children: ViewContainerRef;
private MLENGTH=2;
private RLENGTH=0;
private searchLength=0;
constructor(private factory:ComponentFactoryService) {
}
@Input()
set typed(typed:string)
{
if (typed.length>this.searchLength)
{
if (typed.length>this.MLENGTH)
{
this.core.webservice(this.result,"communities",{search:typed});
}
this.searchLength=typed.length;
}
else
{
if (typed.length==this.RLENGTH)
{
this.p.clear();
this.searchLength=0;
}
}
console.log(this.p.length);
console.log(this.children);
// for(var index = 0; index < this.p.length; index++)
//{
// console.log(this.t);
// }
}
ngAfterViewInit() {
}
ngOnChanges()
{
console.log(this.p.element.nativeElement.childNodes);
console.log(this.children);
}
public result=(data:any)=>
{
data.forEach((item:any)=>
{
this.factory.getComponent(this.p,SearchResultComponent,item);
});
}
}
search.dropdown.component.html:
<datalist id="search-dropdown" #searchresult></datalist>
search.result.component.ts:
import { CoreBase } from './../../core/components/core.base';
import { Component,OnInit,TemplateRef} from "@angular/core";
@Component({
selector:'search-result',
templateUrl:'app/templates/search.result.component.html',
styleUrls:['app/templates/css/search.result.component.css']
})
export class SearchResultComponent extends CoreBase implements OnInit
{
private suggestions:String;
constructor()
{
super();
}
ngOnInit()
{
this.suggestions=this.parameters["search"];
}
}
search.result.component.html:
<option>{{suggestions}}</option>
component.fac.ts (Component factory service):
import { CoreBase } from './../../core/components/core.base';
import {
Injectable,
ReflectiveInjector,
ViewContainerRef,
ComponentFactoryResolver
} from '@angular/core';
@Injectable()
export class ComponentFactoryService
{
constructor(private componentFactoryResolver: ComponentFactoryResolver)
{
}
public getComponent(refDOM:ViewContainerRef, component:any,parameters:any)
{
let factory = this.componentFactoryResolver.resolveComponentFactory(component);
let injector = ReflectiveInjector.fromResolvedProviders([], refDOM.parentInjector);
let comp = factory.create(injector);
(<CoreBase>comp.instance).parameters=parameters;
comp.changeDetectorRef.detectChanges();
refDOM.insert(comp.hostView,0);
return comp.instance;
}
}
I want to develop a search dropdown suggestion widget in Angular 2, when the user types 3 characters in the input box placeholder a request is done to a backend and a json response is returned. Each search suggestion element is dynamically loaded in the search.dropdown.component, specifically in the #searchresult of search.dropdown.component.html.
The components, search.result.component, are injected dynamically, but are rendered outside:
I want to inject the dynamic components inside the datalist and be able to access the attribute suggestion search.result.component afterwards with the ViewChildren api.
The problem is that the search-result components are rendered outside the datalist. If I put a div or a template tag in the html to render the dynamic elements inside, the view is rendered properly but the ViewChildren api doesn't retrieve the dynamic injected components.
How can I access with ViewChildren api components rendered inside a div tag?
Thank you