Angular 4:模型更改后视图没有更新?
Angular 4: View is not updating after model change?
我的应用程序中有两个 component
,即:HeaderComponent
和 TestComponent
。在HeaderComponent
中,有一个方法名setUserData()。
我从文件 test.component.ts
.
中的 TestComponent 的方法 ansSubmit()
调用此 setUserDate()
现在 setUserDate()
正在调用并且值正在进入 setUserDate()
方法。
问题是:当setUserDate()
调用时,我将分数值设置为this.userData.score,并且this.userData.score 值在视图中具有约束力 ( HTML ) 但来自
TestComponent 的方法 ansSubmit() 不会在视图上更新 但该值存在于 ts
文件中(我在控制台中打印)。
代码如下:
test.component.ts:
import { HeaderComponent } from '../../components/header/header.component';
@Component({
selector: 'test-page',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css'],
providers: [HeaderComponent]
})
export class TestComponent implements OnInit {
private userData: any = {};
constructor(private _router: Router, private headerComponent: HeaderComponent) { }
ansSubmit() {
const logged_in_user = new LocalStorage(environment.localStorageKeys.ADMIN);
this.userData = logged_in_user.value;
this.userData['score'] = parseInt(this.userData.score) + 54321
this.headerComponent.getUserData(this.userData['score']); // Calling HeaderComponent's method value is 54321.
}
}
test.component.html:
<div class="col-2">
<button (click)="ansSubmit()" >
<div>Submit Answer</div>
</button>
</div>
header.component.ts:
import {
Component, OnInit, ChangeDetectorRef, NgZone, ApplicationRef, ChangeDetectionStrategy
} from '@angular/core';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css'],
})
export class HeaderComponent implements OnInit {
public userData : any = {
score:2000,
};
getUserData(score) { // score= 54321 ( value is coming )
this.userData.score = score ;
console.log(this.userData.score); // in this.userData.score = 54321 ( Value is assigning )
}
}
}
header.component.html:
<span class="topbar-details">
Scrore : {{userData.score }} // actual problem is here, Its not updating value. Its only showing 2000.
</span>
请建议我如何解决此问题。提前致谢。
我猜问题出在几个 HeaderComponent
多于一个。可能是你的注射引起的
constructor(private _router: Router, private headerComponent: HeaderComponent) { }
.
尝试下面的这段代码找出导致问题的原因。
header.component.ts
import {
Component, OnInit, ChangeDetectorRef, NgZone, ApplicationRef, ChangeDetectionStrategy
} from '@angular/core';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css'],
})
export class HeaderComponent implements OnInit {
static count:number = 0;
public id:number = 0;
public userData : any = {
score:2000,
};
constructor(){
HeaderComponent.count++;
this.id = HeaderComponent.count
}
getUserData(score) { // score= 54321 ( value is coming )
this.userData.score = score ;
console.log(`${this._id} : ${this.userData.score}`); // in this.userData.score = 54321 ( Value is assigning )
}
}
}
header.component.html
<span>id : {{id}}</span>
<span class="topbar-details">
Scrore : {{userData.score }} // actual problem is here, Its not updating value. Its only showing 2000.
</span>
如果视图中的 id 和控制台中的 id 不同,则表示您没有更新 HeaderComponent
实例在视图中还有另一个 HeaderComponent
实例,它在控制台中打印日志。
请试试这个并告诉我结果。谢谢。
由于您正试图从一个组件获取信息并在另一个组件中显示,因此您应该使用事件。
组件数据:
@Output() userDataEvent = new EventEmitter<any>();
----
getUserData(score?){
this.score=score?score:this.userData.score;
console.log("getUserData called :"+this.score);
this.userDataEvent.emit(this.score);
}
显示组件:
<your-component (userDataEvent)='setUserData($event)'></your-component>
然后,setUserData
是一个向您介绍来自其他组件的数据的函数
您正在添加 HeaderComponent 作为提供者,因此它可能正在创建组件的新实例。如果您有一个现有的 HeaderComponent,您将需要获取该实例,因此使用服务将有助于保持对组件实例的引用。
最好将分数完全移动到服务中,并使用 Subject 来更新其值。查看他们的文档:https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service。实际上,该文档中列出的任何策略都应该对您的情况有用。
尝试对 HeaderComponent 实施 OnChanges
export class MyComponent implements OnInit, OnChanges {
ngOnChanges(changes: SimpleChanges): void {
// do your action
}
}
我建议您使用 angular 服务或@Output 并在根目录中发出事件并在 header 中收听它们。
请查看 angular 提供的基本反应类型。
OnChanges 侦听器用于侦听在 angular 之外(如图书馆)所做的更改。
您应该仅将其用作最后的手段!
我相信你挣扎的原因是因为你似乎有兄弟组件试图操纵数据,其中没有一个是真正的数据所有者。 Angular 试图强制执行 Unidirectional Data Flow,这仅仅意味着数据从父流向子流,而不是从子流向父流。解决问题的最简单方法是让父组件 "owns" userData 和子组件绑定到数据以显示它并发出事件来操作它。
以您的场景为例:
app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
public userData: any = {
score: 2000
};
updateScore(score: number): void {
this.userData.score += score;
}
}
app.component.html
<app-header [score]="userData.score"></app-header>
<app-test (onScoreChange)="updateScore($event)"></app-test>
header.component.ts
从“@angular/core”导入{组件、OnInit、输入};
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
@Input('score') score: number;
constructor() { }
ngOnInit() {
}
}
header.component.html
<span class="topbar-details">
Scrore : {{score}}
</span>
test.component.ts
从“@angular/core”导入{组件、OnInit、输出、EventEmitter};
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {
@Output('onScoreChange') onScoreChange = new EventEmitter<number>();
constructor() { }
ngOnInit() {
}
ansSubmit() {
this.onScoreChange.emit(54321);
}
}
test.component.html
<div class="col-2">
<button (click)="ansSubmit()" >
<div>Submit Answer</div>
</button>
</div>
注意:至于从本地存储加载用户信息,我会使用服务来处理。加载用户数据的位置和方式并不是显示和操作数据的组件真正关心的问题。将该逻辑移动到具有适当接口的服务(如果数据可能来自远程位置,则可能返回可观察对象)将允许您无缝地将基于本地存储的服务换成基于 HTTP 的服务,以强制传输所有分数to/from 无需更改组件中一行代码的服务器。它还允许您交换模拟服务以进行测试,因此不需要为本地存储播种就可以通过测试(即-您的测试必须了解较少的组件实现才能通过,因此它们将在实现更改时不会那么脆弱)
我的应用程序中有两个 component
,即:HeaderComponent
和 TestComponent
。在HeaderComponent
中,有一个方法名setUserData()。
我从文件 test.component.ts
.
ansSubmit()
调用此 setUserDate()
现在 setUserDate()
正在调用并且值正在进入 setUserDate()
方法。
问题是:当setUserDate()
调用时,我将分数值设置为this.userData.score,并且this.userData.score 值在视图中具有约束力 ( HTML ) 但来自
TestComponent 的方法 ansSubmit() 不会在视图上更新 但该值存在于 ts
文件中(我在控制台中打印)。
代码如下:
test.component.ts:
import { HeaderComponent } from '../../components/header/header.component';
@Component({
selector: 'test-page',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css'],
providers: [HeaderComponent]
})
export class TestComponent implements OnInit {
private userData: any = {};
constructor(private _router: Router, private headerComponent: HeaderComponent) { }
ansSubmit() {
const logged_in_user = new LocalStorage(environment.localStorageKeys.ADMIN);
this.userData = logged_in_user.value;
this.userData['score'] = parseInt(this.userData.score) + 54321
this.headerComponent.getUserData(this.userData['score']); // Calling HeaderComponent's method value is 54321.
}
}
test.component.html:
<div class="col-2">
<button (click)="ansSubmit()" >
<div>Submit Answer</div>
</button>
</div>
header.component.ts:
import {
Component, OnInit, ChangeDetectorRef, NgZone, ApplicationRef, ChangeDetectionStrategy
} from '@angular/core';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css'],
})
export class HeaderComponent implements OnInit {
public userData : any = {
score:2000,
};
getUserData(score) { // score= 54321 ( value is coming )
this.userData.score = score ;
console.log(this.userData.score); // in this.userData.score = 54321 ( Value is assigning )
}
}
}
header.component.html:
<span class="topbar-details">
Scrore : {{userData.score }} // actual problem is here, Its not updating value. Its only showing 2000.
</span>
请建议我如何解决此问题。提前致谢。
我猜问题出在几个 HeaderComponent
多于一个。可能是你的注射引起的
constructor(private _router: Router, private headerComponent: HeaderComponent) { }
.
尝试下面的这段代码找出导致问题的原因。
header.component.ts
import {
Component, OnInit, ChangeDetectorRef, NgZone, ApplicationRef, ChangeDetectionStrategy
} from '@angular/core';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css'],
})
export class HeaderComponent implements OnInit {
static count:number = 0;
public id:number = 0;
public userData : any = {
score:2000,
};
constructor(){
HeaderComponent.count++;
this.id = HeaderComponent.count
}
getUserData(score) { // score= 54321 ( value is coming )
this.userData.score = score ;
console.log(`${this._id} : ${this.userData.score}`); // in this.userData.score = 54321 ( Value is assigning )
}
}
}
header.component.html
<span>id : {{id}}</span>
<span class="topbar-details">
Scrore : {{userData.score }} // actual problem is here, Its not updating value. Its only showing 2000.
</span>
如果视图中的 id 和控制台中的 id 不同,则表示您没有更新 HeaderComponent
实例在视图中还有另一个 HeaderComponent
实例,它在控制台中打印日志。
请试试这个并告诉我结果。谢谢。
由于您正试图从一个组件获取信息并在另一个组件中显示,因此您应该使用事件。
组件数据:
@Output() userDataEvent = new EventEmitter<any>();
----
getUserData(score?){
this.score=score?score:this.userData.score;
console.log("getUserData called :"+this.score);
this.userDataEvent.emit(this.score);
}
显示组件:
<your-component (userDataEvent)='setUserData($event)'></your-component>
然后,setUserData
是一个向您介绍来自其他组件的数据的函数
您正在添加 HeaderComponent 作为提供者,因此它可能正在创建组件的新实例。如果您有一个现有的 HeaderComponent,您将需要获取该实例,因此使用服务将有助于保持对组件实例的引用。
最好将分数完全移动到服务中,并使用 Subject 来更新其值。查看他们的文档:https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service。实际上,该文档中列出的任何策略都应该对您的情况有用。
尝试对 HeaderComponent 实施 OnChanges
export class MyComponent implements OnInit, OnChanges {
ngOnChanges(changes: SimpleChanges): void {
// do your action
}
}
我建议您使用 angular 服务或@Output 并在根目录中发出事件并在 header 中收听它们。 请查看 angular 提供的基本反应类型。 OnChanges 侦听器用于侦听在 angular 之外(如图书馆)所做的更改。 您应该仅将其用作最后的手段!
我相信你挣扎的原因是因为你似乎有兄弟组件试图操纵数据,其中没有一个是真正的数据所有者。 Angular 试图强制执行 Unidirectional Data Flow,这仅仅意味着数据从父流向子流,而不是从子流向父流。解决问题的最简单方法是让父组件 "owns" userData 和子组件绑定到数据以显示它并发出事件来操作它。
以您的场景为例:
app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
public userData: any = {
score: 2000
};
updateScore(score: number): void {
this.userData.score += score;
}
}
app.component.html
<app-header [score]="userData.score"></app-header>
<app-test (onScoreChange)="updateScore($event)"></app-test>
header.component.ts
从“@angular/core”导入{组件、OnInit、输入};
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
@Input('score') score: number;
constructor() { }
ngOnInit() {
}
}
header.component.html
<span class="topbar-details">
Scrore : {{score}}
</span>
test.component.ts
从“@angular/core”导入{组件、OnInit、输出、EventEmitter};
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {
@Output('onScoreChange') onScoreChange = new EventEmitter<number>();
constructor() { }
ngOnInit() {
}
ansSubmit() {
this.onScoreChange.emit(54321);
}
}
test.component.html
<div class="col-2">
<button (click)="ansSubmit()" >
<div>Submit Answer</div>
</button>
</div>
注意:至于从本地存储加载用户信息,我会使用服务来处理。加载用户数据的位置和方式并不是显示和操作数据的组件真正关心的问题。将该逻辑移动到具有适当接口的服务(如果数据可能来自远程位置,则可能返回可观察对象)将允许您无缝地将基于本地存储的服务换成基于 HTTP 的服务,以强制传输所有分数to/from 无需更改组件中一行代码的服务器。它还允许您交换模拟服务以进行测试,因此不需要为本地存储播种就可以通过测试(即-您的测试必须了解较少的组件实现才能通过,因此它们将在实现更改时不会那么脆弱)