Angular material <mat-selection-list> 和 <mat-list-option> 跨模板边界
Angular material <mat-selection-list> and <mat-list-option> across template boundaries
如何制作 <mat-list-option>
-- 在组件 sub
中声明 -- "subscribe" 到 <mat-selection-list>
外部组件 sub
(比如说,组件 app
)?
(不幸的是,我无法让 Stackblitz 与我公司的代理一起工作,所以我只放我的示例的相关部分)
示例 1(有效,无组件 sub
)
(app.component.html)
<div>{{selections | json}}</div>
<mat-selection-list [(ngModel)]="selections">
<mat-list-option [value]="{x: 1}">x: 1</mat-list-option>
<mat-list-option [value]="{x: 2}">x: 2</mat-list-option>
<mat-list-option [value]="{y: 1}">y: 1</mat-list-option>
<mat-list-option [value]="{y: 2}">y: 2</mat-list-option>
</mat-selection-list>
(app.component.ts)
@Component({
templateUrl: './app.component.html',
})
export class AppComponent {
selections = [];
}
此示例按预期工作。所有 4 个选项都被渲染,它们的选择反映在 selections
属性 中(所有选项的值都是 javascript 对象,并且它们从 selections
数组).
示例 2(不起作用,在 <mat-selection-list>
和 <mat-list-option>
之间添加了组件 sub
)
(app.component.html)
<div>{{selections | json}}</div>
<mat-selection-list [(ngModel)]="selections">
<sub></sub>
</mat-selection-list>
(sub.component.html)
<mat-list-option [value]="{x: 1}">x: 1</mat-list-option>
<mat-list-option [value]="{x: 2}">x: 2</mat-list-option>
<mat-list-option [value]="{y: 1}">y: 1</mat-list-option>
<mat-list-option [value]="{y: 2}">y: 2</mat-list-option>
(app.component.ts 不变;sub.component.ts 微不足道)
此示例确实按预期呈现了所有选项。他们的选择不会反映回 selections
属性(正如预期的那样,因为在每个 <mat-list-option>
被实例化时,没有可见的 <mat-selection-list>
供他们订阅) .
例3(尝试转发<mat-selection-list>
,无果)
(app.component.ts)
@Component({
...
viewProviders: [{ provide: MatSelectionList, useExisting: MatSelectionList }]
})
export class AppComponent {
selections = [];
}
我预计这个会起作用。但我只能得到一个错误:
Cannot instantiate cyclic dependency! MatSelectionList (...)
如何进行这项工作?
备注
我想观察 ngModel
指令(与 ngForm
and/or ngModelGroup
协同工作)只需添加适当的模板边界即可完美工作viewProviders
到实例化 ngForm
或 ngModelGroup
(含)和实例化 ngModel
(不含)之间的所有中间组件。
虽然它们的注入路径不一样:ngModel
通过 获取其父 ControlContainer
(包含 ngForm
和 ngModelGroup
) [source]:
constructor(@Optional() @Host() parent: ControlContainer, ...) {...}
而 <mat-list-option>
通过 [source]:
constructor(..., @Inject(forwardRef(() => MatSelectionList)) public selectionList: MatSelectionList) {...}
我 angular 不了解这些差异及其含义。
MatSelectList 的内置 SelectionModel 与示例 2 方法配合使用效果很好。问题在于 NgModel(这可能是错误或固有限制)。您可以通过监听列表的选择更改并直接管理模型来解决此问题。例如:
HTML
<mat-selection-list [ngModel]="selections" (selectionChange)="handleSelectionChange($event.option)">
<sub></sub>
</mat-selection-list>
TS
selections = [];
handleSelectionChange(option: MatSelectionListChange) {
if (option.selected) {
this.selections.push(option.value);
}
else {
const index = this.selections.indexOf(option.value);
this.selections.splice(index, 1);
}
}
如何制作 <mat-list-option>
-- 在组件 sub
中声明 -- "subscribe" 到 <mat-selection-list>
外部组件 sub
(比如说,组件 app
)?
(不幸的是,我无法让 Stackblitz 与我公司的代理一起工作,所以我只放我的示例的相关部分)
示例 1(有效,无组件 sub
)
(app.component.html)
<div>{{selections | json}}</div>
<mat-selection-list [(ngModel)]="selections">
<mat-list-option [value]="{x: 1}">x: 1</mat-list-option>
<mat-list-option [value]="{x: 2}">x: 2</mat-list-option>
<mat-list-option [value]="{y: 1}">y: 1</mat-list-option>
<mat-list-option [value]="{y: 2}">y: 2</mat-list-option>
</mat-selection-list>
(app.component.ts)
@Component({
templateUrl: './app.component.html',
})
export class AppComponent {
selections = [];
}
此示例按预期工作。所有 4 个选项都被渲染,它们的选择反映在 selections
属性 中(所有选项的值都是 javascript 对象,并且它们从 selections
数组).
示例 2(不起作用,在 <mat-selection-list>
和 <mat-list-option>
之间添加了组件 sub
)
(app.component.html)
<div>{{selections | json}}</div>
<mat-selection-list [(ngModel)]="selections">
<sub></sub>
</mat-selection-list>
(sub.component.html)
<mat-list-option [value]="{x: 1}">x: 1</mat-list-option>
<mat-list-option [value]="{x: 2}">x: 2</mat-list-option>
<mat-list-option [value]="{y: 1}">y: 1</mat-list-option>
<mat-list-option [value]="{y: 2}">y: 2</mat-list-option>
(app.component.ts 不变;sub.component.ts 微不足道)
此示例确实按预期呈现了所有选项。他们的选择不会反映回 selections
属性(正如预期的那样,因为在每个 <mat-list-option>
被实例化时,没有可见的 <mat-selection-list>
供他们订阅) .
例3(尝试转发<mat-selection-list>
,无果)
(app.component.ts)
@Component({
...
viewProviders: [{ provide: MatSelectionList, useExisting: MatSelectionList }]
})
export class AppComponent {
selections = [];
}
我预计这个会起作用。但我只能得到一个错误:
Cannot instantiate cyclic dependency! MatSelectionList (...)
如何进行这项工作?
备注
我想观察 ngModel
指令(与 ngForm
and/or ngModelGroup
协同工作)只需添加适当的模板边界即可完美工作viewProviders
到实例化 ngForm
或 ngModelGroup
(含)和实例化 ngModel
(不含)之间的所有中间组件。
虽然它们的注入路径不一样:ngModel
通过 获取其父 ControlContainer
(包含 ngForm
和 ngModelGroup
) [source]:
constructor(@Optional() @Host() parent: ControlContainer, ...) {...}
而 <mat-list-option>
通过 [source]:
constructor(..., @Inject(forwardRef(() => MatSelectionList)) public selectionList: MatSelectionList) {...}
我 angular 不了解这些差异及其含义。
MatSelectList 的内置 SelectionModel 与示例 2 方法配合使用效果很好。问题在于 NgModel(这可能是错误或固有限制)。您可以通过监听列表的选择更改并直接管理模型来解决此问题。例如:
HTML
<mat-selection-list [ngModel]="selections" (selectionChange)="handleSelectionChange($event.option)">
<sub></sub>
</mat-selection-list>
TS
selections = [];
handleSelectionChange(option: MatSelectionListChange) {
if (option.selected) {
this.selections.push(option.value);
}
else {
const index = this.selections.indexOf(option.value);
this.selections.splice(index, 1);
}
}