角度4:更改模型后视图是否未更新?

时间:2018-06-27 10:44:16

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

我的应用中有两个component,即HeaderComponentTestComponent。在HeaderComponent中,有一个方法名称 setUserData()。 我从文件ansSubmit()中的 TestComponent的方法test.component.ts 调用此 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>

请建议我如何解决此问题。预先感谢。

5 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:2)

我相信您正在苦苦挣扎的原因是因为您似乎在尝试操纵数据的同级组件,而这些人都不是真正的数据所有者。 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'导入{Component,OnInit,Input};

@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的服务,以强制传输所有分数往返服务器,而无需更改组件中的代码行。它还将允许您交换模拟服务以进行测试,因此不需要为通过测试而播种本地存储(即,您的测试必须对要通过的组件的实现了解得更少,因此它们将在实施更改时不那么脆弱)

答案 2 :(得分:0)

我想问题是服务器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实例,而是在更新另一个{{1 }}实例,该实例将在控制台中打印日志。

请尝试此操作并告诉我结果。谢谢。

答案 3 :(得分:0)

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

组件数据:

@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是一个功能,可将其他组件中的数据介绍给您

答案 4 :(得分:0)

尝试实现对HeaderComponent的OnChanges

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

我建议您使用角度服务或@Output并在根目录中发出事件,并在标题中侦听它们。 请查看angular提供的基本反应类型。 OnChanges侦听器用于侦听超出角度的更改(例如库)。 您应该仅将此作为最后的选择!