我有以下代码:
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;
}
}
我想在Angular 2中开发一个搜索下拉建议小部件,当用户在输入框占位符中键入3个字符时,会向后端发出请求并返回json响应 . 每个搜索建议元素都在search.dropdown.component中动态加载,特别是在search.dropdown.component.html的#searchresult中 .
组件search.result.component是动态注入的,但是在外部呈现:
我想在datalist中注入动态组件,然后能够使用ViewChildren api访问属性建议search.result.component .
问题是搜索结果组件是在数据列表之外呈现的 . 如果我在html中放置div或模板标签以在其中呈现动态元素,则视图将正确呈现,但ViewChildren api不会检索动态注入的组件 .
如何使用在div标签内呈现的ViewChildren api组件进行访问?
谢谢
3 回答
我不明白你为什么使用@ViewChild ...你的
search.dropdown.component.html
可能是这样的:然后将您的sugestions作为组件中的输入进行分配以显示内容:
并在
search.dropdown.component.ts
中添加一个包含建议的字段:那么你所看到的是与角度路由器本身类似的东西,不是吗?看看这些来源:https://github.com/angular/angular/blob/master/modules/%40angular/router/src/directives/router_outlet.ts:
很快你就有一个 ViewContainerRef ,它将当前组件引用为容器和 ComponentFactoryResolver . 它们都是由构造函数注入的 .
使用方法
ComponentFactoryResolver.resolveComponentFactory(desiredComponent)
创建 componentFactory (上面的const factory
) .然后使用方法
ViewContainerRef.createComponent(componentFactory, index)
(此处为doc:https://angular.io/docs/ts/latest/api/core/index/ViewContainerRef-class.html#!#createComponent-anchor)将 desiredComponent (上面的this.activated
)添加到容器中 .所以在你的代码中,替换:
通过:
有一个棘手的解决方案 . 现在在Angular rc5之后,无法根据需要实现嵌套标记,但如果更改:
search.dropdown.component.html:
你应该在html代码中找到一些谎言:
模板标签不是由角度渲染的,而是更改为注释(任何其他标签f.ex. div将显示为空div .