Partilhar via


Parte 5: Criar uma interface dinâmica com Knockout.js

por Rick Anderson

Descarregar Projeto Concluído

Criar uma interface dinâmica com Knockout.js

Nesta secção, vamos usar Knockout.js para adicionar funcionalidade à vista de Administrador.

Knockout.js é uma biblioteca Javascript que facilita a atribuição de controlos HTML a dados. Knockout.js utiliza o padrão Model-View-ViewModel (MVVM).

  • O modelo é a representação do lado do servidor dos dados no domínio empresarial (no nosso caso, produtos e encomendas).
  • A vista é a camada de apresentação (HTML).
  • O view-model é um objeto Javascript que contém os dados do modelo. O modelo de visualização é uma abstração de código da interface. Não tem conhecimento da representação HTML. Em vez disso, representa características abstratas da vista, como "uma lista de itens".

A visualização está vinculada ao modelo de visualização. As atualizações ao modelo de visualização são automaticamente refletidas na visualização. O modelo de visualização também recebe eventos da vista, como cliques de botões, e realiza operações no modelo, como criar um pedido.

Diagrama da interação entre dados H T M L, o modelo de visualização, j son e o controlador Web A P I.

Diagrama que mostra a interação entre os dados H T M L, o modelo de visualização, j son e o controlador Web A P I. A caixa de dados H T M L está rotulada como vista. Uma seta dupla rotulada como data binding liga a caixa de dados H T M L à caixa do modelo de visualização. Uma seta dupla rotulada com pedidos HTTP e modelo JSON do servidor liga o modelo de vista ao controlador API Web.

Primeiro, vamos definir o modelo de visualização. Depois disso, vamos associar a marcação HTML ao modelo de visualização.

Adicione a seguinte secção Razor ao Admin.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>
}

Pode adicionar esta secção em qualquer parte do ficheiro. Quando a visualização é renderizada, a secção aparece no final da página HTML, mesmo antes da etiqueta de encerramento </body> .

Todo o script desta página irá dentro da tag script indicada pelo comentário:

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

Primeiro, defina uma classe view-model:

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

ko.observableArray é um tipo especial de objeto em Knockout, chamado observável. Segundo a documentação Knockout.js: Um observável é um "objeto JavaScript que pode notificar assinantes sobre alterações." Quando o conteúdo de um observável muda, a interface é automaticamente atualizada em conformidade.

Para preencher o products array, faça um pedido AJAX à API web. Lembre-se que armazenámos o URI base da API no "view bag" (ver Parte 4 do tutorial).

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

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

De seguida, adicione funções ao modelo de visualização para criar, atualizar e eliminar produtos. Estas funções submetem chamadas AJAX para a API web e usam os resultados para atualizar o modelo de visualização.

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);
}

Agora a parte mais importante: Quando o DOM estiver totalmente carregado, chame a função ko.applyBindings e passe uma nova instância do ProductsViewModel:

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

O método ko.applyBindings ativa o Knockout e liga o modelo de visualização à vista.

Agora que temos um modelo de visualização, podemos criar as ligações. Em Knockout.js, faz-se isto adicionando data-bind atributos a elementos HTML. Por exemplo, para associar uma lista HTML a um array, use a foreach vinculação.

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

A foreach ligação itera através do array e cria elementos filhos para cada objeto do array. As ligações nos elementos filhos podem referenciar propriedades nos objetos da matriz.

Adicione as seguintes associações à lista de "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>

O <li> elemento ocorre dentro do âmbito da ligação foreach . Isto significa que o Knockout irá renderizar o elemento uma vez para cada produto no products array. Todas as ligações dentro do <li> elemento referem-se àquela instância do produto. Por exemplo, $data.Name refere-se à propriedade Name do produto.

Para definir os valores das entradas de texto, use o value binding. Os botões estão associados a funções no modelo-vista, usando a vinculação click. A instância do produto é passada como parâmetro a cada função. Para mais informações, a documentação Knockout.js tem boas descrições das várias ligações.

De seguida, adicione uma ligação para o evento de submissão no formulário Adicionar Produto:

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

Esta ligação chama a função create no view model para criar um novo produto.

Aqui está o código completo para a vista de Administrador:

@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>

Executa a aplicação, inicia sessão com a conta de Administrador e clica no link "Administrador". Deverias ver a lista de produtos e conseguir criar, atualizar ou eliminar produtos.