Angular 2 异步管道不会自动渲染/更新 Observable 数据 [英] Angular 2 async pipe not rendering/updating Observable data automatically
问题描述
我遇到了 Angular2 路由器和异步管道的问题.
我正在尝试呈现 RxJs Observable,但数据不会自动呈现.
必须单击要呈现数据的路线的链接.
这是根应用程序:
import {bootstrap} from 'angular2/platform/browser';从 'angular2/http' 导入 {HTTP_PROVIDERS};从'angular2/router'导入{ROUTER_PROVIDERS};从'./app.component.ts'导入{AppComponent};bootstrap(AppComponent, [HTTP_PROVIDERS, ROUTER_PROVIDERS]);
这是根组件:
import {Component} from 'angular2/core';从 'angular2/router' 导入 {RouteConfig, ROUTER_DIRECTIVES};从'./app.first-component.ts'导入{FirstComponent};从'./app.second-component.ts'导入{SecondComponent};从./app.services.ts"导入{AppService};@成分({选择器:'我的应用',提供者:[AppService,FirstComponent,SecondComponent],指令:[FirstComponent,SecondComponent,ROUTER_DIRECTIVES],模板:`<h1>Angular 2 App</h1><a [routerLink]="['First']">first-default</a><a [routerLink]="['Second']">second</a><路由器插座></路由器插座>`})@RouteConfig([{path: '/', name: 'First', 组件: FirstComponent, useAsDefault: true},{路径:'/second',名称:'Second',组件:SecondComponent}])导出类 AppComponent {}
这是第一个组件:
import {Component} from "angular2/core";从./app.services.ts"导入{AppService};导入rxjs/Rx";@成分({选择器:'我的第一个',模板:`<div><ul><li *ngFor="#s of appService.someObservable$ | async">一个字符串:{{ s }}
`})导出类 FirstComponent {构造函数(私有应用服务:应用服务){console.log('constructor', 'first');}}
最后是服务(数据所在的位置):
从angular2/core"导入{Injectable};从rxjs/Rx"导入{Observable};@Injectable()导出类 AppService {构造函数(){console.log('constructor', 'appService');this.constructSomeObservable();}someObservable$:Observable ;构造一些Observable(){this.someObservable$ = Observable.create(observer => {const eventSource = new EventSource('/interval-sse-observable');eventSource.onmessage = x =>观察者.next(JSON.parse(x.data));eventSource.onerror = x =>观察者.错误(console.log('事件源失败'));返回 () =>{eventSource.close();};}).从...开始([]).scan((acc, value) => acc.concat(value));}}
路由器或管道有什么问题?
查看 github 上的示例项目此处.
编辑:这是组件的修改版本:
import {Component} from "angular2/core";从./app.services.ts"导入{AppService};从rxjs/Rx"导入{Observable};@成分({选择器:'我的第一个',模板:`<div><ul><li *ngFor="#s of someObservable$ | async">一个字符串:{{ s }}
`})导出类 FirstComponent {someObservable$:Observable 模板中的数据未更新.是否与双向/单向绑定有关? 我认为 angular zone 不会修补从 eventSource.onmessage 发出的事件,不像例如setTimeout、SetInterval 或 xhr 请求 来自 angular2-polyfills.js 因此,您需要为 eventsource.onmessage 包装回调,例如: app.services.ts I am facing an issue with the Angular2 router and an async pipe. I am trying to render an RxJs Observable and the data does not render automatically. One has to click on the link for the route for the data to render. Here is the root app: Here is the root component: Here is First component: and finally the service (where the data resides): What I am getting wrong with the router or the pipe? See sample project on github here. edit: Here is the modified version of the component: The data is not updated in the template. Is it to do with two/one way binding? I think angular zone doesn't patch events emitted from eventSource.onmessage unlike e.g. setTimeout, SetInterval or xhr request From angular2-polyfills.js Therefore you need to wrap your callback for eventsource.onmessage something like: app.services.ts
这篇关于Angular 2 异步管道不会自动渲染/更新 Observable 数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!/***/function(module, export, __webpack_require__) {/* WEBPACK VAR 注入 */(function(global) {"use strict";__webpack_require__(1);var event_target_1 = __webpack_require__(2);vardefine_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 blocksMethods = ['alert', 'prompt', 'confirm'];var _global = typeof window == 'undefined' ?全球:窗口;patchTimer(_global, set, clear, '超时');patchTimer(_global, set, clear, 'Interval');patchTimer(_global, set, clear, '立即');patchTimer(_global, 'request', 'cancelMacroTask', 'AnimationFrame');patchTimer(_global, 'mozRequest', 'mozCancel', 'AnimationFrame');patchTimer(_global, 'webkitRequest', 'webkitCancel', 'AnimationFrame');for (var i = 0; i
import {Injectable, NgZone} from "angular2/core";//<=== 1) 不要忘记导入 NgZone 类从rxjs/Rx"导入{Observable};@Injectable()导出类 AppService {constructor(private zone: NgZone) {//<== 2) 不要忘记在构造函数中注入 zoneconsole.log('constructor', 'appService');this.constructSomeObservable();}someObservable$: 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));
}
}
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$;
}
}
/***/ 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;
}
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));
}
}