Condividi tramite


Parte 5: Creazione di un'interfaccia utente dinamica con Knockout.js

di Rick Anderson

Scaricare il progetto completato

Creazione di un'interfaccia utente dinamica con Knockout.js

In questa sezione si userà Knockout.js per aggiungere funzionalità alla visualizzazione Amministrazione.

Knockout.js è una libreria Javascript che semplifica l'associazione di controlli HTML ai dati. Knockout.js usa il modello Model-View-ViewModel (MVVM).

  • Il modello è la rappresentazione lato server dei dati nel dominio aziendale (in questo caso, prodotti e ordini).
  • La visualizzazione è il livello presentazione (HTML).
  • Il modello di visualizzazione è un oggetto Javascript che contiene i dati del modello. Il modello di visualizzazione è un'astrazione del codice dell'interfaccia utente. Non ha alcuna conoscenza della rappresentazione HTML. Rappresenta invece le caratteristiche astratte della visualizzazione, ad esempio "un elenco di elementi".

La vista è associata ai dati al modello di visualizzazione. Aggiornamenti al modello di visualizzazione vengono automaticamente riflesse nella visualizzazione. Il modello di visualizzazione ottiene anche gli eventi dalla visualizzazione, ad esempio i clic sui pulsanti, ed esegue operazioni sul modello, ad esempio la creazione di un ordine.

Diagramma dell'interazione tra i dati H T M L, il modello di visualizzazione, j son e il controller Web A P I.

Diagramma che mostra l'interazione tra i dati H T M L, il modello di visualizzazione, j son e il controller Web A P I. La casella dati H T M L è etichettata come visualizzazione. Un data binding con etichetta doppia freccia collega la casella di dati H T M L alla casella del modello di visualizzazione. Una doppia freccia con etichetta H T T P requests e j son model from server collega il modello di visualizzazione al controller Web A P I.

Prima di tutto si definirà il modello di visualizzazione. Successivamente, il markup HTML verrà associato al modello di visualizzazione.

Aggiungere la sezione Razor seguente a Amministrazione.cshtml:

@section Scripts {
  @Scripts.Render("~/bundles/jqueryval")
  <script type="text/javascript" src="@Url.Content("~/Scripts/knockout-2.1.0.js")"></script> 
  <script type="text/javascript">
  // View-model will go here
  </script>
}

È possibile aggiungere questa sezione in qualsiasi punto del file. Quando viene eseguito il rendering della visualizzazione, la sezione viene visualizzata nella parte inferiore della pagina HTML, subito prima del tag /body> di chiusura<.

Tutti gli script per questa pagina verranno inclusi nel tag di script indicato dal commento:

<script type="text/javascript">
  // View-model will go here
  </script>

Definire prima di tutto una classe del modello di visualizzazione:

function ProductsViewModel() {
    var self = this;
    self.products = ko.observableArray();
}

ko.observableArray è un tipo speciale di oggetto in Knockout, chiamato osservabile. Dalla documentazione diKnockout.js: un oggetto osservabile è un "oggetto JavaScript in grado di notificare ai sottoscrittori le modifiche". Quando il contenuto di una modifica osservabile, la visualizzazione viene aggiornata automaticamente in modo che corrisponda.

Per popolare la products matrice, effettuare una richiesta AJAX all'API Web. Tenere presente che è stato archiviato l'URI di base per l'API nel contenitore di visualizzazioni (vedere la parte 4 dell'esercitazione).

function ProductsViewModel() {
    var self = this;
    self.products = ko.observableArray();

    // New code
    var baseUri = '@ViewBag.ApiUrl';
    $.getJSON(baseUri, self.products);
}

Aggiungere quindi funzioni al modello di visualizzazione per creare, aggiornare ed eliminare prodotti. Queste funzioni inviano chiamate AJAX all'API Web e usano i risultati per aggiornare il modello di visualizzazione.

function ProductsViewModel() {
    var self = this;
    self.products = ko.observableArray();

    var baseUri = '@ViewBag.ApiUrl';

    // New code
    self.create = function (formElement) {
        // If the form data is valid, post the serialized form data to the web API.
        $(formElement).validate();
        if ($(formElement).valid()) {
            $.post(baseUri, $(formElement).serialize(), null, "json")
                .done(function (o) { 
                    // Add the new product to the view-model.
                    self.products.push(o); 
                });
        }
    }

    self.update = function (product) {
        $.ajax({ type: "PUT", url: baseUri + '/' + product.Id, data: product });
    }

    self.remove = function (product) {
        // First remove from the server, then from the view-model.
        $.ajax({ type: "DELETE", url: baseUri + '/' + product.Id })
            .done(function () { self.products.remove(product); });
    }

    $.getJSON(baseUri, self.products);
}

Ora la parte più importante: quando il DOM è pieno, chiamare la funzione ko.applyBindings e passare una nuova istanza di ProductsViewModel:

$(document).ready(function () {
    ko.applyBindings(new ProductsViewModel());
})

Il metodo ko.applyBindings attiva Knockout e collega il modello di visualizzazione alla visualizzazione.

Ora che è disponibile un modello di visualizzazione, è possibile creare le associazioni. In Knockout.js eseguire questa operazione aggiungendo data-bind attributi agli elementi HTML. Ad esempio, per associare un elenco HTML a una matrice, usare l'associazione foreach :

<ul id="update-products" data-bind="foreach: products">

L'associazione foreach scorre la matrice e crea elementi figlio per ogni oggetto nella matrice. I binding sugli elementi figlio possono fare riferimento alle proprietà degli oggetti matrice.

Aggiungere le associazioni seguenti all'elenco "update-products":

<ul id="update-products" data-bind="foreach: products">
    <li>
        <div>
            <div class="item">Product ID</div> <span data-bind="text: $data.Id"></span>
        </div>
        <div>
            <div class="item">Name</div> 
            <input type="text" data-bind="value: $data.Name"/>
        </div> 
        <div>
            <div class="item">Price ($)</div> 
            <input type="text" data-bind="value: $data.Price"/>
        </div>
        <div>
            <div class="item">Actual Cost ($)</div> 
            <input type="text" data-bind="value: $data.ActualCost"/>
        </div>
        <div>
            <input type="button" value="Update" data-bind="click: $root.update"/>
            <input type="button" value="Delete Item" data-bind="click: $root.remove"/>
        </div>
    </li>
</ul>

L'elemento <li> si verifica nell'ambito dell'associazione foreach . Ciò significa che Knockout eseguirà il rendering dell'elemento una volta per ogni prodotto nella products matrice. Tutte le associazioni all'interno dell'elemento <li> fanno riferimento a tale istanza del prodotto. Ad esempio, $data.Name fa riferimento alla Name proprietà nel prodotto.

Per impostare i valori degli input di testo, usare l'associazione value . I pulsanti sono associati alle funzioni nella visualizzazione modello, usando l'associazione click . L'istanza del prodotto viene passata come parametro a ogni funzione. Per altre informazioni, la documentazione diKnockout.js contiene descrizioni valide delle varie associazioni.

Aggiungere quindi un'associazione per l'evento di invio nel modulo Aggiungi prodotto:

<form id="addProduct" data-bind="submit: create">

Questa associazione chiama la create funzione nel modello di visualizzazione per creare un nuovo prodotto.

Ecco il codice completo per la visualizzazione Amministrazione:

@model ProductStore.Models.Product

@{
    ViewBag.Title = "Admin";
}

@section Scripts {
  @Scripts.Render("~/bundles/jqueryval")
  <script type="text/javascript" src="@Url.Content("~/Scripts/knockout-2.0.0.js")"></script> 
  <script type="text/javascript">
      function ProductsViewModel() {
          var self = this;
          self.products = ko.observableArray();

          var baseUri = '@ViewBag.ApiUrl';

          self.create = function (formElement) {
              // If valid, post the serialized form data to the web api
              $(formElement).validate();
              if ($(formElement).valid()) {
                  $.post(baseUri, $(formElement).serialize(), null, "json")
                      .done(function (o) { self.products.push(o); });
              }
          }

          self.update = function (product) {
              $.ajax({ type: "PUT", url: baseUri + '/' + product.Id, data: product });
          }

          self.remove = function (product) {
              // First remove from the server, then from the UI
              $.ajax({ type: "DELETE", url: baseUri + '/' + product.Id })
                  .done(function () { self.products.remove(product); });
          }

          $.getJSON(baseUri, self.products);
      }

      $(document).ready(function () {
          ko.applyBindings(new ProductsViewModel());
      })
  </script>
}

<h2>Admin</h2>
<div class="content">
    <div class="float-left">
    <ul id="update-products" data-bind="foreach: products">
        <li>
            <div>
                <div class="item">Product ID</div> <span data-bind="text: $data.Id"></span>
            </div>
            <div>
                <div class="item">Name</div> 
                <input type="text" data-bind="value: $data.Name"/>
            </div> 
            <div>
                <div class="item">Price ($)</div> 
                <input type="text" data-bind="value: $data.Price"/>
            </div>
            <div>
                <div class="item">Actual Cost ($)</div> 
                <input type="text" data-bind="value: $data.ActualCost"/>
            </div>
            <div>
                <input type="button" value="Update" data-bind="click: $root.update"/>
                <input type="button" value="Delete Item" data-bind="click: $root.remove"/>
            </div>
        </li>
    </ul>
    </div>

    <div class="float-right">
    <h2>Add New Product</h2>
    <form id="addProduct" data-bind="submit: create">
        @Html.ValidationSummary(true)
        <fieldset>
            <legend>Contact</legend>
            @Html.EditorForModel()
            <p>
                <input type="submit" value="Save" />
            </p>
        </fieldset>
    </form>
    </div>
</div>

Eseguire l'applicazione, accedere con l'account Amministratore e fare clic sul collegamento "Amministrazione". Verrà visualizzato l'elenco dei prodotti e sarà possibile creare, aggiornare o eliminare prodotti.