通过使用Http,我们调用一个执行网络调用并返回http observable的方法:
getCustomer() {
return this.http.get('/someUrl').map(res => res.json());
}
Run Code Online (Sandbox Code Playgroud)
如果我们采用这个可观察的并添加多个订阅者:
let network$ = getCustomer();
let subscriber1 = network$.subscribe(...);
let subscriber2 = network$.subscribe(...);
Run Code Online (Sandbox Code Playgroud)
我们想要做的是确保这不会导致多个网络请求.
这可能看起来像是一个不寻常的场景,但实际上很常见:例如,如果调用者订阅了observable以显示错误消息,并使用异步管道将其传递给模板,那么我们已经有两个订阅者.
在RxJs 5中这样做的正确方法是什么?
也就是说,这似乎工作正常:
getCustomer() {
return this.http.get('/someUrl').map(res => res.json()).share();
}
Run Code Online (Sandbox Code Playgroud)
但这是在RxJs 5中这样做的惯用方式,还是我们应该做其他事情呢?
注意:根据Angular 5 new HttpClient,.map(res => res.json())所有示例中的部分现在都没用,因为现在默认采用JSON结果.
我试图在Angular中实现类似委托模式的东西.当用户点击a时nav-item,我想调用一个函数然后发出一个事件,而该事件又由一些其他组件监听事件来处理.
这是场景:我有一个Navigation组件:
import {Component, Output, EventEmitter} from 'angular2/core';
@Component({
// other properties left out for brevity
events : ['navchange'],
template:`
<div class="nav-item" (click)="selectedNavItem(1)"></div>
`
})
export class Navigation {
@Output() navchange: EventEmitter<number> = new EventEmitter();
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this.navchange.emit(item)
}
}
Run Code Online (Sandbox Code Playgroud)
这是观察组件:
export class ObservingComponent {
// How do I observe the event ?
// <----------Observe/Register Event ?-------->
public selectedNavItem(item: number) {
console.log('item index changed!');
}
}
Run Code Online (Sandbox Code Playgroud)
关键问题是,如何让观察组件观察相关事件?
event-delegation observable observer-pattern eventemitter angular
我创建了一个发出简单GET请求的服务:
private accountObservable = null;
constructor(private _http: Http) {
}
getAccount () {
// If we have account cached, use it instead
if (this.accountObservable === null) {
this.accountObservable = this._http.get('http://localhost/api/account')
.map(res => <Account> res.json().data)
.catch(this.handleError);
}
return this.accountObservable;
}
Run Code Online (Sandbox Code Playgroud)
我在我的bootstrap函数中添加了该服务以在全局范围内提供它(我希望为所有组件提供相同的实例):
provide(AccountService, { useClass: AccountService })
Run Code Online (Sandbox Code Playgroud)
问题是当我在不同的组件中调用此服务时,每次都会发出GET请求.因此,如果我将其添加到3个组件,即使我检查是否已存在可观察量,也会发出3个GET请求.
ngOnInit() {
this._accountService.getAccount().subscribe(
account => this.account = account,
error => this.errorMessage = <any>error
);
}
Run Code Online (Sandbox Code Playgroud)
如何防止多次发出GET请求?
我来自Angular1,就像链接承诺一样,我希望有类似的行为.
我在某类中有一个方法: -
{.........
doLogin (username, password) {
.......
.......
return this.http.get(api).subscribe(
data => {.....}, //enters here
err => {.....}
}
Run Code Online (Sandbox Code Playgroud)
然后我称这种方法: -
someclass.doLogin(username, password).subscribe(
data => { }, //Not getting called
err => { }
}
Run Code Online (Sandbox Code Playgroud)
正如我上面提到的对上述代码的评论,订阅不会在调用者类中被调用.
有关如何做到这一点的任何建议?
目前我正在加载一个 JSON 文件,如下所示:
翻译服务.ts
@Injectable()
export class TranslationService {
private _messages = [];
constructor(private _http: Http) {
var observable = this._http.get("/app/i18n/localizable.it.strings").map((res: Response) => res.json());
observable.subscribe(res => {
this._messages = res;
});
}
getTranslationByKey(key: string, args?: any[]) {
return this._messages[key];
}
}
Run Code Online (Sandbox Code Playgroud)
localizable.it.strings
{
"home.nav.calendar": "Calendar",
...
}
Run Code Online (Sandbox Code Playgroud)
我TranslationService被注入我的HomeComponent但问题是当我尝试通过管道读取这些值时,它们仍然需要在页面呈现时加载。
翻译.pipe.ts
@Pipe({name: 'translate'})
export class TranslatePipe implements PipeTransform {
constructor(private _translation: TranslationService) {}
transform(value: string, args: string[]) : any {
return this._translation.getTranslationByKey(value);
}
}
Run Code Online (Sandbox Code Playgroud)
知道如何在加载任何页面之前从 JSON 文件加载所有值吗?
我有一个Angular 2应用程序,它调用JSON API将数据加载到嵌套的HTML列表中(<ol>).本质上是动态生成的树视图.由于API中的数据集最终会变得非常大,当用户打开分支时,树会逐渐填充(用户打开分支,使用已打开的节点的id调用API,API返回JSON对于节点的直接子节点的馈送,Angular将返回的JSON绑定到一些新的HTML <li>元素,并且树展开以显示新的分支).
你可以在这个Plunkr中看到它的实际效果.它使用递归指令并且运行良好. 目前,因为我无法打开公共请求的实际API,它只是调用静态JSON提要,因此每个节点的返回数据只是重复,但希望你能得到这个想法.
我现在要克服的问题是在分支关闭然后重新打开时防止无关的HTTP调用.读完HTTP客户端文档后,我希望这就像修改订阅数据服务的方法一样简单,将方法链接.distinctUntilChanged()到app/content-list.component.ts文件,如下所示:
getContentNodes() {
this._contentService.getContentNodes(this._startNodeId)
.distinctUntilChanged()
.subscribe(
contentNodes => this.contentNodes = contentNodes,
error => this.errorMessage = <any>error
);
}
Run Code Online (Sandbox Code Playgroud)
但是,当我打开浏览器网络检查器时,每次重新打开相同的树分支时,它仍然会调用API.
谁能建议如何解决这个问题?
非常感谢.
编辑:
我正试图在下面实施@Thierry Templier的答案; 缓存API返回的数据.所以内容服务现在是:
import {Injectable} from 'angular2/core';
import {Http, Response} from 'angular2/http';
import {Headers, RequestOptions} from 'angular2/http';
import {ContentNode} from './content-node';
import {Observable} from 'rxjs/Observable';
@Injectable()
export class ContentService {
constructor (private http: Http) {}
private _contentNodesUrl = 'app/content.json'; …Run Code Online (Sandbox Code Playgroud) I have a shared service (starting from this suggestion) that cache and returns some data after first http request:
export class SharedService {
constructor(private http:Http) {
}
getData() {
if (this.cachedData) {
return Observable.of(this.cachedData);
} else {
return this.http.get(...)
.map(res => res.json())
.do((data) => {
this.cachedData = data;
});
}
}
}
Run Code Online (Sandbox Code Playgroud)
My problem is that I have some directives and components inside the same template that are all initialized at the same time and each one call simultaneously (inside …
angular ×7
rxjs ×2
caching ×1
concurrency ×1
eventemitter ×1
http ×1
javascript ×1
json ×1
observable ×1
rxjs5 ×1
service ×1
typescript ×1