Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

integrating jquery ui dialog with knockoutjs

I am trying to create knockoutjs bindings for jquery ui dialogs, and cannot get the dialog to open. The dialog element is created correctly, but seems to have display: none that calling dialog('open') doesn't remove. Also, the call to dialog('isOpen') returns the dialog object rather than a boolean.

I am using the latest knockoutjs and jquery 1.4.4 with jquery ui 1.8.7. I've also tried it with jQuery 1.7.1 with the same results. Here's my HTML:

<h1 class="header" data-bind="text: label"></h1>

<div id="dialog" data-bind="dialog: {autoOpen: false, title: 'Dialog test'}">foo dialog</div>

<div>
    <button id="openbutton" data-bind="dialogcmd: {id: 'dialog'}" >Open</button>
    <button id="openbutton" data-bind="dialogcmd: {id: 'dialog', cmd: 'close'}" >Close</button>
</div>

and this is the javascript:

var jQueryWidget = function(element, valueAccessor, name, constructor) {
    var options = ko.utils.unwrapObservable(valueAccessor());
    var $element = $(element);
    var $widget = $element.data(name) || constructor($element, options);
    $element.data(name, $widget);

};

ko.bindingHandlers.dialog = {
        init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
            jQueryWidget(element, valueAccessor, 'dialog', function($element, options) {
                console.log("Creating dialog on "  + $element);
                return $element.dialog(options);
            });
        }        
};

ko.bindingHandlers.dialogcmd = {
        init: function(element, valueAccessor, allBindingsAccessor, viewModel) {          
            $(element).button().click(function() {
                var options = ko.utils.unwrapObservable(valueAccessor());
                var $dialog = $('#' + options.id).data('dialog');
                var isOpen = $dialog.dialog('isOpen');
                console.log("Before command dialog is open: " + isOpen);
                $dialog.dialog(options.cmd || 'open');
                return false;
            });
        }        
};

var viewModel = {
    label: ko.observable('dialog test')
};

ko.applyBindings(viewModel);

I have set up a JSFiddle that reproduces the problem.

I am wondering if this has something to do with knockoutjs and event handling. I tried returning true from the click handler, but that did not appear to affect anything.

like image 651
Gene Golovchinsky Avatar asked Dec 23 '11 01:12

Gene Golovchinsky


People also ask

How make jQuery ui dialog responsive?

Below is how I achieved a responsive jQuery UI Dialog. To do this, I added a new option to the config - fluid: true , which says to make the dialog responsive. I then catch the resize and dialog open events, to change the max-width of the dialog on the fly, and reposition the dialog.

What is dialog in jQuery?

A dialog box is a floating window with a title and content area. This window can be moved, resized, and of course, closed using "X" icon by default. jQueryUI provides dialog() method that transforms the HTML code written on the page into HTML code to display a dialog box.


2 Answers

It looks like writing to the widget to .data("dialog") and then trying to operate on it is causing an issue. Here is a sample where .data is not used and the open/close is called based on the element: http://jsfiddle.net/rniemeyer/durKS/

Alternatively, I like to work with the dialog in a slightly different way. I like to control whether the dialog is open or closed by using an observable. So, you would use a single binding on the dialog itself. The init would initialize the dialog, while the update would check an observable to see if it should call open or close. Now, the open/close buttons just need to toggle a boolean observable rather than worry about ids or locating the actual dialog.

ko.bindingHandlers.dialog = {         init: function(element, valueAccessor, allBindingsAccessor) {             var options = ko.utils.unwrapObservable(valueAccessor()) || {};             //do in a setTimeout, so the applyBindings doesn't bind twice from element being copied and moved to bottom             setTimeout(function() {                  options.close = function() {                     allBindingsAccessor().dialogVisible(false);                                         };                  $(element).dialog(options);                       }, 0);              //handle disposal (not strictly necessary in this scenario)              ko.utils.domNodeDisposal.addDisposeCallback(element, function() {                  $(element).dialog("destroy");              });            },         update: function(element, valueAccessor, allBindingsAccessor) {             var shouldBeOpen = ko.utils.unwrapObservable(allBindingsAccessor().dialogVisible),                 $el = $(element),                 dialog = $el.data("uiDialog") || $el.data("dialog");              //don't call open/close before initilization             if (dialog) {                 $el.dialog(shouldBeOpen ? "open" : "close");             }           } }; 

Used like:

<div id="dialog" data-bind="dialog: {autoOpen: false, title: 'Dialog test' }, dialogVisible: isOpen">foo dialog</div> 

Here is a sample: http://jsfiddle.net/rniemeyer/SnPdE/

like image 60
RP Niemeyer Avatar answered Sep 28 '22 05:09

RP Niemeyer


I made a little change to RP Niemeyer's answer to allow the dialog's options to be observables

http://jsfiddle.net/YmQTW/1/

Get the observables values with ko.toJS to initialize the widget

setTimeout(function() { 
    options.close = function() {
        allBindingsAccessor().dialogVisible(false);                        
    };

    $(element).dialog(ko.toJS(options));          
}, 0);

and check for observables on update

//don't call dialog methods before initilization
if (dialog) {
    $el.dialog(shouldBeOpen ? "open" : "close");

    for (var key in options) {
        if (ko.isObservable(options[key])) {
            $el.dialog("option", key, options[key]());
        }
    }
}
like image 27
Bruno S. Avatar answered Sep 28 '22 03:09

Bruno S.