Угловой <select>Привязать к объекту Подтвердить изменение или возврат к предыдущему значению - PullRequest
0 голосов
/ 06 июля 2018

Я пытаюсь добиться довольно простого поведения <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

Варианты комплектации:

Угловой: 6.0.0

1 Ответ

0 голосов
/ 09 июля 2018

Похоже, я нашел более элегантное решение, оно основано на этом ответе . Идея состоит в том, чтобы манипулировать <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>.

Демонстрация: https://angular -rwnksz.stackblitz.io

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...