.NET

17 jun, 2016

ASP .NET – Single Page Application(SPA) usando AngularJS com Web API – Parte 06

Publicidade

Neste artigo eu vou mostrar como criar uma aplicação ASP .NET Single Page Application usando os recursos do AngularJS com Web API: criando um serviço.

Na quinta parte do artigo criamos o serviço definido em filmeService de forma que encapsulasse as funcionalidades da nossa Web API representada pelo controller FilmeController.

Neste artigo, vamos implementar as funcionalidades para deletar, editar e criar filmes em nossa aplicação SPA.

Recursos usados:

Nota: Baixe e use a versão Community 2015 do VS . Ela é grátis e é equivalente a versão profissional.

Deletando filmes

Agora vamos permitir que o usuário possa deletar um filme em nossa aplicação. Para isso, abra a solução Filmoteca, criada no artigo anterior no VS Community 2015 (Open Project). Depois abra o arquivo lista.html e inclua a linha de código para incluir um botão de comando, conforme o código a seguir:

<div ng-controller="listaController">
    <table class="table">
        <tr>
            <th>Título</th>
        </tr>
        <tr ng-repeat="filme in filmes">
            <td>{{filme.Titulo}}</td>
            <td>
                <a class="btn btn-primary" href="#/detalhes/{{filme.Id}}">Detalhes</a>
                <button class="btn btn-danger" ng-click="deleta(filme)">Deletar</button>
            </td>
        </tr>
    </table>
</div>

Nossa view lista.html está usando alguns recursos do bootstrap para definir estilos para o button Deletar e para o link Detalhes.

Nesta view, incluímos um button HTML onde temos uma diretiva ng-click que aciona a function deleta(filme), passando o filme associado.

Precisamos, então, alterar o código do controller listaController incluindo a function deleta(filme) conforme mostra o código a seguir:

(function (app) {
    var listaController = function ($scope, filmeService)
    {
        filmeService
            .getFilmes()
            .success(function (data) {
            $scope.filmes = data;
            });
        $scope.deleta = function (filme) {
            filmeService.deletar(filme)
            .success(function () {
                removerFilmePorId(filme.Id);
            });
        };
        var removerFilmePorId = function (id) {
            for (var i = 0; i < $scope.filmes.length; i++) {
                if ($scope.filmes[i].Id == id) {
                    $scope.filmes.splice(i, 1);
                    break;
                }
            }
        };
    };
    app.controller("listaController", listaController)
}(angular.module("filmoteca")));

Temos agora duas novas functions no controller listaController. A primeira é a function deleta anexado ao objeto $scope e, por isso mesmo, este método é chamado pela diretiva ng-click que usa o serviço filmeService para deletar o filme.

Quando a chamada é feita com sucesso, é feito uma chamada à function removerFilmePorId(), que não está associada ao objeto $scope e, por isso, é uma implementação privada dentro do controlador. Esta function localiza e deleta o filme pelo seu id no modelo e o remove do array dos filmes.

Abaixo vemos a aparência da view lista.html:

asp_spaa611

Editando e criando filmes

Vamos agora implementar a edição e a criação de um novo filme. Podemos fazer isso de diversas formas e neste exemplo vamos adotar a seguinte abordagem:

  • No arquivo lista.html, que exibe a lista de filmes e o botões – Detalhes e Deletar – vamos incluir um novo botão – Novo Filme – e vincular a esse botão uma diretiva ng-click que chama uma function criar();
  • Vamos criar, então, um novo arquivo HTML, chamado edita.html, que vai funcionar como um formulário para criar um novo filme e para editar um filme existente. Este arquivo funciona como uma partial view e deverá ser incluído na view lista.html e também na viewdetalhes.html usando a diretiva ng-include.

Dessa forma, a view edita.html vai compartilhar a funcionalidade de incluir um filme e editar um filme.

Clique com o botão direito do mouse na pasta Html e, a seguir, em Add -> New Item e selecione o template HTML page e informe o nomeedita.html. A seguir, inclua o código abaixo nesta view:

<div ng-controller="editaController">
    <form ng-show="isEditavel()">
        <fieldset>
            <div class="form-group">
                <label for="titulo">
                    Titulo
                </label>
                <input id="titulo" type="text" ng-model="editar.filme.Titulo" required class="form-control" />
            </div>
            <div class="form-group">
                <label for="anoLancamento">
                    Ano de Lançamento
                </label>
                <input id="anoLancamento" type="number" ng-model="editar.filme.AnoLancamento" required min="1900" max="2050" class="form-control" />
            </div>
            <div class="form-group">
                <label for="duracao">
                    Duração
                </label>
                <input id="duracao" type="number" ng-model="editar.filme.Duracao" required min="10" max="500" class="form-control" />
            </div>
            <button class="btn btn-primary" ng-click="salvar()">Salvar</button>
            <button class="btn btn-danger" ng-click="cancelar()">Cancelar</button>
        </fieldset>
    </form>
</div>

É muito importante entender esta view :

  • Nesta view, usamos a diretiva ng-controller=”editaController”, que indica que o controlador editaController é responsável pelas functions usadas nesta view. Como este controlador ainda não existe, vamos ter que criá-lo posteriormente;
  • A diretiva ng-show é usada para ocultar ou mostrar uma seção do DOM baseado na expressão usada: ng-show=”isEditavel()” que deve retornar true ou false; Neste caso, o elemento form somente será exibido quando a function isEditavel() retornar true a partir do model; Estamos usando esta diretiva para ocultar o formulário, exibindo-o somente para criar ou editar um novo filme;
  • A diretiva ng-model define o two-way-binding entre o model e os elementos do formulário (textarea, select, input, etc); No formulário, definimos as seguintes diretivas ng-model:
  1. ng-model=”editar.filme.Titulo”
  2. ng-model=”editar.filme.AnoLancamento”
  3. ng-model=”editar.filme.Duracao”

Fazendo assim, criamos essas propriedades no objeto $scope e permitimos que elas sejam acessadas pelo controlador editaController que iremos criar.

Perceba que o objetivo das diretivas é fazer a vinculação entre o model e a view. O model (ou controller) nunca manipula diretamente os elementos DOM; quem faz isso são as diretivas. Fazendo uma alteração no model ela se reflete na view.

Vamos, então, alterar a view lista.html incluindo o botão para criar um novo filme e usar a diretiva ng-include para incluir a view edita.html:

<div ng-controller="listaController">
    <table class="table">
        <tr>
            <th>Título</th>
        </tr>
        <tr ng-repeat="filme in filmes">
            <td>{{filme.Titulo}}</td>
            <td>
                <a class="btn btn-primary" href="#/detalhes/{{filme.Id}}">Detalhes</a>
                <button class="btn btn-danger" ng-click="deleta(filme)">Deletar</button>
            </td>
        </tr>
    </table>
   <button class="btn btn-success" ng-click="criar()">Novo Filme</button>
   <div ng-include="'/Cliente/Html/edita.html'"></div>
</div>

Agora a view lista.html pode invocar o método criar() que será definido no model.

A diretiva ng-include faz a inclusão da view edita.html nesta view, exibindo o formulário para o usuário digitar as informações do novo livro.

Observe que usamos aspas simples(”) no interior da diretiva para chamar a página edita.html, assim asseguramos que o caminho informado será reconhecido como um literal string.

A function criar() definida deverá ser criada no controlador listaController, que é responsável por esta view. Altere o arquivolistaController.js incluindo a function criar():

(function (app) {
    var listaController = function ($scope, filmeService)
    {
        filmeService
            .getFilmes()
            .success(function (data) {
            $scope.filmes = data;
            });
        $scope.criar = function () {
            $scope.editar = {
                filme: {
                    Titulo: "",
                    Duracao: 0,
                    AnoLancamento: new Date().getFullYear()
                }
            };
        };
        $scope.deleta = function (filme) {
            filmeService.deletar(filme)
            .success(function () {
                removerFilmePorId(filme.Id);
            });
        };
        var removerFilmePorId = function (id) {
            for (var i = 0; i < $scope.filmes.length; i++) {
                if ($scope.filmes[i].Id == id) {
                    $scope.filmes.splice(i, 1);
                    break;
                }
            }
        };
    };
    app.controller("listaController", listaController)
}(angular.module("filmoteca")));

Da mesma forma, vamos alterar a view detalhes.html para incluir um botão de comando vinculado a diretiva ng-click para editar os dados e outro para retornar para a lista. Vamos usar também a diretiva ng-include para incluir a view edita.html na view detalhes para exibir o formulário para editar os dados. Abaixo temos o código da view detalhes.html alterado:

<div ng-controller="detalhesController">
    <h2>
       Filme :  {{filme.Titulo}}
    </h2>
    <div>
       <h3> Lançamento em : {{filme.AnoLancamento}} </h3>
    </div>
    <div>
       <h3>{{filme.Duracao}} minutos de duração.</h3>
    </div>
    <a class="btn btn-primary" ng-click="editar()">Editar</>
    <a class="btn btn-success" href="#/">Retorna</a>
    <div ng-include="'/Cliente/Html/edita.html'"></div>
</div>

Para concluir esta parte do artigo, vamos definir a function editar() no controlador detalhesController, conforme mostra o código a seguir:

(function (app) {
    var detalhesController = function ($scope, $routeParams, filmeService) {
        var id = $routeParams.id;
        filmeService
            .getFilmePorId(id)
            .success(function (data) {
                $scope.filme = data;
            });
        $scope.editar = function () {
            $scope.editar.filme = angular.copy($scope.filme);
        };
    };
        app.controller("detalhesController", detalhesController);
}(angular.module("filmoteca")));

A função editar() apenas faz uma cópia do filme selecionado no escopo para a propriedade filme, atualizando a view e exibindo os dados do filme selecionado para edição.

Executando o projeto agora, teremos o seguinte resultado:

1. A página inicial exibindo a view lista.html:

asp_spaa612

2. A exibição da view detalhes.html quando o usuário clica no botão Detalhes:

asp_spaa614

3. A exibição do formulário representado pela view edita.html, exibindo os dados do filme selecionado quando o usuário clica no botão Editar:

asp_spaa615

4. A exibição do formulário representado pela view edita.html quando o usuário clica no botão Novo Filme:

asp_spaa613

Na próxima parte do artigo, vamos implementar as funcionalidades do controlador editaController e definir as functions para criar um novo filme e alterar dados do filme selecionado.