首页 > 解决方案 > ngIf 后模型数据丢失

问题描述

https://github.com/jimshowalter/vocabutron/blob/master/src/app/settings/settings.component.html中,应用程序开始时仅显示设置按钮。点击按钮,按钮消失,取而代之的是设置编辑器。编辑设置并提交,您可以看到它被推送到设置服务。提交也会使组件消失,并带回设置按钮。但是第二次单击设置按钮时,设置丢失。控制台日志显示设置组件根本没有任何活动。它似乎已经死了。然而,为设置添加一个值并提交它,组件结果仍然存在(如控制台所示)。

为什么重新显示组件不使用现有数据填充编辑器?

import { Component, OnInit, isDevMode } from "@angular/core";
import { SettingsService } from "../settings.service";
import { Settings } from "../settings";

@Component({
  selector: "app-settings",
  templateUrl: "./settings.component.html",
  styleUrls: ["./settings.component.css"]
})
export class SettingsComponent implements OnInit {
  model: Settings = null;
  display: boolean = false;

  constructor(private settingsService: SettingsService) {
    if (isDevMode) {
      console.log("SettingsComponent.constructed");
    }
  }

  private updateSettings() {
    if (isDevMode) {
      console.log("SettingsComponent.updateSettings");
    }
    this.model = this.settingsService.get();
  }

  ngOnInit() {
    if (isDevMode) {
      console.log("SettingsComponent.ngOnInit");
    }
    this.settingsService.changedMessage.subscribe(changed =>
      this.updateSettings()
    );
  }

  onSubmit(): void {
    let result = this.settingsService.put(this.model);
    if (isDevMode) {
      console.log("SettingsComponent.onSubmit: " + JSON.stringify(result));
    }
    this.display = false;
  }
}

<div *ngIf=!display class="container">
  <button type="button" class="btn btn-success" (click)="display=true">Settings</button>
</div>
<div *ngIf=display class="container">
  <h2>Settings</h2>
  <form (ngSubmit)="onSubmit(); settingsForm.reset()" #settingsForm="ngForm">
    <div class="form-group">
      <input type="number" class="form-control" id="settings" [(ngModel)]="model.maxWords" required pattern="([1-9]+[0-9]*)+"
        name="settings" #settingsModel="ngModel">
    </div>
    <div [hidden]="settingsModel.valid || settingsModel.pristine" class="alert alert-danger">
      Max words is required and must be a number from 1-N.
    </div>
    <button type="submit" class="btn btn-success" [disabled]="!settingsForm.form.valid">Submit</button>
  </form>
</div>

export class Settings {
  maxWords: number = 3;
}

import { Injectable, isDevMode } from "@angular/core";
import { BehaviorSubject } from "rxjs";
import { Settings } from "./settings";

@Injectable({
  providedIn: "root"
})
export class SettingsService {
  changedMessageSource = new BehaviorSubject("changed");
  changedMessage = this.changedMessageSource.asObservable();

  private settings: Settings = new Settings();

  constructor() {
    if (isDevMode) {
      console.log("SettingsService constructed");
    }
  }

  get(): Settings {
    if (isDevMode) {
      console.log("SettingsService.get");
    }
    return this.settings;
  }

  changed() {
    if (isDevMode) {
      console.log("SettingsService.changed");
    }
    this.changedMessageSource.next("changed");
  }

  put(settings: Settings): Settings {
    this.settings = settings;
    this.changed();
    if (isDevMode) {
      console.log("SettingsService.put: " + JSON.stringify(this.settings));
    }
    return this.settings;
  }
}

标签: angularangular-ng-if

解决方案


发生这种情况的原因是您正在通过调用reset()表单提交处理程序来重置表单,但是由于表单只是被隐藏并使用 *ngIf 重新显示,因此没有更新模型的阶段。不会触发主题,因此不会调用更新。只需删除重置即可修复。

  <form (ngSubmit)="onSubmit();" #settingsForm="ngForm">

这种编码风格几乎没有问题,例如复杂的推理,如上所示,以及非性能变化检测,但我认为这些概念要留到另一天。目前,BehaviorSubject可以直接对对象发出更改。直接订阅它可以让我们一步获得新设置。

ngOnInit() {
   this.settingsService.settings$.subscribe(settings =>
     this.model = settings;
  );
}

export class SettingsService {
  private settings: Settings = new Settings();

  private settingsSource = new BehaviorSubject(this.settings);
  settings$ = this.settingsSource.asObservable();

  ...

  changed() {
    this.settingsSubject.next(this.settings);
   }
}

推荐阅读