数据更新后Angular2视图不更改

Joh*_*ort 29 websocket angular

我试图在websocket事件返回更新数据后更新我的视图.

我将一个服务注入到我的应用程序中并在服务上调用getData()方法.此方法向我的NodeJS服务器发出一个socket.io事件,该事件又执行外部api调用并解析一些数据.然后NodeJS服务器发出一个成功事件,其中包含我在我的服务中监听的新数据.返回成功事件后,我会在我的视图中引用的服务上更新我的属性.

但无论我尝试什么,一旦属性更新,我都无法获取数据.

我已经搜索了几天,我发现的所有内容都是博客文章,说这个变化应该是无缝的,或者我需要以某种方式合并zone.js,或者尝试使用表单相同的逻辑(但是我试图这样做而没有用户互动).似乎没有什么对我有用,我有点沮丧.

例如:

假设我收到一个字符串数组,我想创建一个未排序的列表.

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]);
Run Code Online (Sandbox Code Playgroud)

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;
        });
    }
 }
Run Code Online (Sandbox Code Playgroud)

我-app.tpl.html

<div>
    <h2>My List</h2>
    <ul>
        <li *ng-for="#item of mySvc.myList">Item: {{item}}</li>
    </ul>
</div>
Run Code Online (Sandbox Code Playgroud)

有趣的是,我发现如果我在我的组件中加入了一个超时,它会更新我在视图上设置的一些任意属性,从成功回调更新someList属性后,两个属性值会同时正确更新.

例如:

新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]);
Run Code Online (Sandbox Code Playgroud)

新的my-app.tpl.html

<div>
    <h2>My List {{num}}</h2>
    <ul>
        <li *ng-for="#item of mySvc.myList">Item: {{item}}</li>
    </ul>
</div>
Run Code Online (Sandbox Code Playgroud)

那么我应该如何在没有更新其他属性的情况下让angular2识别出数据在"成功"事件后发生了变化?

使用NgFor指令有什么我想念的吗?

Joh*_*ort 35

所以我终于找到了一个我喜欢的解决方案.按照这篇文章中的答案如何在google事件监听器触发后更改angular2后更新视图我在zone.run()中更新了myList,现在我的数据在我的视图中更新,如预期的那样.

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);
            });
        });
    }
 }
Run Code Online (Sandbox Code Playgroud)


小智 5

只需将socket.io初始化移动到Service构造函数即可.
看看这个例子:

import {Injectable} from 'angular2/core';  
@Injectable()
export class SocketService {
    socket:SocketIOClient.Socket;

    constructor(){
        this.socket = io.connect("localhost:8000");
    }
    public getSocket():SocketIOClient.Socket{
        return this.socket;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,只要将此服务注入组件并使用套接字,您的视图就会自动更新.但是如果你把它放在像你这样的全局范围内,你将不得不与某些东西进行交互以强制视图更新.
以下是使用此服务的示例组件:

export class PostsComponent {
    socket: SocketIOClient.Socket;
    posts: Array<Post> = [];

    constructor(private _socketService:SocketService){
        this.socket.on('new-post', data => {
            this.posts.push(new Post(data.id, data.text));
        });  
}  
Run Code Online (Sandbox Code Playgroud)