2016-11-08 188 views
0

参考Global Events in Angular 2我试图实现一个购物车服务,当一个新项目被添加到购物车时发出一个事件。我订阅的另一个组件调用导航栏此服务事件(这不是车孩子),我显示我的购物车项目等数Angular2服务发射器订阅失败

我的购物车服务:

export class CartService { 
    public itemAdded$: EventEmitter<any>; 
    ... 

    constructor(private http: Http){ 

     this.itemAdded$ = new EventEmitter(); 
     this.cart=[]; 
    } 

    addToCart(id: any): any { 

     this.itemAdded$.emit(id); 

     return this.http.get( this.myUrl + 'add' + '/' + id + '/', { withCredentials:true}) 
     .toPromise() 
     .then(response => response.json()) 

    } 
    ... 
    ... 
} 

我的导航栏组件:

@Component({ 
directives:[ROUTER_DIRECTIVES, Cart], 
providers:[CartService], 

}) 
export class Navbar implements OnInit{ 

    ... 
    totalCost: any; 
    cartItemCount : any; 
    addedItem: any; 

    constructor(private cartService: CartService){ 

     this.cartService.itemAdded$.subscribe((id: any) => { 
      alert(id); 
      this.onItemAdded(id); 
      this.fetchCartElements(); 
     }); 
    } 

    private onItemAdded(item: any): void { 
     // do something with added item 
     this.addedItem = item; 
    } 
... 
... 
} 

但是,每当我添加一个项目,什么也没有发生在导航栏即alert(id)onItemAdded()使cartItemCount等可以得到自动更新不会自动调用。

什么问题?

+2

你在哪里提供这种服务? –

+0

我没有正确地得到您的问题,但在我的导航栏组件中,我已将它添加到[提供程序]中。我更新了我的问题。购物车服务直接与导航栏无关。 – Nitish

回答

1

我觉得这里的错误是一个概念的错误。

正如@ mxii所说,你的情况完全符合Observable的行为,你不应该使用promise和一个事件发射器(在你的item被实际添加到服务器端之前调用)。

解决方案与承诺:

在你要修复与承诺您的问题的情况下,我认为解决的办法是,一旦你只得到了答案触发事件:

,然后提供它在您的顶级模块中(通常为AppModule),以确保您的应用程序只有一个实例。

解决方案与可观察:

addToCart(id: any): Observable<any> {//Don't you have an item interface to type the object you get? 
     return this.http.get( this.myUrl + 'add' + '/' + id + '/', { withCredentials:true}) 
     .map(res => res.json()); 
    } 

,然后在你的NavBar

@Component({ 
directives:[ROUTER_DIRECTIVES, Cart] 
//Note that I removed CartService, as I said you HAVE to provide it on the AppModule, else you'll have different instances accross your application and it seems like it's not what you want. 
}) 
export class Navbar implements OnInit{ 

    ... 
    totalCost: any; 
    cartItemCount : any; 
    addedItem: any; 

    constructor(private cartService: CartService){ 
    } 

    private onItemAdded(item: any): void { 
     // do something with added item 
     this.addedItem = item; 
    } 

    public addItemToCart(id:number):void{ 
     //I guess you're adding item from a button click, the button should call this method, passing the id of the item as parameter. 
     this.cartService.addToCart(id).subscribe(this.onItemAdded); 
    } 
... 
... 
} 
+0

在我的情况下,我的navbar组件中没有addItemToCart(id:number)方法,我从另一个组件调用它。在导航栏组件中,我简单地获取购物车元素,并可以将其删除。添加到购物车发生在我的不同产品组件中。 – Nitish

1

您应该只使用EventEmitter@Output()的!

您的方案完全符合一个Observable ..

创建Subject并调用next(),它类似于emit()

import { Subject } from 'rxjs'; 

// .. 

    public itemAdded$ = new Subject<any>(); 

// .. 

    this.itemAdded$.next(id); 

订阅部分应该没问题。

+0

从'rxjs'导入{Subject};给我错误说404没有找到。不过,我从'rxjs/Observable'导入了{Observable};这工作正常.. – Nitish

+0

然后试试这个:从{rxjs/Subject'; import{}} { – mxii

0

服务是单身人士每个供应商。您正在向导航栏注入不同的CartService实例,以及正在调用addToCart函数的任何实例。

我希望Navbar显示在您的应用程序的每一页,所以这里是如何使CartService全球单身。

@NgModule({ 
    declarations: [ 
    ], 
    imports: [ 
    ], 
    providers: [CartService], //<--- added here 
    bootstrap: [AppComponent] 
}) 
export class AppModule { } 

取下模块和组件的任何其他providers: [CartService](如果你没有缩进创建另一个实例)

+0

并提到以上两个答案,哪一个更适合您的解决方案?活动emiiter或与主题和next()? – Nitish

+0

你需要使你的服务单例,因为我用两种方式显示。 – Sefa