2017-02-07 6 views
2

Ich bin neu in Knockout und ich habe Probleme zu verstehen, wie man ein View-Modell "bearbeitet", wenn man das Knockout-Mapping-Plugin benutzt. Hatte gehofft, dass mir jemand helfen könnte. Ich habe eine Liste mit Listen. Unten ist ein ähnliches Beispiel. Grundsätzlich mehrere Gruppen mit mehreren Dateien.Wie fügt man dem Knockout-Mapping-View-Modell Zeug hinzu?

[ 
    { 
     "group": "Alice", 
     "files": [ 
      {"filename": "red.mp3", "length": 5}, 
      {"filename": "blue.mp3","length": 6}, 
      {"filename": "yellow.mp3","length": 5} 
     ] 
    }, 
    { 
     "group": "Bob", 
     "files": [ 
      {"filename": "green.mp3","length": 2}, 
      {"filename": "purple.mp3","length": 10} 
     ] 
    } 
] 

Und ich kann das Grundmodell von diesem erhalten:

$.getJSON('api/get-list', function(data) 
    { 
     view = ko.mapping.fromJS(data); 
     ko.applyBindings(view); 
    }); 

Es funktioniert, und ich habe es geschafft, es in HTML zu verbinden, so dass es sichtbar ist, und alles ist in diesem Bereich in Ordnung. Aber ich muss ein paar Dinge hinzufügen, und ich bin mir nicht sicher, wie ich das machen soll. Und noch wichtiger, wie man es sauber und gut macht.

Ich gebe die Dateien mit einem Kontrollkästchen aus, und ich möchte eine Eigenschaft 'wählen' an sie gebunden. Ich konnte es tun, indem ich das Feld im Backend hinzufügte, aber will das nicht, weil es wirklich nicht dort sein sollte. Sie müssen außerdem angeben, wie viele Gruppen derzeit ausgewählt sind, aus wie vielen Gruppen und insgesamt.

Also, im Grunde möchte ich etwas wie folgt aus:

{ 
    "formSubmit": ?, 
    "totalNumberOfFiles": ?, 
    "totalNumberOfSelectedFiles": ?, 
    "groups": 
    [ 
     { 
      "group": "Alice", 
      "numberOfFiles": ?, 
      "selectedFiles": ?, 
      "files": [ 
       { 
        "filename": "red.mp3", 
        "length": 5, 
        "selected": boolean 
       }, 
       ... 
      ] 
     }, 
     ... 
    ] 
} 
  • Obwohl zum Beispiel die numberOfFiles ist wahrscheinlich nicht einmal nötig? Kann man das von files.length oder etwas bekommen?
  • Und sollte selectedFiles eine Funktion/beobachtbar sein, die die Anzahl der ausgewählten Dateien zählt (wie würde das aussehen?) Oder sollte es eher eine Liste sein, die irgendwie hinzugefügt/entfernt wurde (und wie würde man das tun?)
  • Und wie könnte ich, in der Submit-Funktion, eine Liste der aktuell ausgewählten Dateien bekommen, damit ich sie wieder auf den Server stellen kann?
  • Und wie kann ich das grundlegende Array, das ich vom Server mit diesen Dingen bekomme, auf eine nicht allzu chaotische Art und Weise "verbessern/anreichern"?

Grundsätzlich weiß ich (herausfinden), wie die Bindung zu tun, wenn nur das Modell funktioniert, aber nicht verstehen, wie es in einer guten Art und Weise zu bauen, wenn das Mapping-Plugin (und ich wirklich möchte es nicht manuell machen).

Hoffnung, jemand kann mir helfen, denn ich kann nur diese

Antwort

3

nicht herausfinden Wenn Sie ko.mapping.fromJS jede Eigenschaft verwenden, um eine beobachtbare umgewandelt wird und jedes Array auf ein observableArray umgewandelt wird.

Die Hauptansicht Modell MyViewModel, hat eine Liste von Dateigruppen, die mit einer Abbildung initialisiert wird, die ein benutzerdefinierte Mapping-Objekt verwendet. Dieses Objekt verfügt über einen Rückruf zum Erstellen (wie in http://knockoutjs.com/documentation/plugins-mapping.html erläutert), der eine neue Dateigruppe instanziiert.

Im Dateigruppe Konstruktor, kurz vor die neue Teilansicht Modell, eine Eigenschaft ‚ausgewählt‘ wird hinzugefügt, mit falschen sein Standardwert ist.

Auch die Hauptansicht Modell hat zwei berechnete Observablen:

  1. NUMBEROFFILES: gibt die Gesamtzahl der Dateien in jedem Dateigruppe
  2. SelectedFiles: gibt einen Array all ausgewählten Dateien in jeder Dateigruppe enthält

Innerhalb der senden Methode gibt es eine einfache Warnung zu demonstrieren, wie Sie auf das Array der ausgewählten Dateien zugreifen.

// data obtained from the server 
 
var data = [ 
 
    { 
 
    "group": "Alice", 
 
    "files": [ 
 
     { "filename": "red.mp3", "length": 5 }, 
 
     { "filename": "blue.mp3", "length": 6 }, 
 
     { "filename": "yellow.mp3", "length": 5 } 
 
    ] 
 
    }, 
 
    { 
 
    "group": "Bob", 
 
    "files": [ 
 
     { "filename": "green.mp3", "length": 2 }, 
 
     { "filename": "purple.mp3", "length": 10 } 
 
    ] 
 
    } 
 
]; 
 

 
// sub view model representing a single file grouping 
 
var FileGroup = function (data) { 
 
    data.files.map(f => f.selected = false); 
 
    ko.mapping.fromJS(data, {}, this); 
 
} 
 

 
// main view model 
 
var MyViewModel = function (data) { 
 
    this.fileGroups = ko.mapping.fromJS(data, { create: options => new FileGroup(options.data) }); 
 

 
    this.numberOfFiles = ko.computed(() => { 
 
    return this.fileGroups().reduce((total, fg) => { 
 
     total += fg.files().length; 
 
     return total; 
 
    }, 0); 
 
    }, this); 
 

 
    this.selectedFiles = ko.computed(function() { 
 
    return this.fileGroups().reduce((selectedFiles, fg) => { 
 
     selectedFiles.push.apply(selectedFiles, fg.files().filter(f => f.selected())); 
 
     return selectedFiles; 
 
    }, []) 
 
    }, this); 
 

 
    this.submit = function() { 
 
    alert("FILES POSTED TO SERVER: " + this.selectedFiles().length); 
 
    } 
 
} 
 

 
var viewModel = new MyViewModel(data); 
 
ko.applyBindings(viewModel);
.fileGroup { 
 
    border: 1px solid lightgray; 
 
    margin-bottom: 15px; 
 
    padding: 10px; 
 
} 
 

 
.selected { 
 
    border: 1px solid lightgreen; 
 
    margin-bottom: 15px; 
 
    padding: 10px; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js" type="text/javascript"></script> 
 

 
<div data-bind="foreach: fileGroups"> 
 
    <h3 data-bind="text: group"></h3> 
 

 
    <div data-bind="foreach: files" class="fileGroup"> 
 
    <input type="checkbox" data-bind="checked: selected"> 
 
    <span data-bind="text: filename" /> 
 
    </div> 
 
</div> 
 

 
<h4>Number of Files: <span data-bind="text: numberOfFiles"></span></h4> 
 

 
<div data-bind="foreach: selectedFiles, visible: selectedFiles().length > 0" class=selected> 
 
    <span data-bind="text: filename" /> 
 
</div> 
 

 
<button data-bind="click: submit">Submit</button>

+0

, dass es viel gemacht * * klarer denken, dass ich tatsächlich in der Lage sein werde weiter auf diesem Weg Knockout auf meinem eigenen jetzt zu bekommen. Ich danke dir sehr! – Svish

Verwandte Themen