javascript - 带有 Bootstrap 事件的 Angular2 不会触发可观察到的变化

标签 javascript jquery twitter-bootstrap typescript angular

我发现了一个奇怪的问题,涉及 bootstrapjs 模态和 angular2。 我有一个组件绑定(bind)到 Bootstrap 模式的 html:

// ... 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();
    }

}

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

模态的 html 看起来像这样:

<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 函数填充的 session 变量没有在 View 中更新。我在 fetch 完成方法上放置了一个调试器,它被一个 scrumsession 对象的结果调用。

但是,当我删除 on("shown.bs.modal") 事件监听器并简单地将对 initialize() 的调用放在 5 秒的 setTimeout 函数中,然后打开模态时, session 列表被正确填充。

只有当我将初始化调用放入 Bootstrap 显示事件的回调中时才会发生。当调用在 jquery 回调中时,它就像停止检查更改一样。有谁知道这是怎么回事?我当然可以在构造函数中调用初始化,但我宁愿在 Bootstrap 中调用显示的事件。

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

最佳答案

解决方案:使用 Angular4/Bootstrap4 观察 Bootstrap 事件。

总结:拦截 Bootstrap 事件,并在其位置触发自定义事件。自定义事件将从 Angular 组件中观察到。

索引.html:

<body>
...
<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>
</body>

在您的组件/服务中:

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

在您的组件的构造函数或 ngOnInit() 中,您现在可以注册并观察 Bootstrap 事件。例如,Bootstrap Modal“隐藏”事件。

constructor(){
    registerEvent('hidden.bs.modal');
     Observable.fromEvent(document, 'hidden.bs.modal')
     .subscribe(($event) => {
       console.log('my component observed hidden.bs.modal');
       //...insert your code here...
    });
}

注意:'eventRelay' 函数必须在 index.html 中,以便 DOM 加载它。否则,当您从“registerEvent”中发出对“eventRelay”的调用时,它不会被识别。

结论:这是一个中间件解决方案,适用于原始 Angular4/Bootstrap4。我不知道为什么 Bootstrap 事件在 Angular 内不可见,而且我还没有找到任何其他解决方案。

注意1:每个事件只调用一次registerEvent。这意味着在整个应用程序中“一次”,因此考虑将所有 registerEvent 调用放在 app.component.ts 中。多次调用 registerEvent 将导致向 angular 发送重复事件。

注意 2:有一个替代的 Bootstrap 框架可以与 angular 一起使用,称为 ngx-bootstrap ( https://valor-software.com/ngx-bootstrap/#/ ),它可能会使 Bootstrap 事件可见,但是我没有测试过这个。

高级解决方案:创建一个 Angular 服务来管理通过“registerEvent”注册的事件,因此它只为每个事件调用一次“registerEvent”。这样,您可以在您的组件中调用“registerEvent”,然后立即为该事件创建 Observable,而不必担心在其他组件中重复调用“registerEvent”。

关于javascript - 带有 Bootstrap 事件的 Angular2 不会触发可观察到的变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34495307/

相关文章:

javascript-创建最大连通图

javascript - ckeditor 更改段落元素生成的输出

javascript - 更改并将值添加到数组中然后显示它

jQuery - 将 CSS 边框添加到文本区域中的图像

ajax - 即使我得到的响应为readyStatus 4和status 200,Jquery Ajax调用也会进入错误回调

javascript - HTML固定大元素

html - Bootstrap Glyphicons 不会显示,除非所有文件都在根目录中

javascript - 选中/取消选中所有子复选框时选中/取消选中主复选框

jquery - 如何在点击时重复 css3 动画?

css - Bootstrap 3 上的输入宽度