Arquivos da categoria: AngularJS

O que é: SPA – Single Page Application e REST/RESTFul

SPASPA – Single Page Application é uma novo modelo de desenvolvimento de aplicações Web e mobile que vem ganhando destaque em grandes empresas como Microsoft, Google, Twitter, Facebook, etc.

SPA basicamente significa codificar menos no server-side e mais no client-side. Ou seja, a aplicação estará contida toda ou quase toda no cliente (dentro do navegador Web). É praticamente uma aplicação Desktop rodando sob o navegador.

Vantagem:

1 – balanceamento da responsabilidade da execução entre cliente e servidor (agora não é só mais responsabilidade do servidor);
2 – menos código do servidor, e mais responsabilidade no cliente;
3 – melhorar a experiência ao usuário (UX) criando interface com usabilidade moderna e de fácil entendimento do usuário;
4 – menor consumo de banda, pois as cargas de dados são feitas por demanda e por AJAX.

O grande ator de app SPA é o código Javascript executado no cliente. Toda a aplicação pode ser construída simplesmente manipulando o DOM – Document Object Model de forma nativa, ou com o uso de bibliotecas e frameworks Javascript que auxiliam na construção da aplicação. Estas bibliotecas e frameworks fornecem recursos para manipulação dinâmica do DOM, definição de templates de tela, chamadas assincronas ao servidor, organização do código Javascript, etc. Dentres as diversas bibliotecas JS que surgem a todo momento, as mais difundidas na comunidade de progamadores estão: BACKBONE, EMBER, ANGULARJS e KNOCKOUT.

No lado servidor, temos a execução das linguagens tradicionais como PHP, ASP.NET, JSP, etc, trabalhando também de forma tradicional, servindo arquivos, acessando a banco de dados, tratando as regras de negócios que não podem estar no código JS por questões de segurança. E é neste lado (servidor) que podemos utilizar a arquitetura REST – Representational State Transfer para fornecer serviços do servidor para nossa aplicação SPA. É comum encontrar aplicação SPA utilizando serviços RESTFul. Uma aplicação no servidor que utiliza a arquitetura REST para servir serviços, então é chamada de RESTFul.

Ao construir uma aplicação utilizando a arquitetura REST, o protocolo HTTP é usado em sua essência, utilizando os verbos (ou métodos de requisição ao servidor): GET, POST, PUT e DELETE (estes são os mais comuns), e cada um deles indica uma determinada ação a ser executada em um recurso específico do servidor.

  • GET: Está requisitando ao serviço um determinado recurso, por exemplo, uma listagem de dados;
  • POST: Indica ao serviço que a ele deve receber o recurso que está sendo enviado e adicionar em algum repositório;
  • PUT: Indica que ao serviço que o recurso que está sendo enviado deve ser alterado se ele já existir, ou ainda, pode ser adicionado caso ele ainda não exista;
  • DELETE: Indica que o serviço deve excluir o recurso.

Pensando em banco de dados, temos o seguinte entendimento:

  • GET: Recupera dados [select];
  • POST: Realiza a inserção de dados [insert];
  • PUT: Realiza a alteração de dados [update];
  • DELETE: Realiza a exclusão de dados [delete].

Iniciando em Single Page Application – SPA

SPASPA – Single Page Application é uma novo modelo de desenvolvimento de aplicações Web e mobile que vem ganhando destaque em grandes empresas como Microsoft, Google, Twitter, Facebook, etc.

SPA basicamente significa codificar menos no server-side e mais no client-side. Ou seja, a aplicação estará contida toda ou quase toda no cliente (dentro do navegador Web). É praticamente uma aplicação Desktop rodando sob o navegador.

Vantagem:

1 – balanceamento da responsabilidade da execução entre cliente e servidor (agora não é só mais responsabilidade do servidor);
2 – menos código do servidor, e mais responsabilidade no cliente;
3 – melhorar a experiência ao usuário (UX) criando interface com usabilidade moderna e de fácil entendimento do usuário;
4 – menor consumo de banda, pois as cargas de dados são feitas por demanda e por AJAX.

O grande ator de app SPA é o código Javascript executado no cliente. Toda a aplicação pode ser construída simplesmente manipulando o DOM – Document Object Model de forma nativa, ou com o uso de bibliotecas e frameworks Javascript que auxiliam na construção da aplicação. Estas bibliotecas e frameworks fornecem recursos para manipulação dinâmica do DOM, definição de templates de tela, chamadas assincronas ao servidor, organização do código Javascript, etc. Dentres as diversas bibliotecas JS que surgem a todo momento, as mais difundidas na comunidade de progamadores estão: BACKBONE, EMBER, ANGULARJS e KNOCKOUT.

No lado servidor, temos a execução das linguagens tradicionais como PHP, ASP.NET, JSP, etc, trabalhando também de forma tradicional, servindo arquivos, acessando a banco de dados, tratando as regras de negócios que não podem estar no código JS por questões de segurança. E é neste lado (servidor) que podemos utilizar a arquitetura REST – Representational State Transfer para fornecer serviços do servidor para nossa aplicação SPA. É comum encontrar aplicação SPA utilizando serviços RESTFul. Uma aplicação no servidor que utiliza a arquitetura REST para servir serviços, então é chamada de RESTFul.

Ao construir uma aplicação utilizando a arquitetura REST, o protocolo HTTP é usado em sua essência, utilizando os verbos (ou métodos de requisição ao servidor): GET, POST, PUT e DELETE (estes são os mais comuns), e cada um deles indica uma determinada ação a ser executada em um recurso específico do servidor.

  • GET: Está requisitando ao serviço um determinado recurso, por exemplo, uma listagem de dados;
  • POST: Indica ao serviço que a ele deve receber o recurso que está sendo enviado e adicionar em algum repositório;
  • PUT: Indica que ao serviço que o recurso que está sendo enviado deve ser alterado se ele já existir, ou ainda, pode ser adicionado caso ele ainda não exista;
  • DELETE: Indica que o serviço deve excluir o recurso.

Pensando em banco de dados, temos o seguinte entendimento:

  • GET: Recupera dados [select];
  • POST: Realiza a inserção de dados [insert];
  • PUT: Realiza a alteração de dados [update];
  • DELETE: Realiza a exclusão de dados [delete].

WebAPI é o nome dado a solução da Microsoft dentro do .NET Framework para o desenvolvimento de serviços que utilizam o conceito REST.

Criando o projeto

No VisualStudio 2013, ao criar um projeto Web, está disponível opção para seleção do template WebAPI, como é a ideia deste post é relatar a criação de app SPA, então o template selecionado deverá ser Single Page Application, que é um projeto WebAPI preparado para receber as programações SPA:

projeto_tipo_spa

Sugestão da arquitetura do projeto:

spa_webapi_arqproj

 

  • pasta app: contém os arquivos que formam a aplicação que rodará no cliente, de fato a Single Page Application;
  • pasta app\controllers: controllers do angularjs;
  • pasta app\view: views do angularjs;
  • app\app.js: configuração da aplicação no cliente;
  • pasta App_Start: classes de configuração da aplicação no servidor;
  • pasta Content: CSS da aplicação utilizando nas views (app\views);
  • pasta Controllers: Classes controladoras a nível de servidor. É de fato os serviços RESTful;
  • pasta Script: Arquivos JS da aplicação;
  • index.html: Raiz da aplicação. Será o único arquivo HTML enviado do servidor ao cliente.

No arquivo WebApiConfig.cs (da pasta App_Start) contém a configuração das rotas da aplicação:

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

Toda chamada a um método terá a URL assim: http://www.meusite.com.br/api/metodohttp/parametro.

Na configuração da api é importante padronizar o tipo de entrada e saída de dados. Para padronizar como JSON fica assim:

//padronizar JSON como retorno
config.Formatters.Remove(config.Formatters.XmlFormatter);

// Use camel case para serializar/deserializar JSON data.
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));

Um projeto WebAPI ou SPA segue praticamente a mesma estrutura do projeto MVC. A diferença está na herança das classes Controllers, pois ao invés de ser herdadas da classe Controller, são herdadas da classe abstrata ApiController.

Esta classe dispõem dos recursos necessários para o desenvolvimento de serviços RESTful. Nela estarão os métodos implementados para receber requisições de acordo com os verbos HTTP: GET, POST, PUT e DELETE.

Criando um controller

Toda classe controller deve estar na pasta Controllers e deve ter como sufixo a palavra “controller”:

  • ClienteController
  • PessoaController
  • ProdutoController

Para usar o assistente para criar a classe controller, basta adicionar a classe a partir do menu de contexto (botão direito do mouse) da pasta Controller:

spa_webapi_controller

Exemplo de classe gerada pelo assistente (o método GET foi alterado):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace SPAWebAPI.Controllers
{
    public class ClienteController : ApiController
    {
        // GET api/cliente
        public object Get()
        {
            return new { a = 1, b = 2};
        }

        // GET api/cliente/5
        public string Get(int id)
        {
            return "value";
        }

        // POST api/cliente
        public void Post([FromBody]string value)
        {
        }

        // PUT api/cliente/5
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/cliente/5
        public void Delete(int id)
        {
        }
    }
}

Invocando um método da classe ClienteController com AngularJS

var req = $http({
    url: '/api/Cliente'
});

req.success(function (data, status, headers, config, statusText) {

    console.log(data.a);
    console.log(data.b);

});

req.error(function (data, status, headers, config, statusText) {
    console.log(status);
});

AngularJS – Rotas

pic_angularOlá pessoal. Dando continuidade ao meu estudo sobre o angular, agora vamos de rota.

Numa aplicação SPA – Single Page Application usando o AngularJS, a navegação entre as views da app ocorrem sem requisições ao servidor, e baseada em rotas interna da própria app.

Para criar rotas em nossa app, o cenário perfeito é ter um arquivo principal de configuração. Por exemplo: app.js:

//criando um módulo global app com dependência ao pacote ngRoute
var app = angular.module('app', ['ngRoute']);

//definindo as rotas
app.config(function ($routeProvider, $locationProvider) {

    // remove o # da url, padrão
    $locationProvider.html5Mode(true);

    $routeProvider.when('/', { templateUrl: '/Views/lancamentos.html' });

    $routeProvider.when('/index.html', { templateUrl: '/Views/home.html' });

    $routeProvider.when('/lancamentos', { templateUrl: '/Views/lancamentos.html'});

    $routeProvider.when('/tp-lancamento', { templateUrl: '/Views/tp-lancamento.html'});

});

O objeto $routeProvider em seu método WHEN faz o registro da rota, sendo o primeiro parâmetro a rota de fato e o segundo, um objeto literal indicando da propriedade templateUrl o destino da rota. Por exemplo, toda chamada da app que ocorrer para “/lancamentos”, o conteúdo apresentado será o contido em “/Views/lancamentos.html”.

O link HTML para chamar o conteúdo da rota ficará assim:

<ul>
    <li><a href="lancamentos">Lançamentos</a></li>
    <li><a href="tp-lancamento">Tipos de Lançamento</a></li>
</ul>

O resultado do redirecionamento é o conteúdo do arquivo HTML referenciado pela rota. Este conteúdo deve ser depositado num contêiner que é marcado pela diretiva ng-view.

Exemplo:

<head>
    <script src="angular.min.js"></script>
    <script src="angular-route.min.js"></script>
    <script src="app.js"></script>
    <script src="Controllers/tpLancamento.js"></script>
    <script src="Controllers/lancamentos.js"></script>
</head>
<body>
   <ul>
       <li><a href="lancamentos">Lançamentos</a></li>
       <li><a href="tp-lancamento">Tipos de Lançamento</a></li>
   </ul>
   
   <div ng-view>
       <!--Conteúdo da view será carregado aqui--> 
   </div>
</body>

No código acima, observe a importação do arquivo “angular-route.min.js” responsável por manter o pacote ngRoute, utilizado no app.config. Também foi importado o arquivo app.js e os controladores para views.

AngularJS – Formulário

pic_angularOlá pessoal. Agora relato o que aprendi sobre formulários HTML com AngularJS.

O AngularJS fornece implementações básica de validação para a maiorias de input HTML5 (text, number, url, email, date, radio, checkbox), além de algumas diretivas de validação: required, pattern, minlength, maxlength, min, max, email, number, etc…).

As implementações básicas de validação estão descritas aqui: Angular input directive.

Detalhes sobre as validações dos inputs podem ser obtidos diretamente na referência oficial:

O framework também oferece propriedades booleanas que ajudam a validar os formulário e seus campos, dando informações sobre o a entrada de dados.

  • $dirty: Indica se o usuário interagiu com o formulário/campo.
  • $pristine: Indica se o usuário ainda não interagiu com o formulário/campo.
  • $valid: Indica se o formulário/campo possui valor válido.
  • $invalid: Indica se o formulário/campo campo possui valor válido.

As propriedades são acessadas no formulário (geral para todos os campos) ou diretamente no elemento (input, select ou textarea). Segue a seguinte nomenclatura:

  • Para formulário: <form name>.<angular propriedade>
  • Para o elemento de entrada: <form name>.<input name>.<propriedade>

Perante a todas estas informações descritas acima, demonstro um pequeno exemplo de validação de formulário.

HTML:

<form name="formDados" novalidate>
    <!--novalidate: necessário para anular as validações nativas do navegador para HTML5-->

    <select ng-model="lancamento.tipo" name="tipo" required>
        <option value="0">selecione...</option>
        <option ng-repeat="t in tipos" value="t.id">{{t.descricao}}</option>
    </select>
    <!--Validando se o valor é vazio (requerido)-->
    <span ng-show="formDados.tipo.$error.required">O TIPO é requerido.</span>
    <br />

    <input type="date" ng-model="lancamento.data" placeholder="data" name="data" required />
    <!--Validando se o valor é vazio (requerido) e a quantidade máxima de caracteres-->
    <span ng-show="formDados.data.$error.required">A DATA é requerida.</span>
    <span ng-show="formDados.data.$error.date">A DATA é inválida.</span>
    <br />

    <input type="text" ng-model="lancamento.obs" placeholder="observação" name="obs" required ng-maxlength="20" />
    <!--Validando se o valor é vazio (requerido) e a quantidade máxima de caracteres-->
    <span ng-show="formDados.obs.$error.required">A OBSERVAÇÃO é requerida.</span>
    <span ng-show="formDados.obs.$error.maxlength">A OBSERVAÇÃO deve ter no máximo 20 caracteres.</span>
    <br />

    <input type="number" ng-model="lancamento.valor" placeholder="valor" name="valor" min="0" />
    <!--Validando o valor é numérico-->
    <span ng-show="formDados.valor.$invalid">Não é um número válido.</span>
    <br />

    <!--O botão ficará desabilitado (ng-disabled) de o usuário não interagir com os campos tipo, obs e valor-->
    <input type="button" value="salvar" id="salvar" ng-click="salvar()"
            ng-disabled="!formDados.tipo.$dirty || !formDados.obs.$dirty || !formDados.valor.$dirty" />

</form>

Javascript (controller):

app.controller('LancamentosController', ['$scope', function ($scope) {

    $scope.tipos = [];
    
    $scope.lancamento = {
        tipo: 0,
        data: "",
        obs: "",
        valor: "", 
        cpf: ""
    };

    $scope.init = function () {
        //carregando os tipos
        if (localStorage.getItem("tps") != null) {
            $scope.tipos = JSON.parse(localStorage.getItem("tps"));
        }
    };

    $scope.salvar = function () {
       
        //testando se o formulário é valido
        if (!$scope.formDados.$valid) {
            
            alert('Verifique os campos');
        }
        else{
            alert('salvou');
        }
    }

    $scope.init();

}]);

É BOM OBSERVAR: O formulário e os elemento de entrada de dados possuem o atributo name, pois será utilizado para implementação das validações. As tags span com a mensagem da invalidação somente será mostrada (ng-show) conforme o retorno booleano da diretiva de validação.

Quando as validações nativas do AngularJS não atendem alguma regra do sistema, é por meio de diretivas que podemos criar validações customizadas. O exemplo abaixo implementa a validação customizada para validar CPF (o algoritmo de validação do CPF não foi disponibilizado por questão de espaço).

Javascript:

app.directive('cpfValido', function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, elem, attrs, ctrl) {

            scope.$watch(attrs.ngModel, function () {

                if (elem[0].value.length == 0)
                    ctrl.$setValidity('cpfValido', true);
                else if (elem[0].value.length < 11) {
                    //aplicar o algoritmo de validação completo do CPF
                    ctrl.$setValidity('cpfValido', false);
                }
                else ctrl.$setValidity('cpfValido', true);
            });
        }
    };
});

HTML:

<input type="text" ng-model="lancamento.cpf" name="cpf" cpf-valido />
<span ng-show="formDados.cpf.$error.cpfValido">CPF Inválido</span>
	

https://docs.angularjs.org/guide/forms

AngularJS – Diretivas

pic_angularOlá pessoal. Dando continuidade ao meu estudo sobre o angular, deixo aqui registrado o que estudei e entendi sobre diretivas.

Diretivas dão poder ao programador para estender/ampliar o comportamento de elementos HTML, e é responsável pela manipulação do DOM. Uma diretiva é capaz de selecionar um elemento HTML por seu atributo (associado ao nome da diretiva), ou nome do elemento, ou por um comentário, ou mesmo pelo valor do atributo class.

Ao selecionar um elemento HTML, a diretiva pode ampliar seu comportamento, adicionando um novo HTML, manipulando o DOM, ou ainda associando eventos à funções Javascript.

São diversas as diretivas nativas do angular: ng-controller, ng-model, ng-repeat, ng-show, ng-hide, ng-click, ng-blur, ng-change, ng-checked, ng-focus, ng-keydown, ng-keypress, ng-keyup, e diversas outras.

Podemos criar nossas próprias diretivas (Custom Directives), para por exemplo:

    • Criar componentes como: abas, janelas de mensagens, janelas pop-up, calendário, etc…;
    • Intercecptar a vinculação de dados e tratá-los se necessário;
    • Criar uma esquema padronizado para validação do model;
    • Tratar eventos dos elementos HTML;
    • Etc…

Uma diretiva customizada deve estar associada a um módulo, podendo ser o próprio módulo da página:

<body ng-app="myApp">
    <div minha-diretiva></div>
</body>
var app = angular.module('myApp', []);

app.directive('minhaDiretiva', function () {
   return {
	restrict: 'A',
	link: function (scope, elem, attrs) {
		elem[0].innerHTML = "minha diretiva....";
	}
   }
});

No exemplo acima, a função directive() do módulo, é usada para criar uma diretiva chamada “minhaDiretiva”, retornando um objeto literal com suas definições. A propriedade restrict é usada para especificar como a diretiva irá selecionar o elemento HTML. Os valores válidos para restrict são:

  • ‘A’ – Atributo:
  • ‘E’ – Elemento:
  • ‘C’ – Class:
  • ‘M’ – Comentário:

A propriedade link deve ser associada a uma função de ligação que faz o trabalho de definição da diretiva. Parâmetros da função: scope, elem e attrs.

  • scope: dá acesso ao escopo da diretiva;
  • elem: é um objeto JQuery Lite contendo o elemento encontrado pela diretiva;
  • attrs: é um objeto que mantém todas as propriedades do objeto encontrado pela diretiva.

O resultado final após a execução da diretiva é:

<div minha-diretiva="">minha diretiva....</div>

Agora vou alterar a diretiva anterior para localizar elementos HTML pelo nome (customizado) da tag do elemento. Com angular, posso criar meus tipos de elemento HTML e definir seu comportamento.

<body ng-app="myApp">
    <minha-diretiva></minha-diretiva>
</body>
var app = angular.module('myApp', []);

app.directive('minhaDiretiva', function () {
   return {
	restrict: 'E',
	link: function (scope, elem, attrs) {
		elem[0].innerHTML = "minha diretiva....";
	}
   }
});

O resultado final é:

<minha-diretiva>minha diretiva....</minha-diretiva>

Observação: é padrão no angular o nome da diretiva seguir a nomenclatura: “primeira palavra iniciando em minusculo e demais com inicial maiúscula”, por exemplo: minhaDiretiva, janelaMensagem, etc. No momento de usar (no HTML) fica assim (dash-delimited): minha-diretiva, janela-mensagem, etc.

Utilizando o conceito de diretivas, também é possível criar templates utilizando as propriedades template ou templateUrl do objeto de retorno de definição da diretiva.

Avançando um pouco mais, mas nem tanto. Uma diretiva também pode ser um template. Observe:

<span meu-template="meu primeio template...">
app.directive('meuTemplate', function () {

    return {

        restrict: 'A',
        scope: {},
        link: function (scope, elem, attrs) {
            scope.msg = attrs.meuTemplate;
        },
        template: '<div><strong>{{msg}}</strong></div>',
        replace: false
    }
});

Ao usar a diretiva acima, obtém-se o seguinte resultado após a renderização:

<span meu-template="meu primeio template...">
    <div>
	 <strong>meu primeio template...</strong>
   </div>
</span>

O conteúdo da propriedade template da diretiva foi incluído dentro do elemento span selecionado pela diretiva. Isso ocorreu devido a propriedade replace estar configurada como false. Se configurado com true, o elemento span é totalmente substituído pelo conteúdo do template, observe o resultado da renderização:

<div meu-template="meu primeio template...">
   <strong>meu primeio template...</strong>
</div>

Há também no objeto de definição da diretiva para elementos (restrict: ‘E’) uma propriedade chamada transclude, que é capaz e anexar/incluir elementos (do contêiner selecionado pela diretiva) dentro do template da diretiva.

E para finalizar, segue um exemplo (simplório) de diretiva para mostrar áreas de mensagens.

app.directive('msgAlert', function () {

    return {
        restrict: 'A',
        scope: { textoMsg: '@'},
               
        template: '<div class="msgAlert">{{textoMsg}} <input type="button" value="(fechar)" ng-click="esconder()" /></div>',
        replace: true,
               
        link: function (scope, elemento, attrs) {
            scope.esconder = function () {
                scope.$parent.mostrarAlert = false;
            }
        }
    };
});

<style>
    .msgAlert {
        background-color:#ffd800;
        border: 1px solid #808080;
        padding: 5px;
        margin: 5px;  
   }
</style>

<div msg-alert texto-msg="{{msg}}" ng-show="mostrarAlert"></div>
<input type="button" value="mostrar alerta" ng-click="abrirAlert()" />

Conclui que usar diretivas não é tão fácil. :-(

AngularJS – Introdução

pic_angularOlá pessoal, inicio aqui meu aprendizado no tão falado framework do Google, o AngularJS. Os textos aqui representam o que tenho estudado e aprendido a respeito deste framework.

AngularJS é um framework Javascript open-source mantido pela Google que dá poder aos desenvolvedores para criar aplicações Web baseadas em navegadores, como as aplicações SPA – Single Page Application.

O site oficial é https://angularjs.org/.

Vamos ao Olá Mundo!!!

<html>
<head>
    <title>Olá Mundo</title>
    <script src="angular.min.js"> </script>
    <script>
        var app = angular.module('minhapagina', []);
    </script>
</head>
<body ng-app="minhapagina">
    <p>Olá mundo: {{ 1 + 2 }}</p>
</body>
</html>

O exemplo acima, consiste em uma simples página HTML, a não ser pelo atributo ng-app. Os “angularianos” chamam ng-app de diretiva, e normalmente é aplicada a tag BODY ou HTML, e indica o elemento inicial da aplicação (ponto a partir do qual o Angular pode ser usado dentro do código HTML).

O código javascript destacado no exemplo, localiza a diretiva ng-app, transformando a página num módulo gerenciável pelo o framework.

 
var app = angular.module('minhapagina', [])

O texto “{{ 1 + 2 }}” é avaliado como uma expressão pelo Angular, que ao ser executada, o resultado é concatenado ao HTML do contexto que está inserida. Uma expressão deve estar entre chaves duplas.

Outras principais diretivas:

ng-controller: define uma função Javascript para controlar determinada parte da página;
ng-model: vincula o elemento a uma propriedade do model do seu contexto;
ng-repeat: realiza a iteração em um array (basicamente um foreach);
ng-show: deixa visível um elemento HTML de acordo com um valor booleano (true/false). Também aceita expressões lógicas;
ng-hide: esconde o elemento de acordo com um valor booleano (true/false). Aceita expressões lógicas;

A referência completa das diretivas é obtida em https://docs.angularjs.org/api/ng/directive/.

Existem diretivas para tratar os diversos eventos disponibilizados nos elementos HTML: ng-click, ng-blur, ng-change, ng-checked, ng-focus, ng-keydown, ng-keypress, ng-keyup, e diversas outras.

O angularJS e o padrão MVC.

Normalmente encontramos a implementação do padrão MVC na programação que ocorre no lado do servidor da aplicação. Com o angular é diferente, a implementação ocorre no lado cliente da aplicação.

O padrão MVC é composto por três componentes principais:

Model – Componente responsável por gerenciar os dados para a aplicação. Não é de responsabilidade do model como o usuário vê os dados e qual lógica será aplicada sobre eles.

View – Componente que representa visualmente o model, um pedaço do HTML da página. Exibe os dados para o usuário devidamente organizados em estruturas HTML e CSS. Não é de sua responsabilidade a lógica contida no controller nem no model.

Controller – Componente responsável por preparar o model para a view, além de tratar regras de negócios, tratar eventos da view e requisições ao servidor.

angular_mvc

Vamos a um segundo exemplo.

<script>
   var app = angular.module('minhapagina', []);
</script>
<body ng-app="minhapagina">
     Seu primeiro nome é: <input type="text" ng-model="primeironome" />
     <p>{{primeironome}}</p>
</body>

Entendendo o exemplo: a diretiva ng-model vincula o valor de elementos input, select e textarea a uma propriedade no model chamada “primeironome”. Neste exemplo, a propriedade “primeironome” do model, mantém o valor informado no input, sendo possível, por exemplo, dentro da view usar expressões para recuperar seu valor.

Efeito igual é conquistado usando a diretiva ng-bind, que auto alimenta a propriedade innerHTML do elemento HTML com o valor de uma propriedade do model.

<p ng-bind="primeironome"></p>

Por questão de padronização do HTML e para deixar válido junto ao W3C, é possível utilizar o prefixo data- (dataset do HTML5) antes das diretivas:

data-ng-app
data-ng-model=”primeironome”
data-ng-bind

Vamos entender melhor a diretiva ng-controller.

Um controller é atribuído a um pedaço da página HTML (view) através da diretiva ng-controller. O controller é uma função Javascript (do tipo construtora) que tem por objetivo cuidar e atualizar de uma determinada área do DOM do página (um pedaço da página, a view).

Como regra geral, um controlador não deve fazer referência ou manipular o Document Object Model (DOM) diretamente.

Controllers são responsáveis pela interação entre models e views. A vinculação de dados entre model e view é realizada pelo angularJS de forma dinâmica, ou seja, qualquer alteração ocorrida em um dos lados (model ou view) atualiza o outro lado, é o chamado Two-Way DataBing [atualização de duas vias] (isso pode ser observado no primeiro exemplo: ao digitar no input, a propriedade “primeironome” é atualizada simultaneamente).

O acesso à view pelo controller é realizado através do objeto $scope. O $scope é um parâmetro do controller que dá acesso ao model vinculado a view.

Vamos a um simples exemplo sobre Controller.

HTML:

    <div ng-controller="MinhaControladora">
        <input type="button" ng-click="perguntar()" value="OK" />
        <p ng-bind="nome"></p>
    </div>

JS:

var app = angular.module('myApp', []);

app.controller('Controladora1', ['$scope', function ($scope) {

	$scope.nome = "...";

	$scope.perguntar = function () {
		$scope.nome = prompt("Qual seu nome?");
	};
}]);

Analisando o bloco da função controladora acima, foi definido a propriedade “nome” e o método “perguntar”. O parâmetro $scope estabelece uma conexão entre a model e view. No bloco HTML representando a view, as propriedades e métodos do models podem ser acessadas e vinculados aos elementos HTML.

Vamos a um exemplo menos simples (mas não avançado) sobre Controller. Destaque para a diretiva ng-repeat para iterar um array.

Javascript:

var app = angular.module('myApp', []);

app.controller('principal', ['$scope', function ($scope) {

	$scope.item = "";
	$scope.msg = "";
	$scope.itens = [];

	$scope.adicionar = function () {


		if ($scope.item == "") {
			alert("Informe o texto");
		}
		else {


			if ($scope.itens.indexOf($scope.item) == -1) {
				$scope.itens.push($scope.item);
				$scope.msg = "";
				$scope.item = "";
			}
			else {
				$scope.msg = "Item existente.";
			}
		}
	};

	$scope.excluir = function (item)
	{
	
		var pos = -1;
		for (var i = 0; i < $scope.itens.length; i++) {

			if ($scope.itens[i] == item)
			{
				pos = i;
				break;
			}
		}

		if (pos > -1)
			$scope.itens.splice(pos, 1);
	}
}]);

HTML:

<body ng-app="myApp" ng-controller="principal">
    <input type="text" ng-model="item" />
    <input type="button" ng-click="adicionar()" value="adicionar" />
    <div mostrar-msg></div>
    <table>
        <thead>
            <tr>
                <th>Item</th>
                <th>&nbsp;</th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="item in itens">
                <td>{{item}}</td>
                <td><a href="javascript:;" ng-click="excluir(item)">excluir</a></td>
            </tr>

        </tbody>
    </table>
    <div>{{msg}}</div>
</body>

 

É por aqui que finalizo meu estudo inicial sobre o Angular. Espero nos próximos post destacar o uso de templates, criação de diretivas próprias e AJAX com o AngularJS.

 

Referencial utilizado

  • AngularJS Succinctly [https://www.syncfusion.com/resources/techportal/ebooks]
  • Site Oficial [angularjs.org]
  • Ultimate guide to learning AngularJS in one day [http://toddmotto.com/ultimate-guide-to-learning-angular-js-in-one-day/]
  • AngularJS Tutorial [http://www.w3schools.com/angular/default.asp]

AngularJS – Requisições Assíncronas (AJAX)

pic_angularEste post foi construído com base na documentação oficial: https://docs.angularjs.org/api/ng/service/$http.

A comunicação entre cliente e servidor no AngularJS é gerenciada pelo serviço $http.

Os métodos disponíveis para realizar requisições são:

  • $http.get
  • $http.head
  • $http.post
  • $http.put
  • $http.delete
  • $http.jsonp
  • $http.patch

Por padrão, estes métodos estão configurados com o Content-Type “application/json;charset=UTF-8”.

Vamos a um simples exemplo que obtém uma cidade a partir de um UF selecionado.


var myApp = angular.module("myApp", []);

myApp.controller("carregaCidade", ['$scope','$http', function ($scope, $http) {

	$scope.uf = "";
	$scope.cidades = [];
	$scope.buscarCidades = function () {

		var params = "?UF=" + $scope.uf;
		var $http.req = get("BuscarCidades.aspx" + params , dados);

		req.success(function (retornoServidor, status) {
			$scope.cidades = retornoServidor;
		});

		req.error(function (retornoServidor, status) {

	   });
	};
}]);
<body ng-app="myApp">
    <div ng-controller="carregaCidade">

		<select id="ddlUf" name="uf" ng-model="uf" ng-change="buscarCidades()">
			<option selected="selected" value="">Selecione</option>
			<option value="SP">SP</option>
			<option value="AC">AC</option>
			<!--...-->
			<option value="TO">TO</option>
		</select>

		<select id="ddlCidades" name="ddlCidades">
			<option value="">selecione...</option>
			<option ng-repeat="cidade in cidades" value="{{cidade.Id}}">{{cidade.Nome}}</option>
		</select>
	
  </div>
</body>	

Os eventos success e error tratam o resultado da operação.

É possível usar diretamente o serviço $http fazendo toda a configuração manualmente.

var req = $http({
   method: "GET",
   url: "BuscarCidades.apsx" + params
});

req.success(function (data, status, headers, config, statusText) {
	$scope.cidades = data;
   
});

req.error(function (data, status, headers, config, statusText) {
	console.log(status);
});

Os exemplos acima utilizaram o método de envio GET, passando dados diretamente pela URL. Para usar o método POST também é simples, bastando organizar os dados para envio no formato JSON.

var dados = JSON.stringify({ UF: $scope.uf });
 
var req = $http({
	url: "BuscarCidades.aspx",
	data: dados,
	method: "POST",
	headers: "Content-Type: application/json;charset=UTF-8"

});

Ou

var req = $http.post("BuscarCidades.aspx", dados);

É claro, que pensando no conceito de aplicações que usam a arquitetura REST, este tipo de requisições (busca de dados) deve ser sempre GET.