Wie verwende ich knockout.js mit ASP.NET MVC ViewModels?


129

Kopfgeld

Es ist eine Weile her und ich habe noch ein paar offene Fragen. Ich hoffe, dass diese Fragen durch Hinzufügen eines Kopfgeldes beantwortet werden.

  1. Wie benutzt man HTML-Helfer mit knockout.js?
  2. Warum war das Dokument bereit, damit es funktioniert? (Weitere Informationen finden Sie unter Erste Bearbeitung.)

  3. Wie mache ich so etwas, wenn ich das Knockout-Mapping mit meinen Ansichtsmodellen verwende? Da ich aufgrund der Zuordnung keine Funktion habe.

    function AppViewModel() {
    
        // ... leave firstName, lastName, and fullName unchanged here ...
    
        this.capitalizeLastName = function() {
    
        var currentVal = this.lastName();        // Read the current value
    
        this.lastName(currentVal.toUpperCase()); // Write back a modified value
    
    };
  4. Ich möchte Plugins verwenden, zum Beispiel möchte ich Observables zurücksetzen können, als ob ein Benutzer eine Anfrage stornieren möchte, um zum letzten Wert zurückkehren zu können. Aus meiner Forschung geht hervor, dass dies durch Leute erreicht wird, die Plugins wie editierbare Dateien erstellen

    Wie verwende ich so etwas, wenn ich Mapping verwende? Ich möchte wirklich nicht zu einer Methode gehen, bei der ich in meiner Ansicht ein manuelles Mapping habe, bei dem ich jedes MVC viewMode-Feld einem KO-Modellfeld zuordne, da ich so wenig Inline-Javascript wie möglich möchte, und das scheint nur doppelt so viel Arbeit zu sein warum ich dieses Mapping mag.

  5. Ich mache mir Sorgen, dass ich, um diese Arbeit zu vereinfachen (durch die Verwendung von Mapping), viel KO-Leistung verlieren werde, aber andererseits mache ich mir Sorgen, dass manuelles Mapping nur viel Arbeit bedeutet und meine Ansichten zu viele Informationen und Informationen enthalten Möglicherweise wird die Wartung in Zukunft schwieriger (z. B. wenn ich eine Eigenschaft im MVC-Modell entferne, muss ich sie auch im KO-Ansichtsmodell verschieben).


Ursprünglicher Beitrag

Ich benutze asp.net mvc 3 und schaue mir Knockout an, da es ziemlich cool aussieht, aber es fällt mir schwer herauszufinden, wie es mit asp.net mvc funktioniert, insbesondere mit Ansichtsmodellen.

Für mich mache ich gerade so etwas

 public class CourseVM
    {
        public int CourseId { get; set; }
        [Required(ErrorMessage = "Course name is required")]
        [StringLength(40, ErrorMessage = "Course name cannot be this long.")]
        public string CourseName{ get; set; }


        public List<StudentVm> StudentViewModels { get; set; }

}

Ich hätte eine VM, die einige grundlegende Eigenschaften wie CourseName hat und darüber hinaus eine einfache Validierung hat. Das VM-Modell kann bei Bedarf auch andere Ansichtsmodelle enthalten.

Ich würde diese VM dann an die Ansicht übergeben, wenn ich HTML-Helfer verwenden würde, um sie dem Benutzer anzuzeigen.

@Html.TextBoxFor(x => x.CourseName)

Möglicherweise habe ich einige foreach-Schleifen oder etwas, um die Daten aus der Sammlung von Student View-Modellen zu entfernen.

Wenn ich dann das Formular abschicke, verwende ich jquery und serialize arraysende es an eine Controller-Aktionsmethode, die es wieder an das Ansichtsmodell bindet.

Mit knockout.js ist alles anders, da Sie jetzt Ansichtsmodelle dafür haben und aus all den Beispielen, die ich gesehen habe, keine HTML-Helfer verwenden.

Wie verwenden Sie diese beiden Funktionen von MVC mit knockout.js?

Ich habe dieses Video gefunden und es geht kurz (letzte Minuten des Videos um 18:48 Uhr) in die Verwendung von Ansichtsmodellen ein, indem im Grunde ein Inline-Skript mit dem Ansichtsmodell knockout.js verwendet wird, dem die Werte im ViewModel zugewiesen werden.

Ist dies der einzige Weg, dies zu tun? Wie wäre es in meinem Beispiel mit einer Sammlung von Ansichtsmodellen? Muss ich eine foreach-Schleife oder etwas anderes haben, um alle Werte zu extrahieren und sie in Knockout zuzuweisen?

Was HTML-Helfer betrifft, sagt das Video nichts über sie aus.

Dies sind die beiden Bereiche, die mich verwirren, da nicht viele Leute darüber zu sprechen scheinen und ich verwirrt darüber bin, wie die Anfangswerte und alles zur Ansicht gelangen, wenn ein Beispiel nur ein hartcodiertes Wertebeispiel ist.


Bearbeiten

Ich versuche, was Darin Dimitrov vorgeschlagen hat, und dies scheint zu funktionieren (ich musste jedoch einige Änderungen an seinem Code vornehmen). Ich bin mir nicht sicher, warum ich das Dokument fertig verwenden musste, aber irgendwie war nicht alles ohne es fertig.

@model MvcApplication1.Models.Test

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <title>Index</title>
    <script src="../../Scripts/jquery-1.5.1.js" type="text/javascript"></script>
    <script src="../../Scripts/knockout-2.1.0.js" type="text/javascript"></script>
    <script src="../../Scripts/knockout.mapping-latest.js" type="text/javascript"></script>
   <script type="text/javascript">

   $(function()
   {
      var model = @Html.Raw(Json.Encode(Model));


// Activates knockout.js
ko.applyBindings(model);
   });

</script>

</head>
<body>
    <div>
        <p>First name: <strong data-bind="text: FirstName"></strong></p>
        <p>Last name: <strong data-bind="text: LastName"></strong></p>
        @Model.FirstName , @Model.LastName
    </div>
</body>
</html>

Ich musste es um ein Abfragedokument wickeln, damit es funktioniert.

Ich bekomme auch diese Warnung. Ich bin mir nicht sicher, worum es geht.

Warning 1   Conditional compilation is turned off   -> @Html.Raw

Ich habe also einen Ausgangspunkt, den ich zumindest aktualisieren werde, wenn ich noch ein bisschen herumgespielt habe und wie das funktioniert.

Ich versuche, die interaktiven Tutorials durchzugehen, verwende aber stattdessen ein ViewModel.

Ich bin mir noch nicht sicher, wie ich diese Teile angehen soll

function AppViewModel() {
    this.firstName = ko.observable("Bert");
    this.lastName = ko.observable("Bertington");
}

oder

function AppViewModel() {
    // ... leave firstName, lastName, and fullName unchanged here ...

    this.capitalizeLastName = function() {
        var currentVal = this.lastName();        // Read the current value
        this.lastName(currentVal.toUpperCase()); // Write back a modified value
    };


Bearbeiten 2

Ich konnte das erste Problem herausfinden. Keine Ahnung vom zweiten Problem. Trotzdem. Hat jemand irgendwelche Ideen?

 @model MvcApplication1.Models.Test

    @{
        Layout = null;
    }

    <!DOCTYPE html>

    <html>
    <head>
        <title>Index</title>
        <script src="../../Scripts/jquery-1.5.1.js" type="text/javascript"></script>
        <script src="../../Scripts/knockout-2.1.0.js" type="text/javascript"></script>
        <script src="../../Scripts/knockout.mapping-latest.js" type="text/javascript"></script>
       <script type="text/javascript">

       $(function()
       {
        var model = @Html.Raw(Json.Encode(Model));
        var viewModel = ko.mapping.fromJS(model);
        ko.applyBindings(viewModel);

       });

    </script>

    </head>
    <body>
        <div>
            @*grab values from the view model directly*@
            <p>First name: <strong data-bind="text: FirstName"></strong></p>
            <p>Last name: <strong data-bind="text: LastName"></strong></p>

            @*grab values from my second view model that I made*@
            <p>SomeOtherValue <strong data-bind="text: Test2.SomeOtherValue"></strong></p>
            <p>Another <strong data-bind="text: Test2.Another"></strong></p>

            @*allow changes to all the values that should be then sync the above values.*@
            <p>First name: <input data-bind="value: FirstName" /></p>
            <p>Last name: <input data-bind="value: LastName" /></p>
            <p>SomeOtherValue <input data-bind="value: Test2.SomeOtherValue" /></p>
            <p>Another <input data-bind="value: Test2.Another" /></p>

           @* seeing if I can do it with p tags and see if they all update.*@
            <p data-bind="foreach: Test3">
                <strong data-bind="text: Test3Value"></strong> 
            </p>

     @*took my 3rd view model that is in a collection and output all values as a textbox*@       
    <table>
        <thead><tr>
            <th>Test3</th>
        </tr></thead>
          <tbody data-bind="foreach: Test3">
            <tr>
                <td>    
                    <strong data-bind="text: Test3Value"></strong> 
<input type="text" data-bind="value: Test3Value"/>
                </td>
            </tr>    
        </tbody>
    </table>

Regler

  public ActionResult Index()
    {
              Test2 test2 = new Test2
        {
            Another = "test",
            SomeOtherValue = "test2"
        };

        Test vm = new Test
        {
            FirstName = "Bob",
            LastName = "N/A",
             Test2 = test2,

        };
        for (int i = 0; i < 10; i++)
        {
            Test3 test3 = new Test3
            {
                Test3Value = i.ToString()
            };

             vm.Test3.Add(test3);
        }

        return View(vm);
    }

2
Ich habe gerade einen Blog-Beitrag geschrieben, um eine andere ähnliche Frage zu beantworten: roysvork.wordpress.com/2012/12/09/… Er beantwortet Ihre Frage möglicherweise nicht vollständig, gibt Ihnen jedoch eine gute Vorstellung davon, wie die Dinge funktionieren könnten. Ich hoffe, dass ich in nicht allzu ferner Zukunft einen weiteren Beitrag veröffentlichen kann. Fühlen Sie sich frei, mir Fragen in den Kommentaren zum Beitrag oder hier zu stellen, wenn Sie weitere Informationen benötigen.
Beyond-Code

Antworten:


180

Ich glaube, ich habe alle Ihre Fragen zusammengefasst. Wenn ich etwas verpasst habe, lassen Sie es mich bitte wissen ( Wenn Sie alle Ihre Fragen an einem Ort zusammenfassen könnten, wäre das schön =).

Hinweis. Kompatibilität mit dem ko.editablehinzugefügten Plug-In

Laden Sie den vollständigen Code herunter

Wie benutzt man HTML-Helfer mit knockout.js?

Das ist einfach:

@Html.TextBoxFor(model => model.CourseId, new { data_bind = "value: CourseId" })

Wo:

  • value: CourseIdGibt an, dass Sie die valueEigenschaft des inputSteuerelements mit der CourseIdEigenschaft Ihres Modells und Ihres Skriptmodells verbinden

Das Ergebnis ist:

<input data-bind="value: CourseId" data-val="true" data-val-number="The field CourseId must be a number." data-val-required="The CourseId field is required." id="CourseId" name="CourseId" type="text" value="12" />

Warum war das Dokument bereit, damit es funktioniert? (Weitere Informationen finden Sie unter Erste Bearbeitung.)

Ich verstehe noch nicht, warum Sie das readyEreignis verwenden müssen, um das Modell zu serialisieren, aber es scheint, dass es einfach erforderlich ist (keine Sorge)

Wie mache ich so etwas, wenn ich das Knockout-Mapping mit meinen Ansichtsmodellen verwende? Da ich aufgrund der Zuordnung keine Funktion habe.

Wenn ich das richtig verstehe, müssen Sie eine neue Methode an das KO-Modell anhängen. Das ist einfach, Modelle zusammenzuführen

Weitere Informationen finden Sie im Abschnitt - Zuordnung aus verschiedenen Quellen -

function viewModel() {
    this.addStudent = function () {
        alert("de");
    };
};

$(function () {
    var jsonModel = '@Html.Raw(JsonConvert.SerializeObject(this.Model))';
    var mvcModel = ko.mapping.fromJSON(jsonModel);

    var myViewModel = new viewModel();
    var g = ko.mapping.fromJS(myViewModel, mvcModel);

    ko.applyBindings(g);
});

Über die Warnung, die Sie erhalten haben

Warnung 1 Die bedingte Kompilierung ist deaktiviert -> @ Html.Raw

Sie müssen Anführungszeichen verwenden

Kompatibilität mit dem Plug-In ko.editable

Ich dachte, es würde komplexer werden, aber es stellt sich heraus, dass die Integration wirklich einfach ist. Um Ihr Modell bearbeitbar zu machen, fügen Sie einfach die folgende Zeile hinzu: (Denken Sie daran, dass ich in diesem Fall ein gemischtes Modell von Server und verwende Das Hinzufügen einer Erweiterung im Client und das Bearbeiten funktioniert einfach ... es ist großartig):

    ko.editable(g);
    ko.applyBindings(g);

Von hier aus müssen Sie nur spielen mit den zusätzlichen Erweiterungen mit Bindungen durch die Plug-in, zum Beispiel, habe ich eine Schaltfläche wie diese Bearbeitung meine Felder zu starten und in dieser Taste I um den Bearbeitungsvorgang zu starten:

    this.editMode = function () {
        this.isInEditMode(!this.isInEditMode());
        this.beginEdit();
    };

Dann habe ich Commit- und Cancel-Buttons mit folgendem Code:

    this.executeCommit = function () {
        this.commit();
        this.isInEditMode(false);
    };
    this.executeRollback = function () {
        if (this.hasChanges()) {
            if (confirm("Are you sure you want to discard the changes?")) {
                this.rollback();
                this.isInEditMode(false);
            }
        }
        else {
            this.rollback();
            this.isInEditMode(false);
        }
    };

Und schließlich habe ich ein Feld, das angibt, ob sich die Felder im Bearbeitungsmodus befinden oder nicht. Dies dient nur zum Binden der enable-Eigenschaft.

this.isInEditMode = ko.observable(false);

Über Ihre Array-Frage

Möglicherweise habe ich einige foreach-Schleifen oder etwas, um die Daten aus der Sammlung von Student View-Modellen zu entfernen.

Wenn ich dann das Formular abschicke, verwende ich jquery und serialize array und sende es an eine Controller-Aktionsmethode, die es wieder an das Ansichtsmodell bindet.

Sie können dasselbe mit KO tun. Im folgenden Beispiel werde ich die folgende Ausgabe erstellen:

Geben Sie hier die Bildbeschreibung ein

Grundsätzlich haben Sie hier zwei Listen, die Helpersmit KO erstellt und mit KO verbunden wurden. Sie haben ein dblClickEreignis gebunden, das beim Auslösen das ausgewählte Element aus der aktuellen Liste entfernt und zur anderen Liste hinzufügt, wenn Sie in die Liste postenController den Inhalt der einzelnen Die Liste wird als JSON-Daten gesendet und erneut an das Servermodell angehängt

Nuggets:

Externe Skripte .

Controller-Code

    [HttpGet]
    public ActionResult Index()
    {
        var m = new CourseVM { CourseId = 12, CourseName = ".Net" };

        m.StudentViewModels.Add(new StudentVm { ID = 545, Name = "Name from server", Lastname = "last name from server" });

        return View(m);
    }

    [HttpPost]
    public ActionResult Index(CourseVM model)
    {
        if (!string.IsNullOrWhiteSpace(model.StudentsSerialized))
        {
            model.StudentViewModels = JsonConvert.DeserializeObject<List<StudentVm>>(model.StudentsSerialized);
            model.StudentsSerialized = string.Empty;
        }

        if (!string.IsNullOrWhiteSpace(model.SelectedStudentsSerialized))
        {
            model.SelectedStudents = JsonConvert.DeserializeObject<List<StudentVm>>(model.SelectedStudentsSerialized);
            model.SelectedStudentsSerialized = string.Empty;
        }

        return View(model);
    }

Modell

public class CourseVM
{
    public CourseVM()
    {
        this.StudentViewModels = new List<StudentVm>();
        this.SelectedStudents = new List<StudentVm>();
    }

    public int CourseId { get; set; }

    [Required(ErrorMessage = "Course name is required")]
    [StringLength(100, ErrorMessage = "Course name cannot be this long.")]
    public string CourseName { get; set; }

    public List<StudentVm> StudentViewModels { get; set; }
    public List<StudentVm> SelectedStudents { get; set; }

    public string StudentsSerialized { get; set; }
    public string SelectedStudentsSerialized { get; set; }
}

public class StudentVm
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Lastname { get; set; }
}

CSHTML-Seite

@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>CourseVM</legend>

        <div>
            <div class="editor-label">
                @Html.LabelFor(model => model.CourseId)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.CourseId, new { data_bind = "enable: isInEditMode, value: CourseId" })
                @Html.ValidationMessageFor(model => model.CourseId)
            </div>

            <div class="editor-label">
                @Html.LabelFor(model => model.CourseName)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.CourseName, new { data_bind = "enable: isInEditMode, value: CourseName" })
                @Html.ValidationMessageFor(model => model.CourseName)
            </div>
            <div class="editor-label">
                @Html.LabelFor(model => model.StudentViewModels);
            </div>
            <div class="editor-field">

                @Html.ListBoxFor(
                    model => model.StudentViewModels,
                    new SelectList(this.Model.StudentViewModels, "ID", "Name"),
                    new
                    {
                        style = "width: 37%;",
                        data_bind = "enable: isInEditMode, options: StudentViewModels, optionsText: 'Name', value: leftStudentSelected, event: { dblclick: moveFromLeftToRight }"
                    }
                )
                @Html.ListBoxFor(
                    model => model.SelectedStudents,
                    new SelectList(this.Model.SelectedStudents, "ID", "Name"),
                    new
                    {
                        style = "width: 37%;",
                        data_bind = "enable: isInEditMode, options: SelectedStudents, optionsText: 'Name', value: rightStudentSelected, event: { dblclick: moveFromRightToLeft }"
                    }
                )
            </div>

            @Html.HiddenFor(model => model.CourseId, new { data_bind="value: CourseId" })
            @Html.HiddenFor(model => model.CourseName, new { data_bind="value: CourseName" })
            @Html.HiddenFor(model => model.StudentsSerialized, new { data_bind = "value: StudentsSerialized" })
            @Html.HiddenFor(model => model.SelectedStudentsSerialized, new { data_bind = "value: SelectedStudentsSerialized" })
        </div>

        <p>
            <input type="submit" value="Save" data-bind="enable: !isInEditMode()" /> 
            <button data-bind="enable: !isInEditMode(), click: editMode">Edit mode</button><br />
            <div>
                <button data-bind="enable: isInEditMode, click: addStudent">Add Student</button>
                <button data-bind="enable: hasChanges, click: executeCommit">Commit</button>
                <button data-bind="enable: isInEditMode, click: executeRollback">Cancel</button>
            </div>
        </p>
    </fieldset>
}

Skripte

<script src="@Url.Content("~/Scripts/jquery-1.7.2.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/knockout-2.1.0.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/knockout.mapping-latest.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/ko.editables.js")" type="text/javascript"></script>

<script type="text/javascript">
    var g = null;
    function ViewModel() {
        this.addStudent = function () {
            this.StudentViewModels.push(new Student(25, "my name" + new Date(), "my last name"));
            this.serializeLists();
        };
        this.serializeLists = function () {
            this.StudentsSerialized(ko.toJSON(this.StudentViewModels));
            this.SelectedStudentsSerialized(ko.toJSON(this.SelectedStudents));
        };
        this.leftStudentSelected = ko.observable();
        this.rightStudentSelected = ko.observable();
        this.moveFromLeftToRight = function () {
            this.SelectedStudents.push(this.leftStudentSelected());
            this.StudentViewModels.remove(this.leftStudentSelected());
            this.serializeLists();
        };
        this.moveFromRightToLeft = function () {
            this.StudentViewModels.push(this.rightStudentSelected());
            this.SelectedStudents.remove(this.rightStudentSelected());
            this.serializeLists();
        };
        this.isInEditMode = ko.observable(false);
        this.executeCommit = function () {
            this.commit();
            this.isInEditMode(false);
        };
        this.executeRollback = function () {
            if (this.hasChanges()) {
                if (confirm("Are you sure you want to discard the changes?")) {
                    this.rollback();
                    this.isInEditMode(false);
                }
            }
            else {
                this.rollback();
                this.isInEditMode(false);
            }
        };
        this.editMode = function () {
            this.isInEditMode(!this.isInEditMode());
            this.beginEdit();
        };
    }

    function Student(id, name, lastName) {
        this.ID = id;
        this.Name = name;
        this.LastName = lastName;
    }

    $(function () {
        var jsonModel = '@Html.Raw(JsonConvert.SerializeObject(this.Model))';
        var mvcModel = ko.mapping.fromJSON(jsonModel);

        var myViewModel = new ViewModel();
        g = ko.mapping.fromJS(myViewModel, mvcModel);

        g.StudentsSerialized(ko.toJSON(g.StudentViewModels));
        g.SelectedStudentsSerialized(ko.toJSON(g.SelectedStudents));

        ko.editable(g);
        ko.applyBindings(g);
    });
</script>

Hinweis: Ich habe gerade diese Zeilen hinzugefügt:

        @Html.HiddenFor(model => model.CourseId, new { data_bind="value: CourseId" })
        @Html.HiddenFor(model => model.CourseName, new { data_bind="value: CourseName" })

Da beim Senden des Formulars meine Felder deaktiviert sind und die Werte nicht an den Server übertragen wurden, habe ich einige versteckte Felder hinzugefügt, um den Trick auszuführen


Hmm sehr informativ. Aufgrund Ihrer Antwort und der Antwort von Pual habe ich fast alle meine Fragen beantwortet, außer wie man Plugins wie editierbar verwendet. Hoffentlich weiß jemand, wie ich das nutzen kann.
Chobo2

1
Ich habe gerade die Kompatibilität mit dem ko.editablesPlug-In hinzugefügt. Sie können die aktualisierte Antwort überprüfen oder, wenn Sie möchten, das gesamte Projekt herunterladen, um es lokal
auszuführen

Ich werde es überprüfen, wenn ich kann. Musste sich viel ändern, damit es funktioniert? Ich frage mich, ob ich für jedes Plugin finde, ob ich Änderungen daran vornehmen und dann meine eigene Version behalten muss.
Chobo2

Nee. Sie werden überrascht sein, es ist fast out-of-the-Box
Jupaol

1
Vielen Dank, ich habe aus Ihrer Antwort einige neue Strategien gelernt. Ein großes Lob!
Sky-Dev

23

Sie können Ihr ASP.NET MVC-Ansichtsmodell in eine Javascript-Variable serialisieren:

@model CourseVM
<script type="text/javascript">
    var model = @Html.Raw(Json.Encode(Model));
    // go ahead and use the model javascript variable to bind with ko
</script>

In der Knockout-Dokumentation finden Sie viele Beispiele , die Sie durchgehen könnten.


1
Ja, ich habe das interaktive Tutorial auf der Website durchgesehen, aber ich sehe wirklich nie etwas mit asp.net mvc zu tun. Ich sehe, dass sie auch ein Mapping-Plugin haben, aber nicht sicher sind, wie das passt. In Ihrem Beispiel, wie würden Sie es an das Knockout-Modell binden (in einem anderen Skript). Ich möchte wirklich so wenig Inline-Javascript wie möglich haben (nicht ist vorzuziehen, aber ich denke, es ist nicht möglich)
chobo2

2
Welches Problem versuchen Sie zu lösen? Wenn Sie MVC-Ansichten möchten und mit deren Verwendung zufrieden sind, können Sie dort bleiben. Wenn Sie clientseitige Datenbindungen und -manipulationen wünschen, ist KO eine gute Wahl. Sie können Ihr KO-Ansichtsmodell aus Ihrem MVC-Code generieren, wie diese Antwort zeigt. Es nimmt die VM und serialisiert sie zu JSON. Anschließend können Sie auf dem Client die Ergebnisse einem Javascript-Ansichtsmodell zuordnen. Binden Sie dann das Ansichtsmodell an die Ansicht und Sie sind fertig. Der Schlüssel ist, dass MVC und KO in keiner Weise gekoppelt werden müssen, es sei denn, Sie möchten, dass sie es sind. Es hängt alles von dem Problem ab, das Sie lösen möchten.
John Papa

1
Es ist normal, dass Sie nichts mit asp.net mvc zu tun haben. Knockout ist ein clientseitiges Framework. Es ist weder bekannt noch wichtig, welche serverseitige Sprache Sie verwenden. Diese beiden Frameworks sollten absolut entkoppelt sein.
Darin Dimitrov

@ JohnPapa - Ich mag die Art und Weise, wie ich Dinge jetzt mache, aber ich mag es auch, neue Dinge zu lernen (ich sehe, dass KO in manchen Situationen sehr nützlich sein kann). Ich weiß, dass KO ein clientseitiges Skript ist, aber für mich sehe ich, dass sie zusammenarbeiten. Derzeit generiere ich meine Ansichten mithilfe von Ansichtsmodellen und HTML-Helfern. In meinen Augen muss KO also zusammenarbeiten. Angenommen, Sie haben einen Bearbeitungsdialog. Wie würden Sie die Werte aus einer Datenbank entwerfen und in diese Felder einfügen? Wenn ich meinen Weg benutzen würde, wäre es eine Ansicht von HTML-Helfern, die ein viewModel haben. Würde das Ansichtsmodell füllen und es über die Aktionsmethode senden und verwenden.
Chobo2

1
@ chobo2, Knockout ist ein clientseitiges Framework. Es verwendet Ansichtsmodelle auf dem Client, um das MVC-Muster auf dem Client zu implementieren. Der Server ist entkoppelt. Sie können auch Ansichtsmodelle verwenden. Es sind nur 2 verschiedene Orte. Wenn Sie eine komplexe Logik haben, die Sie mithilfe von Javascript auf dem Client implementieren möchten, kann Knockout dies vereinfachen. Ansonsten brauchst du es ehrlich gesagt nicht.
Darin Dimitrov

2

Um die zusätzlichen berechneten Eigenschaften nach der Serverzuordnung zu erreichen, müssen Sie Ihre Ansichtsmodelle auf der Clientseite weiter verbessern.

Beispielsweise:

var viewModel = ko.mapping.fromJS(model);

viewModel.capitalizedName = ko.computed(function() {...}, viewModel);

Jedes Mal, wenn Sie aus unformatiertem JSON zuordnen, müssen Sie die berechneten Eigenschaften erneut anwenden.

Darüber hinaus bietet das Mapping-Plugin die Möglichkeit, ein Ansichtsmodell schrittweise zu aktualisieren, anstatt es jedes Mal neu zu erstellen, wenn Sie hin und her gehen (verwenden Sie einen zusätzlichen Parameter in fromJS):

// Every time data is received from the server:
ko.mapping.fromJS(data, viewModel);

Dadurch wird eine inkrementelle Datenaktualisierung Ihres Modells nur von Eigenschaften ausgeführt, die zugeordnet sind. Weitere Informationen hierzu finden Sie in der Mapping-Dokumentation

Sie haben in den Kommentaren zu Darins Antwort das FluentJSON- Paket erwähnt. Ich bin der Autor davon, aber sein Anwendungsfall ist spezifischer als ko.mapping. Ich würde es im Allgemeinen nur verwenden, wenn Ihre Ansichtsmodelle eine Möglichkeit sind (z. B. Server -> Client) und die Daten dann in einem anderen Format (oder überhaupt nicht) zurückgesendet werden. Oder wenn Ihr Javascript-Ansichtsmodell in einem wesentlich anderen Format als Ihr Servermodell vorliegen muss.


Hmm, dann denke ich, dass FluentJSON vielleicht nichts für mich ist, da meine Ansichtsmodelle die meiste Zeit in beide Richtungen gehen (ich sende es normalerweise über json zurück und binde es dann im Parameter action method an das Ansichtsmodell). Wissen Sie, wie ich die Plugins verwenden kann, die ich als bearbeitbar bezeichnet habe? Schließlich verliere ich jegliche Funktionalität, indem ich Mapping verwende und versuche, mein Ansichtsmodell zu verwenden, anstatt es nicht zu verwenden?
Chobo2

Ich habe keines der Plugins verwendet, bin mir also nicht sicher. Was ich in der Vergangenheit getan habe, war nur, jede Änderung zu abonnieren und einen Stapel serialisierter Ansichtsmodellzustände beizubehalten, auf die ich beim Ändern drängen und beim Rückgängigmachen einblenden würde ( siehe diese Frage ).
Paul Tyng

Das Mapping hält Sie nicht von irgendwelchen Funktionen ab. Sie müssen lediglich sicherstellen und die Konventionen beachten, wie das Mapping von und zu JS gehandhabt wird, damit alles gut zusammenspielt.
Paul Tyng

Nun, die akzeptierte Antwort auf die Frage, die Sie gestellt haben, ist im Grunde das Plugin. Das ist es, was mich verwirrt, wie Sie sehen können, dass sie ein Ansichtsmodell erstellen und dann ihre von ihnen erstellte Funktion verwenden (ko.observableArrayWithUndo ([])). Wenn ich Mapping mache, weiß ich nicht, wie ich das machen soll. Ich denke nur daran, mein eigenes Mapping zu schreiben (was ich zu diesem Zeitpunkt bezweifle, dass ich es richtig machen könnte), bei dem jede Eigenschaft rückgängig gemacht oder zugeordnet werden kann, aber dann habe ich im Grunde doppelte Ansichtsmodelle, eines für den Server und eines für den Client, und das bin ich Angst, die nicht mehr zu pflegen ist
chobo2

Ah ja, tut mir leid, ich habe über meine Antwort auf diese Frage gesprochen. Es tut mir leid, dass ich direkt verlinkt haben sollte.
Paul Tyng
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.