angular - 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;
}
}
解决方案
发生这种情况的原因是您正在通过调用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);
}
}
推荐阅读
- api - 此错误的含义是什么:“客户端身份验证只能使用一种机制提供”
- swift - UITableView Swift 4中的多个部分
- c++ - 包装 std::vector
从 C++ 到 C 用于 Swift - r - R 函数中的错误。尝试在 intergerOneIndex 中选择少于一个元素
- python - R中的Collatz猜想
- facebook-graph-api - Facebook 的手动登录流程是否允许移动 webview 自动启动 Facebook 的本地应用程序?
- geotiff - GeoTrellis:为在 GeoTrellis 之外托管的云优化 GeoTIFF 创建属性存储
- ruby-on-rails - 安装 Poppler Gem 并在运行服务器时出现捆绑程序错误
- android - Socket.emit 不适用于向上和返回按钮_Android
- eslint - 将 ESLint 配置为在使用某些键定义对象时出错