【问题标题】:Angular 4: View is not updating after model change?Angular 4:模型更改后视图没有更新?
【发布时间】:2018-06-27 10:44:16
【问题描述】:

我的应用中有两个component,即:HeaderComponentTestComponent。在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>

请建议我如何解决此问题。提前致谢。

【问题讨论】:

  • 不同的组件?
  • 是的,我从不同的组件调用此方法。通过使用:this.headerComponent.getUserData(this.userData['score']);
  • 你可以在stackblitz.com中添加一些代码并分享它

标签: angular model angularjs-scope angular2-template angular2-directives


【解决方案1】:

我相信您苦苦挣扎的原因是因为您似乎有兄弟组件试图操纵数据,而其中任何一个都不是数据的真正所有者。 Angular 试图强制执行Unidirectional Data Flow,这仅仅意味着数据从父级流向子级,而不是从子级流向父级。解决您的问题的最简单方法是让“拥有” 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' 导入 { Component, OnInit, Output, 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 的服务,以强制传输所有分数在不更改组件中的一行代码的情况下往返服务器。它还允许您交换模拟服务以进行测试,因此无需为本地存储播种即可通过测试(即 - 您的测试必须较少了解要通过的组件的实现,因此它们将在实施更改时不会那么脆弱)

【讨论】:

    【解决方案2】:

    您将 HeaderComponent 添加为提供程序,因此它可能正在创建该组件的新实例。如果您有一个现有的 HeaderComponent,您将需要获取该实例,因此使用服务将有助于保持对组件实例的引用。

    最好将分数完全移至服务并使用主题来更新其值。查看他们的文档:https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service。实际上,该文档中列出的任何策略都应该对您的情况有用。

    【讨论】:

    • 我同意将功能转移到服务中。另一种解决方案是将功能移动到父组件并利用事件@Output 让渲染引擎正确检测更改。
    【解决方案3】:

    由于您试图从一个组件中获取信息并在另一个组件中显示,您应该使用事件。

    组件数据:

    @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 是一个向您介绍来自其他组件的数据的函数

    【讨论】:

    • 这不是父子组件。
    • 所以请提供更多信息......不清楚您要做什么以及如何做。
    • 嗨@dAxx 我已经更新了我的问题,看看并做出相应的回应。
    • 嗨@dAxx_ this.userDataEvent.emit(this.score); 时它没有发出 setUserData();调用。
    【解决方案4】:

    尝试对 HeaderComponent 实现 OnChanges

    export class MyComponent implements OnInit, OnChanges {
     ngOnChanges(changes: SimpleChanges): void {
       // do your action
     }
    }
    

    我建议您使用 Angular 服务或 @Output 并在根中发出事件并在标头中监听它们。 请查看 Angular 提供的基本反应类型。 OnChanges 侦听器用于侦听在角度之外完成的更改(如库)。 您应该仅将其用作最后的手段!

    【讨论】:

    • 我尝试使用 ngOnChanges() 但它不起作用。而且我不需要父子组件,所以我不想实现父子组件。两者都是不同的组件。
    • 如果它们是不同的组件,您可以使用角度服务,将其注入您的类并使用它。这简化了很多事情。在服务中有一个公共数据,并在组件中使用它来渲染。甚至适用于不相关的组件。
    【解决方案5】:

    我猜问题是有多个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 实例在控制台打印日志。

    请试试这个并告诉我结果。谢谢。

    【讨论】:

    • 我也试过了,但它没有更新视图上的旧值。
    • 哦,您是否也尝试在this._ngZone.run回调函数 中将新值设置为旧值?
    • 是的,我试过this._ngZone.run,但它也没有更新视图上的模型。
    • 那么,我需要更多信息来解决它。你能分享更多细节吗?
    • 嗨@Hyuck Kang 我已经更新了我的问题,请查看并做出相应的回应。
    猜你喜欢
    • 1970-01-01
    • 2016-08-23
    • 2017-09-07
    • 2019-02-28
    • 1970-01-01
    • 2016-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多