Angular <select> 绑定到对象确认更改或恢复到以前的值
Angular <select> Bound to Object Confirm Change or Revert to the Previous Value
我正在尝试实现非常简单的 <select>
行为:如果用户取消更改,则恢复到以前的值。实际上,我成功了,但是那花了我几个小时,而且我对实现仍然不满意,因为它不是那么明显和棘手。
所以,这是模板:
<select id="states" class="form-control" name="states" [ngModel]="selectedState"
(ngModelChange)="onStateChange(selectedState, $event)">
<option [ngValue]="null">All</option>
<option *ngFor="let state of states" [ngValue]="state">{{state.name}}</option>
</select>
和组件:
export class AppComponent {
selectedState: State = null;
states: State[] = [
{ name: 'Alabama', population: 100000 },
{ name: 'Alaska', population: 50000 }
];
onStateChange(previousState: State, state: State): void {
// If we're changing state from "All" to any, it's OK
if (previousState === null) {
this.selectedState = state;
return;
}
// Otherwise we want the user to confirm that change
if (confirm('Are you sure you want to select another state?')) {
this.selectedState = state;
} else {
// But instead of just `this.selectedState = previousState;`
// I need to proceed with below dirty hack.
// Step 1: Changing property value, which is bound to `[ngModel]`,
// to any, except for the current one, so `null` is OK
this.selectedState = null;
// Step 2: Reverting this property value to the previous one,
// which is, ridiculously, already set as the previous one,
// because we're reverting `this.selectedState`,
// while passing exactly the same `this.selectedState`
// to this method as a `previousState` parameter,
// so we're actually doing `this.selectedState = this.selectedState;`,
// but in not-so-obvious form.
// This works only kind of asynchronously,
// after call stack is clear.
setTimeout(() => {
this.selectedState = previousState;
}, 0);
}
}
}
我希望评论是不言自明的,至少我试着把它们写成这样。
正如我在评论中提到的,简单的 this.selectedState = previousState;
不起作用,并且省略了 setTimeout()
。我也试过这个,但没有成功:
this.selectedState = previousState;
this.changeDetectorRef.detectChanges();
我的解决方案也是基于 , and yes, I saw ,但它对我不起作用,因为我将 <select>
绑定到一个对象,而不是标量值。
演示: https://angular-hkaznb.stackblitz.io
软件包版本:
Angular: 6.0.0
看来我找到了更优雅的解决方案,它基于 。这个想法是操纵<select>
的selectedIndex
。所以,这是模板:
<form class="form-inline mt-3">
<div class="container-fluid">
<div class="row">
<div class="form-group col-12">
<label for="states" class="mr-3">State</label>
<select #s id="states" class="form-control" name="states" [ngModel]="selectedState"
(ngModelChange)="onStateChange(selectedState, $event, s)">
<option [ngValue]="null">All</option>
<option *ngFor="let state of states" [ngValue]="state">{{state.name}}</option>
</select>
</div>
</div>
</div>
</form>
和组件:
onStateChange(previousState: State, state: State, statesEl: HTMLSelectElement): void {
// If we're changing state from "All" to any, it's OK
if (previousState === null) {
this.selectedState = state;
return;
}
// Otherwise we want the user to confirm that change
if (confirm('Are you sure you want to select another state?')) {
this.selectedState = state;
} else {
statesEl.selectedIndex = this.states.indexOf(previousState) + 1;
}
}
+1
是必需的,因为 null
不在 this.states
之列,同时是 <select>
的第一个 <option>
。
我正在尝试实现非常简单的 <select>
行为:如果用户取消更改,则恢复到以前的值。实际上,我成功了,但是那花了我几个小时,而且我对实现仍然不满意,因为它不是那么明显和棘手。
所以,这是模板:
<select id="states" class="form-control" name="states" [ngModel]="selectedState"
(ngModelChange)="onStateChange(selectedState, $event)">
<option [ngValue]="null">All</option>
<option *ngFor="let state of states" [ngValue]="state">{{state.name}}</option>
</select>
和组件:
export class AppComponent {
selectedState: State = null;
states: State[] = [
{ name: 'Alabama', population: 100000 },
{ name: 'Alaska', population: 50000 }
];
onStateChange(previousState: State, state: State): void {
// If we're changing state from "All" to any, it's OK
if (previousState === null) {
this.selectedState = state;
return;
}
// Otherwise we want the user to confirm that change
if (confirm('Are you sure you want to select another state?')) {
this.selectedState = state;
} else {
// But instead of just `this.selectedState = previousState;`
// I need to proceed with below dirty hack.
// Step 1: Changing property value, which is bound to `[ngModel]`,
// to any, except for the current one, so `null` is OK
this.selectedState = null;
// Step 2: Reverting this property value to the previous one,
// which is, ridiculously, already set as the previous one,
// because we're reverting `this.selectedState`,
// while passing exactly the same `this.selectedState`
// to this method as a `previousState` parameter,
// so we're actually doing `this.selectedState = this.selectedState;`,
// but in not-so-obvious form.
// This works only kind of asynchronously,
// after call stack is clear.
setTimeout(() => {
this.selectedState = previousState;
}, 0);
}
}
}
我希望评论是不言自明的,至少我试着把它们写成这样。
正如我在评论中提到的,简单的 this.selectedState = previousState;
不起作用,并且省略了 setTimeout()
。我也试过这个,但没有成功:
this.selectedState = previousState;
this.changeDetectorRef.detectChanges();
我的解决方案也是基于 <select>
绑定到一个对象,而不是标量值。
演示: https://angular-hkaznb.stackblitz.io
软件包版本:
Angular: 6.0.0
看来我找到了更优雅的解决方案,它基于 <select>
的selectedIndex
。所以,这是模板:
<form class="form-inline mt-3">
<div class="container-fluid">
<div class="row">
<div class="form-group col-12">
<label for="states" class="mr-3">State</label>
<select #s id="states" class="form-control" name="states" [ngModel]="selectedState"
(ngModelChange)="onStateChange(selectedState, $event, s)">
<option [ngValue]="null">All</option>
<option *ngFor="let state of states" [ngValue]="state">{{state.name}}</option>
</select>
</div>
</div>
</div>
</form>
和组件:
onStateChange(previousState: State, state: State, statesEl: HTMLSelectElement): void {
// If we're changing state from "All" to any, it's OK
if (previousState === null) {
this.selectedState = state;
return;
}
// Otherwise we want the user to confirm that change
if (confirm('Are you sure you want to select another state?')) {
this.selectedState = state;
} else {
statesEl.selectedIndex = this.states.indexOf(previousState) + 1;
}
}
+1
是必需的,因为 null
不在 this.states
之列,同时是 <select>
的第一个 <option>
。