数据更新后 Angular2 视图不会改变 [英] Angular2 View Not Changing After Data Is Updated
问题描述
我正在尝试在 websocket 事件返回更新数据后更新我的视图.
我向我的应用程序注入了一个服务,并在该服务上调用了 getData() 方法.此方法向我的 NodeJS 服务器发出 socket.io 事件,该服务器又执行外部 api 调用并解析一些数据.然后,NodeJS 服务器使用我在服务中侦听的新数据发出成功事件.当成功事件返回时,我会更新我的视图中引用的服务的属性.
但是,无论我尝试什么,一旦属性更新,我都无法显示数据.
我已经搜索了几天,我发现的所有博客文章都说这种变化应该是无缝的,或者我需要以某种方式合并 zone.js,或者使用表单尝试相同的逻辑(但是我试图无需用户交互即可执行此操作).似乎没有什么对我有用,我有点沮丧.
例如:
假设我收到一个字符串数组,我想用它来创建一个未排序的列表.
app.ts
import {Component, View, bootstrap, NgFor} from 'angular2/angular2';从 'js/services/MyService' 导入 {MyService};//注释部分@零件({选择器:'我的应用',视图注入器:[MyService]})@看法({templateUrl: 'templates/my-app.tpl.html',指令:[NgFor]})类我的组件{mySvc:我的服务;构造函数(mySvc:MyService){this.mySvc = mySvc;this.mySvc.getData();}}引导程序(我的组件,[我的服务]);
MyService.ts
let socket = io();导出类 MyService {someList:Array;构造函数(){this.initListeners();}获取数据(){socket.emit('myevent', {value: 'someValue'});}initListeners() {socket.on('success', (data) => {self.someList = 数据;});}}
my-app.tpl.html
<h2>我的列表</h2><ul><li *ng-for="#item of mySvc.myList">项目:{{item}}</li>
有趣的是,我发现如果我在我的组件中加入一个超时来更新一些我在视图上设置的任意属性,然后 someList 属性从成功回调更新,那么两个属性值都会同时正确更新.
例如:
新 app.ts
import {Component, View, bootstrap, NgFor} from 'angular2/angular2';从 'js/services/MyService' 导入 {MyService};//注释部分@零件({选择器:'我的应用',视图注入器:[MyService]})@看法({templateUrl: 'templates/my-app.tpl.html',指令:[NgFor]})类我的组件{mySvc:我的服务;数量:数量;构造函数(mySvc:MyService){this.mySvc = mySvc;this.mySvc.getData();setTimeout(() => this.updateNum(), 5000);}更新数(){this.num = 123456;}}引导程序(我的组件,[我的服务]);
新建 my-app.tpl.html
<h2>我的列表{{num}}</h2><ul><li *ng-for="#item of mySvc.myList">项目:{{item}}</li>
那么我应该如何在不更新其他属性的情况下让 angular2 识别数据在 'success' 事件之后发生了变化?
我在使用 NgFor 指令时是否遗漏了什么?
所以我终于找到了我喜欢的解决方案.按照这篇文章中的答案如何在 google 事件侦听器触发后更改 angular2 后更新视图 我在 zone.run() 中更新了 myList,现在我的数据在我的视图中按预期更新.
MyService.ts
///<参考路径="../../../typings/tsd.d.ts"/>//进口从'angular2/angular2'导入{NgZone};从 'js/services/SocketService' 导入 {SocketService};导出类 MyService {区域:NgZone;myList:Array= [];socketSvc:SocketService;构造函数(){this.zone = new NgZone({enableLongStackTrace: false});this.socketSvc = 新的 SocketService();this.initListeners();}获取数据(){this.socketSvc.emit('事件');}initListeners() {this.socketSvc.socket.on('success', (data) => {this.zone.run(() => {this.myList = 数据;console.log('更新列表:', this.myList);});});}}
I am trying to update my view after a websocket event returns updated data.
I injected a service into my app and call getData() method on the service. This method emits a socket.io event to my NodeJS server which in turn performs an external api call and parses some data. The NodeJS server then emits a success event with the new data that I listen for in my service. When the success event is returned I then update my property on the service that is referenced in my view.
However no matter what I try I cannot get the data to show once the property is updated.
I have searched for a few days now and all I find are blog posts that say this change should be seamless, or that I need to incorporate zone.js somehow, or to try the same logic using forms (however im trying to do this without user interaction). Nothing seems to work for me and I am getting a bit frustrated.
For example:
Lets say I receive an array of strings that I want to create an unsorted list with.
app.ts
import {Component, View, bootstrap, NgFor} from 'angular2/angular2';
import {MyService} from 'js/services/MyService';
// Annotation section
@Component({
selector: 'my-app',
viewInjector: [MyService]
})
@View({
templateUrl: 'templates/my-app.tpl.html',
directives: [NgFor]
})
class MyComponent {
mySvc:MyService;
constructor(mySvc:MyService) {
this.mySvc = mySvc;
this.mySvc.getData();
}
}
bootstrap(MyComponent, [MyService]);
MyService.ts
let socket = io();
export class MyService {
someList:Array<string>;
constructor() {
this.initListeners();
}
getData() {
socket.emit('myevent', {value: 'someValue'});
}
initListeners() {
socket.on('success', (data) => {
self.someList = data;
});
}
}
my-app.tpl.html
<div>
<h2>My List</h2>
<ul>
<li *ng-for="#item of mySvc.myList">Item: {{item}}</li>
</ul>
</div>
Interesting enough, I have found that If I incorporate a timeout within my component that updates some arbitrary property that I set on the view after the someList property is updated from the success callback then both property values are updated correctly at the same time.
For instance:
new app.ts
import {Component, View, bootstrap, NgFor} from 'angular2/angular2';
import {MyService} from 'js/services/MyService';
// Annotation section
@Component({
selector: 'my-app',
viewInjector: [MyService]
})
@View({
templateUrl: 'templates/my-app.tpl.html',
directives: [NgFor]
})
class MyComponent {
mySvc:MyService;
num:Number;
constructor(mySvc:MyService) {
this.mySvc = mySvc;
this.mySvc.getData();
setTimeout(() => this.updateNum(), 5000);
}
updateNum() {
this.num = 123456;
}
}
bootstrap(MyComponent, [MyService]);
new my-app.tpl.html
<div>
<h2>My List {{num}}</h2>
<ul>
<li *ng-for="#item of mySvc.myList">Item: {{item}}</li>
</ul>
</div>
So how should I go about getting angular2 to recognize that the data has changed after the 'success' event without updating some other property?
Is there something I am missing with the use of the NgFor directive?
So I finally found a solution that I like. Following the answer in this post How to update view after change in angular2 after google event listener fired I updated myList within zone.run() and now my data is updated in my view like expected.
MyService.ts
/// <reference path="../../../typings/tsd.d.ts" />
// Import
import {NgZone} from 'angular2/angular2';
import {SocketService} from 'js/services/SocketService';
export class MyService {
zone:NgZone;
myList:Array<string> = [];
socketSvc:SocketService;
constructor() {
this.zone = new NgZone({enableLongStackTrace: false});
this.socketSvc = new SocketService();
this.initListeners();
}
getData() {
this.socketSvc.emit('event');
}
initListeners() {
this.socketSvc.socket.on('success', (data) => {
this.zone.run(() => {
this.myList = data;
console.log('Updated List: ', this.myList);
});
});
}
}
这篇关于数据更新后 Angular2 视图不会改变的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!