Compartilhar via


Parte 5: Criando uma interface do usuário dinâmica com Knockout.js

por Rick Anderson

Baixar Projeto Concluído

Criação uma interface do usuário dinâmica com Knockout.js

Nesta seção, usaremos Knockout.js para adicionar funcionalidade à exibição Administração.

Knockout.js é uma biblioteca Javascript que facilita a associação de controles HTML aos dados. Knockout.js usa o padrão MVVM (Model-View-ViewModel).

  • O modelo é a representação do lado do servidor dos dados no domínio de negócios (em nosso caso, produtos e pedidos).
  • O modo de exibição é a camada de apresentação (HTML).
  • O modelo de exibição é um objeto Javascript que contém os dados do modelo. O modelo de exibição é uma abstração de código da interface do usuário. Ele não tem conhecimento da representação HTML. Em vez disso, ele representa recursos abstratos do modo de exibição, como "uma lista de itens".

A exibição é associada a dados ao modelo de exibição. Atualizações para o modelo de exibição são refletidos automaticamente na exibição. O modelo de exibição também obtém eventos do modo de exibição, como cliques de botão, e executa operações no modelo, como a criação de um pedido.

Diagrama de interação entre os dados do H T M L, o modelo de exibição, o j son e o controlador web A P I.

Diagrama que mostra a interação entre os dados do H T M L, o modelo de exibição, o j son e o controlador web A P I. A caixa de dados H T M L é rotulada como exibição. Uma associação de dados rotulada por seta dupla vincula a caixa de dados H T M L à caixa de modelo de exibição. Uma seta dupla rotulada H T T P requests e j son model do servidor vincula o modelo de exibição ao controlador Web A P I.

Primeiro, definiremos o modelo de exibição. Depois disso, associaremos a marcação HTML ao modelo de exibição.

Adicione a seguinte seção razor a Administração.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>
}

Você pode adicionar esta seção em qualquer lugar no arquivo. Quando o modo de exibição é renderizado, a seção aparece na parte inferior da página HTML, logo antes da marca /body> de fechamento<.

Todo o script desta página entrará na marca de script indicada pelo comentário:

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

Primeiro, defina uma classe de modelo de exibição:

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

ko.observableArray é um tipo especial de objeto em Knockout, chamado de observável. Na documentação doKnockout.js: um observável é um "objeto JavaScript que pode notificar os assinantes sobre as alterações". Quando o conteúdo de uma alteração observável, o modo de exibição é atualizado automaticamente para corresponder.

Para preencher a products matriz, faça uma solicitação AJAX para a API Web. Lembre-se de que armazenamos o URI base para a API no recipiente de exibição (consulte a Parte 4 do tutorial).

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

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

Em seguida, adicione funções ao modelo de exibição para criar, atualizar e excluir produtos. Essas funções enviam chamadas AJAX para a API Web e usam os resultados para atualizar o modelo de exibiçã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 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 conecta o modelo de exibição à exibição.

Agora que temos um modelo de exibição, podemos criar as associações. Em Knockout.js, você faz isso adicionando data-bind atributos a elementos HTML. Por exemplo, para associar uma lista HTML a uma matriz, use a foreach associação :

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

A foreach associação itera por meio da matriz e cria elementos filho para cada objeto na matriz. As associações nos elementos filho podem se referir às propriedades nos objetos da matriz.

Adicione as seguintes associações à lista "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 escopo da associação foreach . Isso significa que Knockout renderizará o elemento uma vez para cada produto na products matriz. Todas as associações dentro do <li> elemento referem-se a essa instância do produto. Por exemplo, $data.Name refere-se à Name propriedade no produto.

Para definir os valores das entradas de texto, use a value associação . Os botões são associados a funções na exibição de modelo, usando a associação click . A instância do produto é passada como um parâmetro para cada função. Para obter mais informações, a documentação doKnockout.js tem boas descrições das várias associações.

Em seguida, adicione uma associação para o evento submit no formulário Adicionar Produto:

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

Essa associação chama a create função no modelo de exibição para criar um novo produto.

Este é o código completo para a exibição Administração:

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

Execute o aplicativo, faça logon com a conta administrador e clique no link "Administração". Você deve ver a lista de produtos e ser capaz de criar, atualizar ou excluir produtos.