【问题标题】:Ionic Events replace with Angular Observables离子事件替换为 Angular Observables
【发布时间】:2020-02-04 12:04:01
【问题描述】:

我了解 Ionic 事件将在下一版本中被弃用。目前,我使用事件从子组件执行父页面中的功能。这是一个例子:

在我的主页中,它订阅了要刷新的事件:

constructor(){
  this.eventFormRefresh = (obj) => {
    this.fetch(obj.isReset);
  };
  this.events.subscribe('form:refresh', this.eventFormRefresh);
}

ngOnDestroy(): void {
  this.events.unsubscribe('form:refresh', this.eventFormRefresh);
}

在一个子组件中,我通过发布 'form:refresh' 事件来激活刷新:

this.events.publish('form:refresh');

我将如何使用 angular observables 进行上述操作?

【问题讨论】:

    标签: angular ionic-framework observable


    【解决方案1】:

    您可以为此使用rxjs Subject,因此首先创建一个通用服务,例如。

    @Injectable()
    export class EventService{
      private formRefreshAnnouncedSource = new Subject();
      formRefreshSource$ = this.formRefreshAnnouncedSource.asObservable();
    
      publishFormRefresh(){
        this.formRefreshAnnouncedSource.next()
      }
    
    }
    

    然后发布喜欢

    this.eventService.publishFormRefresh();
    

    并订阅一些组件

    this.subscription = this.eventService.formRefreshSource$.subscribe(data => {
      //do something here
    });
    

    cancel subscription ngOnDestroy

    this.subscription.unsubscribe()
    

    【讨论】:

    • 谢谢,所以如果我想传递数据,我假设我通过 publishFormRefresh(data) 和 this.formRefreshAnnouncedSource.next(data) 传递它,对吗?
    • 很抱歉有其他问题,但有没有办法用 observables 做到这一点?即 formRefreshAnnouncedSource = new Observable 不是主题
    • @KaTech 使用event emitter 然后formRefreshAnnouncedSource = new EventEmitter<any>() 并像this.formRefreshAnnouncedSource.emit() 一样发射
    • 感谢在研究更多主题之后是要走的路。但是 this.formRefreshAnnouncedSource.asObservable 有必要吗?我设法做到了。即,我在我的组件中直接订阅了 formRefreshAnnouncedSource(通过服务中的 getSubject fn)。看这个教程coryrylan.com/blog/rxjs-observables-versus-subjects
    • @KaTech 主题可以是 subscribed bysubscribed to 但如果您直接订阅主题,在这种情况下,您也可以从组件中发出,这不是正确的方法。应该使用服务来发出数据
    【解决方案2】:

    您在 IONIC 3 中习惯的用户事件。 您只需在要使用它的页面中导入此服务/提供者。 参考 https://git.furworks.de/opensourcemirror/Ionic/commit/e5f2a18230f3ca3017f0302fb57ef275d0f63a8b

    import { Injectable } from '@angular/core';
    
    export type EventHandler = (...args: any[]) => any;
    @Injectable({
      providedIn: 'root',
    })
    export class Events {
      private c = new Map<string, EventHandler[]>();
    
      constructor() {
      //   console.warn(`[DEPRECATION][Events]: The Events provider is deprecated, and it will be removed in the next major release.
      // - Use "Observables" for a similar pub/sub architecture: https://angular.io/guide/observables
      // - Use "Redux" for advanced state management: https://ngrx.io`);
      }
      /**
       * Subscribe to an event topic. Events that get posted to that topic will trigger the provided handler.
       *
       * @param topic the topic to subscribe to
       * @param handler the event handler
       */
      subscribe(topic: any, ...handlers: EventHandler[]) {
        let topics = this.c.get(topic);
        if (!topics) {
          this.c.set(topic, topics = []);
        }
        topics.push(...handlers);
      }
    
      /**
       * Unsubscribe from the given topic. Your handler will no longer receive events published to this topic.
       *
       * @param topic the topic to unsubscribe from
       * @param handler the event handler
       *
       * @return true if a handler was removed
       */
      unsubscribe(topic: string, handler?: EventHandler): boolean {
        if (!handler) {
          return this.c.delete(topic);
        }
    
        const topics = this.c.get(topic);
        if (!topics) {
          return false;
        }
    
        // We need to find and remove a specific handler
        const index = topics.indexOf(handler);
    
        if (index < 0) {
          // Wasn't found, wasn't removed
          return false;
        }
        topics.splice(index, 1);
        if (topics.length === 0) {
          this.c.delete(topic);
        }
        return true;
      }
    
      /**
       * Publish an event to the given topic.
       *
       * @param topic the topic to publish to
       * @param eventData the data to send as the event
       */
      publish(topic: string, ...args: any[]): any[] | null {
        const topics = this.c.get(topic);
        if (!topics) {
          return null;
        }
        return topics.map(handler => {
          try {
            return handler(...args);
          } catch (e) {
            console.error(e);
            return null;
          }
        });
      }
    }
    

    【讨论】:

    • 更多的控制和更少的修改。谢谢!
    • 请注意,这将很快从 Angular 中删除。
    【解决方案3】:

    // 使用 ionic g 服务事件创建服务

        import { Injectable } from '@angular/core';
        import { Subject } from 'rxjs';
    
        @Injectable({
        providedIn: 'root'
         })
    
         export class EventsService {
    
         private refreshData=new Subject();
    
         constructor() {};
    
         refreshData= this.refreshDatasObservable();
    
         refresh(message){
         this.refreshDatanext(message)
         }
    
       }
    

    在 app.module.ts 中

          import {EventsService} from './service/vents.service'; // add it to   provider 
    
           providers:[....
                   EventsService
                    ....
                    ]
    

    在您想要的页面中订阅并像这样调用

          import {EventsService} from './service/vents.service'; //import service                                   
              constructor(private eventsService:EventsService){
    
               //for refreshing or publishing
               this.eventsService.refresh('i am data');
    
              //for subscribing to change
              this.eventsService.refreshChatData$.subscribe(data=>{
                //do something
                })
    
               }
    

    【讨论】:

      【解决方案4】:

      您可以使用BehaviorSubject 创建服务,并且可以传递数据并随时随地订阅它。在您的情况下,传入子组件并订阅父组件。

      【讨论】:

        【解决方案5】:

        对于在与我相同的设置中发现此问题的其他人,这是另一种可能的路线。我们正在考虑从 Ionic V3 -> V4 开始,并且知道我们有一些令人头疼的问题。一个是不推荐使用的事件。我决定看看事件的离子角度实现是如何设置的,并意识到我有点喜欢它。我做了一个模仿他们实现的服务,希望以后替换离子角事件会更容易。

        @Injectable()
        export class Events {
            private _channels: { [key: string]: ((...args: any[]) => void)[] } = {};
            public subscribe(topic: string, handler: (...args: any[]) => void) {
                if (!this._channels[topic]) {
                    this._channels[topic] = [];
                }
                this._channels[topic].push(handler);
            }
            public publish(topic: string, ...args: any[]) {
                if (this._channels[topic] && this._channels[topic].length) {
                    this._channels[topic].forEach(handler => handler(...args));
                }
            }
            public unsubscribe(topic: string, handler: ((...args: any[]) => void) = null) {
                if (!handler) {
                    delete this._channels[topic];
                }
                const index = this._channels[topic].indexOf(handler);
                if (index > 0) {
                    this._channels[topic].splice(index, 1);
                }
                if (!this._channels[topic].length) {
                    delete this._channels[topic];
                }
            }
        }
        

        我知道这不使用 Observables,但想为其他希望直接修复 ionic-angular/events 的人提供不同的解决方案 我简化/删除了他们的一些代码,如果有任何问题请告诉我。

        【讨论】:

          【解决方案6】:

          这可以通过使用事件服务来处理,正如这篇媒体帖子Dealing with breaking change in Ionic 5中指出的那样

          作者说明了如何以最简单的方式重构代码并保持流程。

          【讨论】:

            猜你喜欢
            • 2019-03-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-05-04
            • 2018-07-11
            • 2016-03-30
            • 2017-10-03
            • 1970-01-01
            相关资源
            最近更新 更多