带引导事件的Angular2不会触发可观察到的更改 [英] Angular2 with bootstrap events does not trigger observable changes

查看:133
本文介绍了带引导事件的Angular2不会触发可观察到的更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现了一个涉及bootstrapjs模态以及angular2的奇怪问题。
我有一个绑定到bootstrap模式的html的组件:

I found a weird issue involving bootstrapjs modals along with angular2. I have a component that is bound to the html of an bootstrap modal:

// ... lots of imports here

@Component({
selector: 'scrum-sessions-modal',
bindings: [ScrumSessionService, ScrumSessionRepository, ScrumModuleDataContext, ElementRef]

})

@View({
templateUrl: 'templates/modals/scrumSessions.modal.html',

styleUrls: ['']
})

export class ScrumSessionsModalComponent {

    private _elementRef: ElementRef;
    public sessions: ScrumSession[];

    constructor(scrumSessionsProxy: ScrumSessionsProxy, scrumSessionService: ScrumSessionService, elementRef: ElementRef) {

        this._proxy = scrumSessionsProxy;
        this._scrumSessionService = scrumSessionService;
        this._elementRef = elementRef;

        // This is the bootstrap on shown event where i call the initialize method
        jQuery(this._elementRef.nativeElement).on("shown.bs.modal", () => {
            this.initialize();    
        });

         jQuery("#scrumSessionsModal").on("hidden.bs.modal", () => {
             this.cleanup();
         });

    }

    public initialize() {

        // Start our hub proxy to the scrumsessionshub
        this._proxy.start().then(() => {
            // Fetch all active sessions;
            this._scrumSessionService.fetchActiveSessions().then((sessions: ScrumSession[]) => {
                // This console.log is being shown, however the sessions list is never populated in the view even though there are active sessions!
                console.log("loaded");
                this.sessions = sessions;
            }); 
        });
    }

    // Free up memory and stop any event listeners/hubs
    private cleanup() {
        this.sessions = [];
        this._proxy.stop();
    }

}

在这个模式中,我有一个事件构造函数中的监听器,用于检查何时显示模态。当它这样做时,它调用初始化函数,该函数将加载将在模态中显示的初始数据。

In this modal i have an event listener in the constructor that checks when the modal is shown. when it does it calls the initialize function that will load the initial data that will be displayed in the modal.

模态的html如下所示:

The html for the modal looks like this:

<div class="modal fade" id="scrumSessionsModal" tabindex="-1" role="dialog" aria-labelledby="scrumSessionsModalLabel">
<div class="modal-dialog" role="document">
    <div class="modal-content">
    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="myModalLabel">Actieve sessies </h4>
    </div>
    <div class="modal-body">

        <table class="table">
            <tr>
                <th>Id</th>
                <th>Maker</th>
                <th>Start datum</th>
                <th>Aantal deelnemers</th>
            </tr>
            <tr *ngFor="#session of sessions">
                <td>
                    {{ session.id }}
                </td>
                <td>
                    test
                </td>
                <td>
                    test
                </td>
                <td>
                test
                </td>
            </tr>
        </table>

    </div>
    <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
    </div>
    </div>
</div>

我遇到的问题是fetchactivesessions函数填充的sessions变量没有更新在视图中。我在调用完成方法上放了一个调试器,并且调用了一个scrumsession对象的结果。

The problem i am having is that the sessions variable that is filled by the fetchactivesessions function does not get updated in the view. I put a debugger on the fetch completion method and it is being called with a result of one scrumsession object.

然而,当我删除on(shown.bs。 modal)事件监听器,只需将调用初始化()置于5秒的setTimeout函数内,然后打开模式,会话列表正确填充。

However, when i remove the on("shown.bs.modal") event listener and simply put the call to initialize() inside a setTimeout function of 5 seconds and then open the modal the sessions list is correctly populated.

仅限当我将initialize调用放在bootstrap显示事件的回调中时发生。当调用在jquery回调中时,它就像停止检查更改一样。有谁知道这笔交易是什么?我可以只在构造函数中调用初始化,但我宁愿在bootstrap中调用显示的事件。

It only happens when i put the initialize call inside the callback of the bootstrap shown event. It is like it stops checking for changes when the call is inside a jquery callback. Does anyone know what the deal is here? I could offcourse just call the initialize in the constructor but i rather have it called on the shown event from bootstrap.

我已发布最新版本的应用程序以进行调试: http://gbscrumboard.azurewebsites.net/

I have published the latest version of the app for debugging at: http://gbscrumboard.azurewebsites.net/

推荐答案

使用易于使用的服务包含上述解决方案:

Wrapped above solution with an easy-to-use-service:

更新:如果你正在使用 rxjs-6 有重大变化,你必须

Update: If you are using rxjs-6 there are breaking changes, you will have to

import { fromEvent } from 'rxjs';
..

并使用

..
fromEvent(document, BsEventsService.BS_COLLAPSIBLE_SHOWN);

而不是

Observable.fromEvent(document, BsEventsService.BS_COLLAPSIBLE_SHOWN);

bs-events.service.ts

import { Subject, Observable, Subscription } from 'rxjs';
import { Injectable } from '@angular/core';

@Injectable() export class BsEventsService {   private static BS_COLLAPSIBLE_SHOWN: string = 'shown.bs.collapse';   private static BS_COLLAPSIBLE_HIDDEN: string = 'hidden.bs.collapse';

  constructor() {
    this.registerEvent(BsEventsService.BS_COLLAPSIBLE_SHOWN);
    this.registerEvent(BsEventsService.BS_COLLAPSIBLE_HIDDEN);
  }

  onCollapsibleShown(): Observable<Event> {
      return Observable.fromEvent(document, BsEventsService.BS_COLLAPSIBLE_SHOWN);
  }   
  onCollapsibleHidden(): Observable<Event> {
      return Observable.fromEvent(document, BsEventsService.BS_COLLAPSIBLE_HIDDEN);
  }

  private registerEvent(event) {
    var script = document.createElement('script');
    script.innerHTML = "eventRelay('" + event + "');"
    document.body.appendChild(script);
  }

}

index.html

<app-root></app-root>
..
  <!-- relay bootstrap events to angular - start -->
  <script>
    function eventRelay(bs_event) {
      $('body').on(bs_event, function ($event) {
        const customEvent = document.createEvent('Event');
        customEvent.initEvent(bs_event, true, true);
        let target_id = '#' + $event.target.id;
        $(target_id)[0].dispatchEvent(customEvent);
      });
    }
  </script>
  <!-- relay bootstrap events to angular - end -->
..
</body>

组件

import { BsEventsService } from './service/bs-events.service';
import { Subject, Observable, Subscription } from 'rxjs';
..

private onCllapsibleShownSubject: Subscription;
private onCllapsibleHiddenSubject: Subscription;

..
constructor(.., private bsEventsService: BsEventsService) {
..
}

ngOnInit() {
    this.onCllapsibleShownSubject = this.bsEventsService.onCollapsibleShown().subscribe((event: any) => {
      console.log('shown: ' + event.target.id);
    });
    this.onCllapsibleHiddenSubject = this.bsEventsService.onCollapsibleHidden().subscribe((event: any) => {
      console.log('hidden: ' + event.target.id);
    });
}
ngOnDestroy() {
    this.onCllapsibleShownSubject.unsubscribe();
    this.onCllapsibleHiddenSubject.unsubscribe();
}

这篇关于带引导事件的Angular2不会触发可观察到的更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆