jqueryUI modal dialog breaks knockoutjs bindings

2019-05-10 11:22发布

问题:

Intent is for the user to click on a logo section and be presented with a modal dialog where they can upload a new logo image, change the current logo image, or remove the current logo image.

Right now the upload image causes a page refresh, but I'm moving towards using ajax posts handle this functionality to prevent a page refresh.

The issue I'm having is that once an image is there, and the user removes the image, the modal dialog box doesn't update after the knockout js model has. The image is displayed into two areas, once on the screen where it should be, and once again in the modal dialog as a preview. The main image src updates and I can hides, but looks like the bindings between knockout and the dialog are dropped when jQueryUI clones the element.

I was trying to use the init example from this post but the modal dialog didn't render.

Any ideas?

HTML/Razor

<div id="logo" data-bind="cmdDialog: {id:'dialog-form', cmd:'open'} ">
    <div id="changeLogo">
        <h1 data-bind="visible: URL() == null"><span>Logo Here</span></h1>
        <img data-bind="attr: { src: URL}, visible: URL() != null"/>
    </div>
    <div id="dialog-form" data-bind="setDialog:{}">
        <img data-bind="attr: { src: URL}"/>
        <button type="button" data-bind="visible: URL() != null, deleteImage: ImageID">Remove Image</button>
        <hr/>
        <form action="uploadImage" method="post">
            @Html.HiddenFor(m => m.ID, new { data_bind = "value: ID" })
            @Html.HiddenFor(m => m.ImageID, new { data_bind = "value: ImageID" })
            <div>
                <input type="file" name="file" id="file"/>
            </div>
            <div>
                <input type="submit" value="Upload" />
                <button type="button" data-bind="cmdDialog: {id:'dialog-form', cmd:'close'} ">Cancel</button>
            </div>
        </form>
    </div>
</div>

​​​​​

JavaScript

$(document).ready(function () {
        /*************************************/
        // Modal Dialog config
        /*************************************/
        var options = {
            autoOpen: false,
            resizable: false,
            modal: true,
            height: 400,
            width: 450
        };

        /*************************************/
        // Knockout config
        /*************************************/
        var viewModelLogo;

        ko.bindingHandlers.setDialog = {
            init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
                var $element = $(element);

                setTimeout(function() {$element.dialog(options); }, 0);
            }
        };

        ko.bindingHandlers.cmdDialog = {
            init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
                $(element).click(function() {
                    var parms = ko.utils.unwrapObservable(valueAccessor());
                    var $logoForm = $('#' + parms.id);

                    $logoForm.dialog(parms.cmd);
                });
            }
        };

        ko.bindingHandlers.deleteImage = {
            init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
                $(element).click(function() {
                    deleteImage(viewModel);
                });
            }
        };
        $.getJSON("/Logo/Logo/GetPageModel", Model.ID, function(result) {
            updateModel(result.Data);
        });

        var deleteImage = function(imageModel) {
            var image = ko.toJS(imageModel);
            $.post("/Logo/Logo/deleteImage", image, function(result) {
                updateModel(result.Data);
            });
        };

        function updateModel(image) {
                viewModelLogo = ko.mapping.fromJS(image);
                ko.applyBindings(viewModelLogo, document.getElementById('logo'));
                $('#dialog-form').dialog("close");
        };
    });

回答1:

I found that when I defined the dialog as you have done - ie as a normal div The bindings would not work. When, however, I used a template I could use the data parameter to specify the item i was binding to which brought everything into scope including other items i was using on the viewmodel.

Have a look at Ryan Niemeyer's excellent example of doing this with a dialog window which updates the original page http://jsfiddle.net/rniemeyer/WpnTU/

note how he has defined the content of the dialog as a template.



回答2:

It looks like you're not setting your update handlers. Check out this knockout tutorial for how to do this correctly.