【问题标题】:Angular 2 async pipe not rendering/updating Observable data automaticallyAngular 2 异步管道不会自动渲染/更新 Observable 数据
【发布时间】:2016-08-20 08:35:04
【问题描述】:

我遇到了 Angular2 路由器和异步管道的问题。

我正在尝试渲染 RxJs Observable,但数据不会自动渲染。

必须单击要呈现数据的路由的链接。

这是根应用程序:

import {bootstrap}    from 'angular2/platform/browser';
import {HTTP_PROVIDERS} from 'angular2/http';
import {ROUTER_PROVIDERS} from 'angular2/router';
import {AppComponent} from './app.component.ts';

bootstrap(AppComponent, [HTTP_PROVIDERS, ROUTER_PROVIDERS]);

这是根组件:

import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
import {FirstComponent} from './app.first-component.ts';
import {SecondComponent} from './app.second-component.ts';
import {AppService} from "./app.services.ts";


@Component({
    selector: 'my-app',
    providers: [AppService, FirstComponent, SecondComponent],
    directives: [FirstComponent, SecondComponent, ROUTER_DIRECTIVES],
    template: `<h1>An Angular 2 App</h1>
               <a [routerLink]="['First']">first-default</a> 
               <a [routerLink]="['Second']">second</a> 
               <router-outlet></router-outlet>`
})
@RouteConfig([
    {path: '/', name: 'First', component: FirstComponent, useAsDefault: true},
    {path: '/second', name: 'Second', component: SecondComponent}
])
export class AppComponent {
}

这是第一个组件:

import {Component} from "angular2/core";
import {AppService} from "./app.services.ts";
import "rxjs/Rx";


@Component({
    selector: 'my-first',
    template: `
<div>
    <ul>
        <li *ngFor="#s of appService.someObservable$ | async">
           a string: {{ s }}
        </li>
    </ul>
 </div>`
})
export class FirstComponent {

    constructor(private appService:AppService) {
        console.log('constructor', 'first');
    }
}

最后是服务(数据所在的位置):

import {Injectable} from "angular2/core";
import {Observable} from "rxjs/Rx";

@Injectable()
export class AppService {

    constructor() {
        console.log('constructor', 'appService');
        this.constructSomeObservable();
    }

    someObservable$:Observable <string[]>;

    constructSomeObservable() {
        this.someObservable$ = Observable.create(observer => {
                const eventSource = new EventSource('/interval-sse-observable');
                eventSource.onmessage = x => observer.next(JSON.parse(x.data));
                eventSource.onerror = x => observer.error(console.log('EventSource failed'));
                return () => {
                    eventSource.close();
                };
            })
            .startWith([])
            .scan((acc, value) => acc.concat(value));
    }
}

路由器或管道出了什么问题?

在 github here 上查看示例项目。

edit:这是组件的修改版本:

import {Component} from "angular2/core";
import {AppService} from "./app.services.ts";
import {Observable} from "rxjs/Rx";


@Component({
    selector: 'my-first',
    template: `
<div>
    <ul>
        <li *ngFor="#s of someObservable$ | async">
           a string: {{ s }}
        </li>
    </ul>
 </div>`
})
export class FirstComponent {

    someObservable$:Observable <string[]>;

    constructor(private appService:AppService) {
        console.log('constructor', 'first');
        this.someObservable$ = appService.someObservable$;
    }
}

模板中的数据未更新。是否与双向/单向绑定有关?

【问题讨论】:

    标签: angular angular2-routing angular2-template angular2-directives


    【解决方案1】:

    我会在组件本身中引用 observable:

    @Component({
      selector: 'my-first',
      template: `
        <div>
          <ul>
            <li *ngFor="#s of someObservable$ | async">
               a string: {{ s }}
            </li>
          </ul>
       </div>`
    })
    export class FirstComponent {
      constructor(private appService:AppService) {
        console.log('constructor', 'first');
        this.someObservable$ = appService.someObservable;
      }
    }
    

    【讨论】:

    【解决方案2】:

    我认为角度区域不会修补从 eventSource.onmessage 发出的事件,不像例如setTimeout、SetInterval 或 xhr 请求

    来自 angular2-polyfills.js

    /***/ function(module, exports, __webpack_require__) {
    
        /* WEBPACK VAR INJECTION */(function(global) {"use strict";
        __webpack_require__(1);
        var event_target_1 = __webpack_require__(2);
        var define_property_1 = __webpack_require__(4);
        var register_element_1 = __webpack_require__(5);
        var property_descriptor_1 = __webpack_require__(6);
        var utils_1 = __webpack_require__(3);
        var set = 'set';
        var clear = 'clear';
        var blockingMethods = ['alert', 'prompt', 'confirm'];
        var _global = typeof window == 'undefined' ? global : window;
        patchTimer(_global, set, clear, 'Timeout');
        patchTimer(_global, set, clear, 'Interval');
        patchTimer(_global, set, clear, 'Immediate');
        patchTimer(_global, 'request', 'cancelMacroTask', 'AnimationFrame');
        patchTimer(_global, 'mozRequest', 'mozCancel', 'AnimationFrame');
        patchTimer(_global, 'webkitRequest', 'webkitCancel', 'AnimationFrame');
        for (var i = 0; i < blockingMethods.length; i++) {
            var name = blockingMethods[i];
            utils_1.patchMethod(_global, name, function (delegate, symbol, name) {
                return function (s, args) {
                    return Zone.current.run(delegate, _global, args, name);
                };
            });
        }
        event_target_1.eventTargetPatch(_global);
        property_descriptor_1.propertyDescriptorPatch(_global);
        utils_1.patchClass('MutationObserver');
        utils_1.patchClass('WebKitMutationObserver');
        utils_1.patchClass('FileReader');
        define_property_1.propertyPatch();
        register_element_1.registerElementPatch(_global);
        // Treat XMLHTTPRequest as a macrotask.
        patchXHR(_global);
        var XHR_TASK = utils_1.zoneSymbol('xhrTask');
        function patchXHR(window) {
            function findPendingTask(target) {
                var pendingTask = target[XHR_TASK];
                return pendingTask;
            }
    

    因此,您需要为 eventsource.onmessage 包装回调,例如:

    app.services.ts

    import {Injectable, NgZone} from "angular2/core"; // <=== 1) Don't forget to import the NgZone class
    import {Observable} from "rxjs/Rx";
    
    @Injectable()
    export class AppService {
    
      constructor(private zone: NgZone) { // <== 2) Don't forget also to inject zone in constructor
        console.log('constructor', 'appService');
        this.constructSomeObservable();
      }
    
      someObservable$: Observable<string[]>;
    
      constructSomeObservable() {
        this.someObservable$ = Observable.create(observer => {
          const eventSource = new EventSource('/interval-sse-observable');
          eventSource.onmessage = x => this.zone.run(() => observer.next(JSON.parse(x.data))); // <=== 3) Wrap onmessage event
          eventSource.onerror = x => observer.error(console.log('EventSource failed'));
          return () => {
            eventSource.close();
          };
        })
          .startWith([])
          .scan((acc, value) => acc.concat(value));
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-09
      • 1970-01-01
      • 2019-07-17
      • 2016-11-04
      • 2017-11-20
      • 2020-11-13
      相关资源
      最近更新 更多