在 angular 5 中使用 ngx-bootstrap typeahead 和模型值数组
using ngx-bootstrap typeahead in angular 5 with an array of model values
HTML 模板
<tr *ngFor="let wi of page.items" (click)="selectWorkItem(wi)">
<td><input [ngModel]="wi.checked" type="checkbox"></td>
<td [textContent]="wi.someText"></td>
<td>
<input
class="form-control"
tabindex="-1"
[typeahead]="WHAT THE ?" <!-- tried propertyManagers below -->
[ngModel]="wi.propertyManager" />
组件
export class WorkItemListComponent implements OnInit {
selectedPropertyManager: any;
propertyManagers = Observable.create((observer: any) => {
observer.next(this.selectedPropertyManager);
}).mergeMap((token: string) =>
this.partyService.loadPartyHints(token).map(_ => _.displayName));
page.items
包含对应于 table 中每一行的项目列表。
我观察到的是,在我的例子中,observer.next
意味着绑定到 page.items[?].propertyManager
的 [ngModel]
,但可观察对象实际上绑定到 selectedPropertyManager
(这与 [ngModel]
).
不同
有什么方法可以创建一个 typeahead 来观察当前模型值,并将其传递给 loadPartyHints
函数。
<input
class="form-control"
tabindex="-1"
[typeahead]="CREATE_OBSERVABLE_OVER_MODEL(wi.propertyManager)"
[ngModel]="wi.propertyManger"
<!-- THIS is the model value, not selectedPropertyManager -->
编辑
我已经试过了...
有了这样的模板...
<input
#inp
class="form-control"
tabindex="-1"
[typeahead]="propertyManagers"
[(ngModel)]="wi.propertyManager"
(ngModelChange)="valueChanged(inp.value)"/>
及以下Subject
hints = new Subject();
propertyManagers = this.hints.mergeMap((token: string) => this.partyService.loadPartyHints(token).map(_ => _.map(x => x.displayName)));
valueChanged(value: string) {
this.logger.info(`input changed :: ${value}`);
this.hints.next(value);
}
这让我更接近了,但现在所有 ngx-bootstrap
typeahead 都相互干扰并获取彼此的数据。
我需要有人创建一个 Subject
/ Observable
独立连接每一行的工厂吗?
import { Component, Provider, forwardRef, Input, Output, EventEmitter } from "@angular/core";
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
import { NGXLogger } from "ngx-logger";
import { Subject } from "rxjs/Subject";
@Component({
selector: "typeahead-input",
template: `<input
#inp
class="form-control"
tabindex="-1"
[typeahead]="observable"
[(ngModel)]="value"
(typeaheadOnSelect)="select($event)"
(ngModelChange)="hintValueChanged(inp.value)"/>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TypeaheadInputComponent),
multi: true
}]
})
export class TypeaheadInputComponent implements ControlValueAccessor {
private _value: any = "";
hints = new Subject();
observable = this.hints.mergeMap((token: string) => this.loadHints(token));
@Input() hint: Function;
@Output() itemSelected = new EventEmitter<string>();
constructor(
private readonly logger: NGXLogger) {
}
get value(): any { return this._value; };
set value(v: any) {
if (v !== this._value) {
this._value = v;
this.onChange(v);
}
}
loadHints(token: string) {
this.logger.info(`loading hints ${token}`);
return this.hint(token);
}
hintValueChanged(hint: string) {
this.logger.info(`typehead :: hint value (${hint})`);
this.hints.next(hint);
}
select(selectedItem: any) {
this.itemSelected.emit(selectedItem.value);
}
writeValue(value: any) {
this._value = value;
this.onChange(value);
}
onChange = (_) => { };
onTouched = () => { };
registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
}
HTML 模板
<tr *ngFor="let wi of page.items" (click)="selectWorkItem(wi)">
<td><input [ngModel]="wi.checked" type="checkbox"></td>
<td [textContent]="wi.someText"></td>
<td>
<input
class="form-control"
tabindex="-1"
[typeahead]="WHAT THE ?" <!-- tried propertyManagers below -->
[ngModel]="wi.propertyManager" />
组件
export class WorkItemListComponent implements OnInit {
selectedPropertyManager: any;
propertyManagers = Observable.create((observer: any) => {
observer.next(this.selectedPropertyManager);
}).mergeMap((token: string) =>
this.partyService.loadPartyHints(token).map(_ => _.displayName));
page.items
包含对应于 table 中每一行的项目列表。
我观察到的是,在我的例子中,observer.next
意味着绑定到 page.items[?].propertyManager
的 [ngModel]
,但可观察对象实际上绑定到 selectedPropertyManager
(这与 [ngModel]
).
有什么方法可以创建一个 typeahead 来观察当前模型值,并将其传递给 loadPartyHints
函数。
<input
class="form-control"
tabindex="-1"
[typeahead]="CREATE_OBSERVABLE_OVER_MODEL(wi.propertyManager)"
[ngModel]="wi.propertyManger"
<!-- THIS is the model value, not selectedPropertyManager -->
编辑
我已经试过了...
有了这样的模板...
<input
#inp
class="form-control"
tabindex="-1"
[typeahead]="propertyManagers"
[(ngModel)]="wi.propertyManager"
(ngModelChange)="valueChanged(inp.value)"/>
及以下Subject
hints = new Subject();
propertyManagers = this.hints.mergeMap((token: string) => this.partyService.loadPartyHints(token).map(_ => _.map(x => x.displayName)));
valueChanged(value: string) {
this.logger.info(`input changed :: ${value}`);
this.hints.next(value);
}
这让我更接近了,但现在所有 ngx-bootstrap
typeahead 都相互干扰并获取彼此的数据。
我需要有人创建一个 Subject
/ Observable
独立连接每一行的工厂吗?
import { Component, Provider, forwardRef, Input, Output, EventEmitter } from "@angular/core";
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
import { NGXLogger } from "ngx-logger";
import { Subject } from "rxjs/Subject";
@Component({
selector: "typeahead-input",
template: `<input
#inp
class="form-control"
tabindex="-1"
[typeahead]="observable"
[(ngModel)]="value"
(typeaheadOnSelect)="select($event)"
(ngModelChange)="hintValueChanged(inp.value)"/>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TypeaheadInputComponent),
multi: true
}]
})
export class TypeaheadInputComponent implements ControlValueAccessor {
private _value: any = "";
hints = new Subject();
observable = this.hints.mergeMap((token: string) => this.loadHints(token));
@Input() hint: Function;
@Output() itemSelected = new EventEmitter<string>();
constructor(
private readonly logger: NGXLogger) {
}
get value(): any { return this._value; };
set value(v: any) {
if (v !== this._value) {
this._value = v;
this.onChange(v);
}
}
loadHints(token: string) {
this.logger.info(`loading hints ${token}`);
return this.hint(token);
}
hintValueChanged(hint: string) {
this.logger.info(`typehead :: hint value (${hint})`);
this.hints.next(hint);
}
select(selectedItem: any) {
this.itemSelected.emit(selectedItem.value);
}
writeValue(value: any) {
this._value = value;
this.onChange(value);
}
onChange = (_) => { };
onTouched = () => { };
registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
}