在 HTML 模板中声明的组件中获取组件
Getting component inside component which is declared in HTML template
我想创建过滤器组件,它将在不同的地方使用不同数量的内部组件。
filter.component.html
<select-filter name="somename" ></select-filter>
<input-filter name="somename"></input-filter>
...
Select-filter 和 input filter 是实现 Interface FilterItem
的组件
export interface FilterItem{
name: string;
getValue() : any;
}
我想在 filter.component.ts 中获取每个组件的实例(例如调用 getValue() );
最好的方法是什么?
听起来您想创建作为表单控件的组件。
如果我是对的,请尝试使用 ControlValueAccessor
:
https://angular.io/api/forms/ControlValueAccessor
有很多关于如何使用它们的示例。
这是取自 https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html
的实施示例
export function createCounterRangeValidator(maxValue, minValue) {
return (c: FormControl) => {
let err = {
rangeError: {
given: c.value,
max: maxValue || 10,
min: minValue || 0
}
};
return (c.value > +maxValue || c.value < +minValue) ? err: null;
}
}
@Component({
selector: 'counter-input',
template: `
<button (click)="increase()">+</button> {{counterValue}} <button (click)="decrease()">-</button>
`,
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CounterInputComponent), multi: true },
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => CounterInputComponent), multi: true }
]
})
export class CounterInputComponent implements ControlValueAccessor, OnChanges {
propagateChange:any = () => {};
validateFn:any = () => {};
@Input('counterValue') _counterValue = 0;
@Input() counterRangeMax;
@Input() counterRangeMin;
get counterValue() {
return this._counterValue;
}
set counterValue(val) {
this._counterValue = val;
this.propagateChange(val);
}
ngOnChanges(inputs) {
if (inputs.counterRangeMax || inputs.counterRangeMin) {
this.validateFn = createCounterRangeValidator(this.counterRangeMax, this.counterRangeMin);
this.propagateChange(this.counterValue);
}
}
writeValue(value) {
if (value) {
this.counterValue = value;
}
}
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched() {}
increase() {
this.counterValue++;
}
decrease() {
this.counterValue--;
}
validate(c: FormControl) {
return this.validateFn(c);
}
}
接下来就是解决方案
1) 父组件使用@ContentChildren 或@ViewChildren 获取子组件的数据,参数为QueryList。参数是抽象的 class 很重要。我们不能在那里使用接口。其实我们也不能使用abstract class,而是在嵌套组件中使用provider。
在我的例子中是
export class FilterComponent{
@ContentChildren(FilterItem) filterItems: QueryList<FilterItem>;
constructor() {}
getItems(){
console.log(this.filterItems);
this.filterItems.forEach( i => {
console.log( 'My name is ' + i.name + 'My value is ' + i.getValue());
});
}
}
2) 嵌套组件应扩展抽象 class 并将此抽象 class 声明为提供者。
就我而言
@Component({
selector: 'app-string-filter-item',
templateUrl: './string-filter-item.component.html',
styleUrls: ['./string-filter-item.component.scss'],
providers: [{provide: FilterItem, useExisting: forwardRef(() => StringFilterItemComponent)}]
})
export class StringFilterItemComponent extends FilterItem {
selectValue: string;
@Input()
name:string;
caption: 'SHow me smt';
getValue(){
return this.selectValue;
}
}
字符串过滤器-item.component.html
<p>
<input type="text" [(ngModel)]="selectValue">
</p>
filter.component.html
<div class="filter-wr">
<ng-content></ng-content>
</div>
在任何地方使用过滤器组件
( select 字符串组件是我使用的另一个组件)
<app-filter>
<app-select-filter-item name="first"></app-select-filter-item>
<app-string-filter-item name="second"></app-string-filter-item>
<app-select-filter-item name="third"></app-select-filter-item>
<app-string-filter-item name="fourth"></app-string-filter-item>
</app-filter>
就是这样!感谢您的关注!
我想创建过滤器组件,它将在不同的地方使用不同数量的内部组件。
filter.component.html
<select-filter name="somename" ></select-filter>
<input-filter name="somename"></input-filter>
...
Select-filter 和 input filter 是实现 Interface FilterItem
的组件export interface FilterItem{
name: string;
getValue() : any;
}
我想在 filter.component.ts 中获取每个组件的实例(例如调用 getValue() ); 最好的方法是什么?
听起来您想创建作为表单控件的组件。
如果我是对的,请尝试使用 ControlValueAccessor
:
https://angular.io/api/forms/ControlValueAccessor
有很多关于如何使用它们的示例。 这是取自 https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html
的实施示例export function createCounterRangeValidator(maxValue, minValue) {
return (c: FormControl) => {
let err = {
rangeError: {
given: c.value,
max: maxValue || 10,
min: minValue || 0
}
};
return (c.value > +maxValue || c.value < +minValue) ? err: null;
}
}
@Component({
selector: 'counter-input',
template: `
<button (click)="increase()">+</button> {{counterValue}} <button (click)="decrease()">-</button>
`,
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CounterInputComponent), multi: true },
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => CounterInputComponent), multi: true }
]
})
export class CounterInputComponent implements ControlValueAccessor, OnChanges {
propagateChange:any = () => {};
validateFn:any = () => {};
@Input('counterValue') _counterValue = 0;
@Input() counterRangeMax;
@Input() counterRangeMin;
get counterValue() {
return this._counterValue;
}
set counterValue(val) {
this._counterValue = val;
this.propagateChange(val);
}
ngOnChanges(inputs) {
if (inputs.counterRangeMax || inputs.counterRangeMin) {
this.validateFn = createCounterRangeValidator(this.counterRangeMax, this.counterRangeMin);
this.propagateChange(this.counterValue);
}
}
writeValue(value) {
if (value) {
this.counterValue = value;
}
}
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched() {}
increase() {
this.counterValue++;
}
decrease() {
this.counterValue--;
}
validate(c: FormControl) {
return this.validateFn(c);
}
}
接下来就是解决方案
1) 父组件使用@ContentChildren 或@ViewChildren 获取子组件的数据,参数为QueryList。参数是抽象的 class 很重要。我们不能在那里使用接口。其实我们也不能使用abstract class,而是在嵌套组件中使用provider。 在我的例子中是
export class FilterComponent{
@ContentChildren(FilterItem) filterItems: QueryList<FilterItem>;
constructor() {}
getItems(){
console.log(this.filterItems);
this.filterItems.forEach( i => {
console.log( 'My name is ' + i.name + 'My value is ' + i.getValue());
});
}
}
2) 嵌套组件应扩展抽象 class 并将此抽象 class 声明为提供者。 就我而言
@Component({
selector: 'app-string-filter-item',
templateUrl: './string-filter-item.component.html',
styleUrls: ['./string-filter-item.component.scss'],
providers: [{provide: FilterItem, useExisting: forwardRef(() => StringFilterItemComponent)}]
})
export class StringFilterItemComponent extends FilterItem {
selectValue: string;
@Input()
name:string;
caption: 'SHow me smt';
getValue(){
return this.selectValue;
}
}
字符串过滤器-item.component.html
<p>
<input type="text" [(ngModel)]="selectValue">
</p>
filter.component.html
<div class="filter-wr">
<ng-content></ng-content>
</div>
在任何地方使用过滤器组件 ( select 字符串组件是我使用的另一个组件)
<app-filter>
<app-select-filter-item name="first"></app-select-filter-item>
<app-string-filter-item name="second"></app-string-filter-item>
<app-select-filter-item name="third"></app-select-filter-item>
<app-string-filter-item name="fourth"></app-string-filter-item>
</app-filter>
就是这样!感谢您的关注!