Modal Dialog for HotTowel SPA

In my previous post, I illustrated a master-detail scenario for displaying data from a “master” screen.

In this posting, I’m going to demonstrate how to display the “detail” data, using a modal dialog UI instead. DurandalJS used by HotTowel template has an excellent modal dialog module which utilizes the framework’s composition and viewModel modules

Our modified “Master Page” View Model

We have a new method added called ShowModal. This method will be bound to a click event of the buttons displayed in the table.

define(['services/logger',
       'services/datacontext',
       'durandal/modaldialog',
       'viewmodels/modaldetail'],
    function (logger, datacontext, modalDialog, modaldetail) {
        var vm = {
            activate: activate,
            title: 'Home View',
            Result: ko.observable(),
            ShowModal: ShowModal,
            Sessions: ko.observableArray([])
        };

        return vm;

        //#region Internal Methods

        function activate() {
            var self = this;
            return datacontext.getSessions(self.Sessions)
            .then(function () {
                logger.log('Sessions Loaded', null, 'home', true);
            });

        }

        function ShowModal(data) {

            var sessionName = data.Name;
            modaldetail.title(sessionName);
            datacontext.getSessionFull(sessionName, modaldetail.RowData)
            .then(function (data) {
                modalDialog.show(modaldetail)
                .then(function () {
                    logger.log('Modal Closed', null, 'home', true);
                });
            });

        }
        //#endregion
    });

Modified View for “Master Page”

Everything is almost the same as the previous html view markup, except that I have now bound a click event to each button, instead of the hash-based navigation link.

<section>
    <h2 class="page-title" data-bind="text: title"></h2>
    <table class='table table-bordered table-condensed table-hover'>
        <thead>
            <tr>
                <th>Name</th>
                <th>DOB</th>
            </tr>
        </thead>
        <tbody data-bind="foreach: Sessions">
            <tr>
                <td>
                    <button class ='btn btn-small btn-primary' data-bind="click:$root.ShowModal"><i class='icon-edit'></i>&nbsp;<span data-bind='    text: Name'></span></button>
                </td>
                <td data-bind='text: moment(DOB).format("MMMM Do YYYY, h:mm:ss a")'>
                </td>
        </tbody>
    </table>
</section>

The ViewModel for the “Detail” modal

DurandalJS folks are very clever in using the same concepts, that we are aleady familiar with – view and viewmodels. The modalDialog module still operates on those concepts. You design (html, with bindings if needed) how your modal like (View), and then the underlying data that it needs to display (ViewModel).

define([], function () {
    "use strict";
    var title = ko.observable(),
    RowData = ko.observableArray([]),
    Close = function() {
        this.modal.close();
    },
    activate = function (routeData) {
        return true;

    };
    return {
        title: title,
        activate: activate,
        RowData: RowData,
        Close: Close
    }

})

The cool thing as well, is that the modal dialog returns a Promise which is “fulfilled” then the modal is closed. If you look at our ViewModel for the “master” UI,

 function ShowModal(data) {

            var sessionName = data.Name;
            modaldetail.title(sessionName);
            datacontext.getSessionFull(sessionName, modaldetail.RowData)
            .then(function (data) {
                modalDialog.show(modaldetail)
                .then(function () {
                    logger.log('Modal Closed', null, 'home', true);
                });
            });

        }

we are able to detect and display something, when the modal is closed!

Our “View” for the Detail modal UI

Pretty much the same thing as the previous one, except that it is being styled as a modal

<div class="messageBox">
    <div class="modal-header">
        <h2 data-bind='html: title'></h2>
    </div>
    <div class="modal-body">
        <table class='table table-bordered table-condensed table-hover'>
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Name</th>
                    <th>Cost</th>
                </tr>
            </thead>
            <tbody data-bind="foreach: RowData">
                <tr>
                    <td data-bind='text: ID'></td>
                    <td data-bind='text: Name'></td>
                    <td data-bind='text: Cost'></td>
            </tbody>
        </table>
    </div>
    <div class="modal-footer">
        <button class="btn btn-info" data-dismiss="modal" aria-hidden="true" data-bind='click: Close'>Close</button>
    </div>
</div>
Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer’s view in any way.
Tagged with: ,
Posted in SPA
  • Jake Gaston

    I get “Unable to get property ‘close’ of undefined or null reference” When I try to use the close button.

    • Jake Gaston

      Evidently I needed to define ‘durandal/plugins/dialog’ as dialog, and use dialog.close(this).

      I want to thank you for this article, as it did help me out quite a bit.