53 Stimmen

Knockout-Datenbindung bei dynamisch erzeugten Elementen

Wie ist es möglich, Knockout Data-Bind auf dynamisch generierte Elemente anzuwenden? Ich füge zum Beispiel ein einfaches HTML-Auswahlmenü in ein Div ein und möchte die Optionen mit der Knockout-Optionen-Bindung auffüllen. So sieht mein Code aus:

$('#menu').html('<select name="list" data-bind="options: listItems"></select>');

aber diese Methode funktioniert nicht. Irgendwelche Ideen?

33voto

PlTaylor Punkte 7085

Wenn Sie dieses Element spontan hinzufügen, nachdem Sie Ihr Viewmodel gebunden haben, ist es nicht im Viewmodel enthalten und wird nicht aktualisiert. Sie können eine von zwei Möglichkeiten nutzen.

  1. Fügen Sie das Element zum DOM hinzu und binden Sie es erneut, indem Sie ko.applyBindings(); wieder
  2. ODER fügen Sie die Liste dem DOM von Anfang an hinzu und lassen Sie die Optionssammlung in Ihrem Viewmodel leer. Knockout wird es nicht rendern, bis Sie später Elemente zu Optionen on the fly hinzufügen.

17voto

Stevanicus Punkte 7098

Knockout 3.3

ko.bindingHandlers.htmlWithBinding = {
          'init': function() {
            return { 'controlsDescendantBindings': true };
          },
          'update': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
              element.innerHTML = valueAccessor();
              ko.applyBindingsToDescendants(bindingContext, element);
          }
    };

Mit dem obigen Codeschnipsel können Sie HTML-Elemente dynamisch mit der Eigenschaft "htmlWithBinding" einfügen. Die hinzugefügten untergeordneten Elemente werden dann ebenfalls ausgewertet... d.h. ihre Datenbindungsattribute.

11voto

Salomón Punkte 111

Den HTML-Bindungscode umschreiben oder einen neuen erstellen. Denn HTML-Bindung verhindert "injizierte Bindungen" in dynamischem HTML:

ko.bindingHandlers['html'] = {
  //'init': function() {
  //  return { 'controlsDescendantBindings': true }; // this line prevents parse "injected binding"
  //},
  'update': function (element, valueAccessor) {
    // setHtml will unwrap the value if needed
    ko.utils.setHtml(element, valueAccessor());
  }
};

4voto

Ivan Malagon Punkte 307

EDIT: Es scheint, dass dies seit Version 2.3 IIRC nicht mehr funktioniert, wie von LosManos

Mit myViewModel[newObservable] = ko.observable('') können Sie eine weitere Observable zu Ihrem View-Modell hinzufügen.

Danach rufen Sie erneut ko.applyBindings auf.

Hier ist eine einfache Seite, auf der ich dynamisch Absätze hinzufüge und das neue Ansichtsmodell und die Bindungen funktionieren einwandfrei.

// myViewModel starts only with one observable
        var myViewModel = {
            paragraph0: ko.observable('First')
        };

        var count = 0;

        $(document).ready(function() {
            ko.applyBindings(myViewModel);

            $('#add').click(function() {
                // Add a new paragraph and make the binding
                addParagraph();
                // Re-apply!
                ko.applyBindings(myViewModel);          
                return false;   
            });
        });

        function addParagraph() {
            count++;
            var newObservableName = 'paragraph' + count;
            $('<p data-bind="text: ' + newObservableName + '"></p>').appendTo('#placeholder');

            // Here is where the magic happens
            myViewModel[newObservableName] = ko.observable('');
            myViewModel[newObservableName](Math.random());

            // You can also test it in the console typing
            // myViewModel.paragraphXXX('a random text')
        }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/knockout-min.js"></script>

<div id="placeholder">
    <p data-bind="text: paragraph0"></p>
</div>

<a id="add" href="#">Add paragraph</a>

4voto

vivanov Punkte 1312

Für v3.4.0 verwenden Sie die unten stehende benutzerdefinierte Bindung:

ko.bindingHandlers['dynamicHtml'] = {
    'update': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        // setHtml will unwrap the value if needed
        ko.utils.setHtml(element, valueAccessor());
        ko.applyBindingsToDescendants(bindingContext, element);
    }
};

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X