2016-07-05 13 views
1

Mein viewModel hat ein Array namens 'Items'. Ich möchte den Inhalt von 'Items' mit einem Foreach-Binding anzeigen. Alles funktioniert gut, wenn ich normales HTML verwende. Funktioniert aber nicht mit einer Dialogbox, die ich mit jQueryUI erstellt habe.Knockout-Bindung funktioniert nicht mit jQueryUI-Dialog

HTML:

<div id="skus0"> 
    <div id="skus1"> 
    <ul data-bind="foreach: Items"> 
     <li data-bind="text:Name"></li> 
    </ul> 
    </div> 
    <input type="button" id="openQryItems" class="btn btn-info" value="Open" data-bind="click:openQueryItems" /> 
</div> 

JavaScript:

// my view model 
var viewModel = { 
    Items: [{Name:'Soap'},{Name:'Toothpaste'}] 
}; 

// JS to configure dialogue 
$("#skus1").dialog({ 
    autoOpen: false, 
    width: 500, 
    modal: true, 
    buttons: { 
    "OK": function() { 
     $(this).dialog("close"); 
    }, 
    "Cancel": function() { 
     $(this).dialog("close"); 
    } 
    } 
}); 

// for mapping my model using ko.mapping plugin 
var zub = zub || {}; 
zub.initModel = function (model) { 
    zub.cycleCountModel = ko.mapping.fromJS(model); 
    zub.cycleCountModel.openQueryItems = function() { 
    $("#skus1").dialog("open"); 
    } 
    ko.applyBindings(zub.cycleCountModel, $("#skus0")[0]); 
} 

zub.initModel(viewModel); 

ich eine Geige hier my fiddle

+0

@ Matt.kaaj Ich muss nutzen ko.mapping und den Namespace. Mein wirkliches Weltmodell ist sehr groß und ko.mapping hilft mir dabei. – Harrobbed

Antwort

2

$.fn.dialog das Element von seinem Platz in der DOM und legt sie in einen neuen Container erstellt haben, beseitigt ; So kann ein schwebendes Fenster erstellt werden. Das Problem dabei ist, dass es die Datenbindung unterbricht, da das Dialogfeld DOM nicht länger im datengebundenen DOM der obersten Ebene verschachtelt ist.

Verschieben der Dialog Initialisierung nachko.applyBindings wird dialog ermöglichen Sachen aus dem DOM zu zerren nach die Liste aufgefüllt wird. Dies bedeutet natürlich, dass zukünftige Änderungen nach wie vor nicht berücksichtigt werden. Dies kann wichtig sein, wenn Sie möchten, dass der geöffnete Dialog automatisch geändert wird.

Wenn der Dialoginhalt vollständig dynamisch sein soll, können Sie einen Bindungshandler erstellen; Das haben wir in unserem Projekt gemacht. Hier ist eine grobe Skizze, wie wir taten dies:

ko.bindingHandlers.dialog = { 
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingCtx) { 
    var bindingValues = valueAccessor(); 
    var hasAppliedBindings = false; 
    var elem = $(element); 
    var options = { 
     id: ko.utils.unwrapObservable(bindingValues.id), 
     title: ko.utils.unwrapObservable(bindingValues.title), 
     // etc... 
     onOpen: function() { 
     if (!hasAppliedBindings) { 
      hasAppliedBindings = true; 
      var childCtx = bindingCtx.createChildContext(viewModel); 
      ko.applyBindingsToDescendants(childCtx, element); 
     } 
     } 
    }; 

    elem.dialog(options); 
    } 

    return { controlsDescendantBindings: true }; 
} 

..., die wir wie folgt verwendet:

<div data-bind="dialog: { title: 'some title', id: 'foo', ... }"> 
    <!-- dialog contents --> 
</div> 

Was return { controlsDescendantBindings: true } ist nicht gewährleistet, dass äußere Bindungen wirken sich nicht auf irgendetwas die dialog mit Bindung Handler. Dann erstellen wir unsere eigene Knockout-bindende "Insel", nachdem sie aus dem DOM herausgezogen wurde, basierend auf dem ursprünglichen Ansichtsmodell.

Obwohl wir in unserem Projekt auch hybrid jQuery + Knockout verwendet haben, würde ich Ihnen wärmstens empfehlen, dies zu vermeiden, wann immer es möglich ist. Es gab so viele Hacks, die wir einsetzen mussten, um diese Art von Anwendung aufrecht zu erhalten. Das Beste, was Sie tun sollten, ist Knockout-Binding-Handler zu bevorzugen (und ich denke, es hat ein "Komponenten" -Konzept, mit dem ich noch nicht gespielt habe) über DOM-Manipulationen, um fehlerhaftes UI-Management zu vermeiden.

+0

danke! ging nach Hause und probierte es aus. Habe es funktioniert. Alles was ich zu tun hatte, war den Dialog nach ko.applyBindings zu initialisieren, wie Sie es vorgeschlagen haben. – Harrobbed

Verwandte Themen