【问题标题】:How to subscribe object from service in Angular 2/5?如何从 Angular 2/5 中的服务订阅对象?
【发布时间】:2017-12-29 18:40:11
【问题描述】:

我有一个问题,我想在数据来自服务器后将数据接收到我的属性组件中。

我在服务中做了这样的事情:

private events: Event[] = [];
eventChanged = new Subject<any>(); // Edit: added an observable

constructor(private http: HttpClient) { 
    this.http.get<Event[]>(this.baseUrl)
    .subscribe(events => this.events = events);
  this.eventChanged.next(this.events.slice()); //Edit: added an information to subscribers that events list changed
}
getEvents(): Observable<Event[]> {
    return this.eventChanged.asObservable();
}  // Edit: now I use this method to enables subscribers to observable

        /* I don't use that method after Edit
        showAllEvents(): Event[] {
            return [...this.events];
        }
        */

然后我像这样在我的组件中使用方法showAllEvents()

private events: Event[] = [];
private calendarEvents: CalendarEvent[] = [];
subscription: Subscription; // Edit: Added a Subscription

    getInterestedEvents() {
       // this.events = this.el.showAllEvents(); <-- I changed it into observable
   this.subscription = this.el.getEvents()
    .subscribe(
    (events) => {
      this.events = events;
    });
    this.events.forEach(eachEvent => {
        let calendarEvent: CalendarEvent = {
            start: subDays(startOfDay(new Date()), 1),
            end: addDays(new Date(), 1),
            title: eachEvent.name,
            color: colors.red
        }
        this.calendarEvents.push(calendarEvent);
    })
}

我不知道如何让this.events 等待来自服务的数据。有任何想法吗?每页看起来都不一样,现在我觉得自己像个傻瓜。

编辑

我订阅了并且可以观察到,但this.el.getEvents().subscribe... 仍然没有在我的组件中返回任何数据。

【问题讨论】:

    标签: javascript angular typescript angular2-services


    【解决方案1】:

    您可以在您的服务中创建订阅,以通知事件列表是否更改

    eventChanged = new Subject<Event[]>();
    

    在您的组件中,您需要订阅 eventChanged,以防事件列表发生变化

    this.subscription = this.eventService.eventChanged
      .subscribe(
        (event: Event[]) => {
          this.events = events;
        }
      );
    

    然后在您的服务中添加一个next,以在每次任何组件更新它时通知事件更改,并使其重新发送事件列表或您想要的任何内容

      addEvent(event: Event) {
        this.events.push(event);
        this.eventChanged.next(this.events.slice());
      }
    

    更新:以示例

    如果我们有事件查看器、事件编辑器组件和事件服务

    设置事件服务有一个主题(事件改变),访问者(获取事件)加法器(更新事件)

    import { Injectable } from '@angular/core';
    import {Subject} from 'rxjs/Subject';
    
    @Injectable()
    export class EventService {
    
      eventChanged = new Subject<string[]>();
    
      events: string[] = [
        'Pizza Party',
        'Hackacthon',
        'Movie Night'
      ]
      constructor() { }
    
      addEvent(event: string) {
        this.events.push(event);
        this.eventChanged.next(this.events.slice());
      }
    
      getEvents() {
        return this.events.slice();
      }
    }
    

    然后组件EventViewer,获取列表,以及订阅任何更改

    event-viewer.component.ts

    import { Component, OnInit } from '@angular/core';
    import {EventService} from '../event.service';
    import {Subscription} from 'rxjs/Subscription';
    
    @Component({
      selector: 'app-event-viewer',
      templateUrl: './event-viewer.component.html',
      styleUrls: ['./event-viewer.component.css']
    })
    export class EventViewerComponent implements OnInit {
    
      subscription: Subscription;
      events: string[] = this.eventService.getEvents();
    
      constructor(private eventService: EventService) { }
    
    
      ngOnInit() {
        this.subscription = this.eventService.eventChanged
        .subscribe(
          (events: string[]) => {
            this.events = events;
          }
        )
      }
    
    }
    

    然后我们渲染出来

    event-viewer.component.html

    <ul>
      <li *ngFor="let event of events">{{event}}</li>
    </ul>
    

    最后我们想要一个事件编辑器组件

    事件编辑器.component.ts

    import { Component, OnInit } from '@angular/core';
    import {EventService} from '../event.service';
    
    @Component({
      selector: 'app-event-edit',
      templateUrl: './event-edit.component.html',
      styleUrls: ['./event-edit.component.css']
    })
    export class EventEditComponent implements OnInit {
    
      eventNumber: number = 1;
    
      constructor(private eventService: EventService) { }
    
      ngOnInit() {
      }
    
      addEvent()
      {
        this.eventService.addEvent(this.eventNumber.toString())
        this.eventNumber++;
      }
    
    }
    

    并呈现一个按钮供用户控制

    事件编辑器.component.ts

    <button (click)="addEvent()">Add event {{eventNumber}}</button>
    

    在选择的模块中,我们显然必须声明这些组件,加入提供者

    app.module.ts

    @NgModule({
      declarations: [
        EventViewerComponent,
        EventEditComponent
      ],
      imports: [
        CommonModule
      ],
      providers: [EventService]
    })
    

    然后我们渲染两个组件

    app.component.ts
    
    <app-event-viewer></app-event-viewer>
    <app-event-edit></app-event-edit>
    

    现在每次我们点击一​​个组件中的按钮时,另一个组件都会获取更新的列表

    【讨论】:

    • 不幸的是它不起作用,我在我的服务构造函数中添加了this.eventChanged.next(this.events.slice());,我还测试了方法addEvent()this.eventService.eventChanged.subscribe(..没有注意到任何变化。它没有被再次调用。
    • @Adriano,创建了一个完整的例子
    • @lancovici 当我从服务器获取数据时,订阅不起作用。多亏了这一点:events: string[] = this.eventService.getEvents(); 它会在页面重新加载后显示数据。
    • @Adriano 检查你在 package.json 中的 rxjs,并告诉我它是什么版本。在检查页面时您还看到任何错误吗?
    • @lancovici 它是“rxjs”:“^5.5.2”,不,我没有注意到任何错误。我进行订阅工作,但只有在我添加下一个“事件”之后
    【解决方案2】:

    例如:

    export class YourService {
        private refreshSource: Subject<boolean> = new Subject();
        public refreshStream: Observable<boolean> = this.refreshSource.asObservable();
    
        endpoint_url = "https://<your_backend>/api/";
    
        constructor(private client: HttpClient) {}
    
        // get collection
        cget(queryParams: any): Promise<Obj[]> {
             return this.client.get<Obj[]>(this.endpoint_url + 'objs').toPromise();
        }
    
        // create one object
        post(obj: Obj): Promise<Obj> {
            const res = this.client.post(
                this.endpoint_url + 'objs',
                JSON.stringify(obj),
                this.requestParams);
    
            return res.toPromise().then((response) => {
                obj.id = response['id'];
                this.refreshSource.next(true);
                return obj as Obj;
            });
    }
    
    
    
    export class YourComponent implements OnDestroy {
        subscriptions: Subscription[] = [];
        success:boolean;
        failure:boolean;
        loading:boolean;
    
        constructor(private ys: YourService) {
            this.subscriptions.push( this.ys.refreshStrem.subscribe(() => this.load()) );
        }
    
    
        async load() {
            this.yourObjs = await this.ys.cget();
        }
    
        async submit() {
            this.loading = true;
            try {
                const response = this.ys.post(this.obj)
                this.success = true;   
            } catch (error) {
                console.log('error', error);
                this.failure = true;
            } finally {
                this.loading = false;
            }
        }
    
        ngOnDestroy() {
            this.subscriptions.forEach(subscription => subscription.unsubscribe());
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-23
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 2017-03-13
      • 2018-10-06
      • 2017-06-25
      • 2019-11-25
      相关资源
      最近更新 更多