09 jul

AngularJS: Formulário de Contato

Neste tutorial iremos utilizar o angularjs juntamente com o PHP para o envio de emails de um formulário de contatos.

Requisitos para esse Tutorial

Instalação do Wamp

A instalação passo-à-passo pode ser vista neste link.

Desenvolvimento da Página de Contato

Primeiramente, iremos mover os arquivos do Tutorial anterior para a pasta www do seu wamp. Geralmente, localiza-se em c:\wamp\www . Em seguida, criaremos uma pasta com o nome ‘tutorial’ e a sua estrutura ficará parecida com esta:

  • www
    •  tutorial
      • css
      • fonts
      • img
      • js
      • templates
      • index.html

Ao acessar http:\localhosttutorial em seu navegador, conforme nosso exemplo anterior, uma página semelhante à imagem abaixo deverá aparecer:

Página inicial do Projeto

O primeiro passo será atualizar a versão do nosso angular, que referenciamos no arquivo index.html, conforme exemplo abaixo:

    <!-- alteramos o angular da versão 1.3.14 para 1.4.1 -->
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.1/angular.min.js"></script>

Feito isso, iremos editar o arquivo templatesheader.html, para acrescentarmos ao menu o link para contato.

<ul class="nav navbar-nav">
   <!-- cada linha é um item do menu -->
   <li><a href="#/">Home</a></li>
   <li><a href="#/servicos">Serviços</a></li>
   <li><a href="#/precos">Preços</a></li>
   <li><a href="#/sobre">Sobre</a></li>
   <li><a href="#/contato">Contato</a></li> <!-- nosso novo item do menu -->
</ul>

A seguir iremos acrescentar a rota, para carregarmos tanto o modelo da página de contatos como o seu controller. Para isso iremos editar o arquivo jsmain.js

app.config(['$routeProvider', function ($routeProvider) {
    $routeProvider

        // aqui dizemos quando estivernos na url / vamos carregar o conteúdo da pagina inicila a home
        // no segundo parametro definimos um objeto contendo o templateUrl da nossa pagina home e o controller que irá
        // preparar o conteudo e processar outros eventos da página que veremos posteriormente
        .when("/", {templateUrl: "templates/home.html", controller: "HomeCtrl"})
        // configuração das rotas bem parecidas para as outras paginas
        .when("/sobre", {templateUrl: "templates/sobre.html", controller: "SobreCtrl"})
        .when("/servicos", {templateUrl: "templates/servicos.html", controller: "ServicosCtrl"})
        .when("/precos", {templateUrl: "templates/precos.html", controller: "PrecosCtrl"})
        /* aqui você pode adicionar rotas para outras paginas que desejar criar */
        .when("/contato", {templateUrl: "templates/contato.html", controller: "ContatoCtrl"})// nossa nova rota
        // por último dizemos se nenhuma url digitada for encontrada mostramos a página 404 que não existe no nosso servidor
        .when('/404', {templateUrl: "templates/404.html"})
        .otherwise("/404");
}]);

Logo abaixo nesse mesmo arquivo, iremos criar o controller que será o responsável por pegar os dados preenchidos pelo usuário e enviar para o servidor, onde o mesmo encarregar-se-á de enviar o email de contato.

app.controller('ContatoCtrl', function ($scope, $location, $http) {

});

Iremos criar o HTML da página de contatos e posteriormente atualizar este controller. Para isso vamos criar o arquivo contato.html na pasta templates.

<div class="row" ng-if="!emailEnviado">
    <div class="box">
        <div class="col-lg-12 text-center">
            <hr/>
            <h2 class="intro-text">Contato</h2>
			<hr/>
        </div>
		<div class="col-lg-12">
			<div class="alert alert-danger" ng-if="frmContato.nome.$error && !frmContato.nome.$valid" ng-show="frmContato.nome.$dirty">
				<strong ng-show="frmContato.nome.$error.required">Nome é Obrigatório!</strong>
				<strong ng-show="frmContato.nome.$error.minlength">Nome deve conter no minímo 3 caractéres!</strong>
			</div>
			
			<div class="alert alert-danger" ng-if="frmContato.email.$error && !frmContato.email.$valid" ng-show="frmContato.email.$dirty">
				<strong ng-show="frmContato.email.$error.required">Email é Obrigatório!</strong>
				<strong ng-show="frmContato.email.$error.email">Email está Inválido!</strong>
			</div>
			
			<div class="alert alert-danger" ng-if="frmContato.assunto.$error && !frmContato.assunto.$valid" ng-show="frmContato.assunto.$dirty">
				<strong ng-show="frmContato.assunto.$error.required">Assunto é Obrigatório!</strong>
				<strong ng-show="frmContato.assunto.$error.maxlength">Assunto deve conter no máximo 100 caractéres!</strong>
			</div>
			
			<div class="alert alert-danger" ng-if="frmContato.mensagem.$error && !frmContato.mensagem.$valid" ng-show="frmContato.mensagem.$dirty">
				<strong ng-show="frmContato.mensagem.$error.required">Mensagem é Obrigatório!</strong>
				<strong ng-show="frmContato.mensagem.$error.minlength">Mensagem deve conter no minímo 30 caractéres!</strong>
				<strong ng-show="frmContato.mensagem.$error.maxlength">Mensagem deve conter no máximo 300 caractéres!</strong>
			</div>
			
			<div class="alert alert-danger" ng-if="emailNaoEnviado">
				<strong>Opss!</strong> Houve um problema ao enviar o seu contato, tente mais tarde.
			</div>
			
			<form name="frmContato" class="form-horizontal" role="form">
                <div class="form-group" ng-class="{ 'has-error': frmContato.nome.$invalid && frmContato.nome.$dirty}">
                    <label for="nome" class="col-lg-2 control-label">Nome</label>
                    <div class="col-lg-10">
                        <input ng-model="formData.nome" ng-minlength="3" type="text" class="form-control" name="nome" placeholder="Seu Nome" ng-required="true">
                    </div>
                </div>
                <div class="form-group" ng-class="{ 'has-error': frmContato.email.$invalid && frmContato.email.$dirty}">
                    <label for="email" class="col-lg-2 control-label">E-Mail</label>
                    <div class="col-lg-10">
                        <input ng-model="formData.email" type="email" class="form-control" name="email" placeholder="Seu E-Mail" ng-required="true">
                    </div>
                </div>
                <div class="form-group" ng-class="{ 'has-error': frmContato.assunto.$invalid && frmContato.assunto.$dirty}">
                    <label for="assunto" class="col-lg-2 control-label">Assunto</label>
                    <div class="col-lg-10">
                        <input ng-model="formData.assunto" ng-maxlength="100" type="text" class="form-control" name="assunto" placeholder="Assunto" ng-required="true">
                    </div>
                </div>
                <div class="form-group" ng-class="{ 'has-error': frmContato.mensagem.$invalid && frmContato.mensagem.$dirty}">
                    <label for="mensagem" class="col-lg-2 control-label">Mensagem</label>
                    <div class="col-lg-10">
                        <textarea ng-model="formData.mensagem" ng-minlength="30" ng-maxlength="300" class="form-control" rows="4" name="mensagem" placeholder="Sua mensagem..." ng-required="true"></textarea>
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-lg-offset-2 col-lg-10">
                        <button type="submit" ng-disabled="!frmContato.$valid" ng-click="enviarEmail()" class="btn btn-default" ng-disabled="submitButtonDisabled">
                            Enviar
                        </button>
                    </div>
                </div>
            </form>
		</div>
    </div>
</div>

<div class="row" ng-if="emailEnviado">
	<div class="box">
		<div class="alert alert-success">
			<strong>Email foi enviado com sucesso!</strong> Entraremos em contato em breve!
		</div>
	</div>
</div>

Verificamos que neste código HTML encontram-se algumas “tags” que naturalmente não fazem parte do HTML-Standard, pois são tags especiais do AngularJS. Abaixo, uma breve descrição de cada uma delas:

ng-if

A documentação oficial <https://docs.angularjs.org/api/ng/directive/ngIf> , nos demonstra a seguinte definição:

A diretiva ngIf remove ou recria uma parte da árvore DOM com base em uma {expressão}. Se a expressão for atribuída a ngIf e avaliada como um valor falso, então o elemento é removido do DOM, caso contrário, um clone do elemento é reinserido no DOM.

Ou seja, nas linhas 9, 14, 19, 24, estamos usando o ng-if para mostrarmos o alerta, caso cada “input” contenha erro e ele não esteja válido.

ng-show

A documentação oficial <https://docs.angularjs.org/api/ng/directive/ngShow> nos demonstra a seguinte definição:

A diretiva ngShow exibe ou oculta o elemento HTML baseado na {expressão} fornecida. O elemento é exibido ou ocultado pela remoção da classe CSS. ng-hide . Essa classe do AngularJS define “display: none !important” no elemento.

Ou seja, ao contrário do ngIf que não cria o elemento, o ngShow cria o elemento e apenas altera a visibilidade do elemento conforme as expressões nas linhas 9, 14, 19, 24 . Usamos o ngShow para exibir o erro quando o campo html for alterado;

ng-class

Na documentação oficial <https://docs.angularjs.org/api/ng/directive/ngClass> a seguinte definição é apresentada:

A diretiva ngClass permite definir dinamicamente classes CSS em um elemento HTML por ligação de dados (databinding). Uma expressão que representa todas as classes a serem adicionados.

Ou seja, as classes de estilo são adicionadas ou removidas do elemento conforme as expressões. Nas linhas 35, 41, 47, 53 o ngClass é utilizado para adicionar a classe css ‘has-error’ caso o input contenha algum erro.

ng-model

A documentação oficial <https://docs.angularjs.org/api/ng/directive/ngModel> oferece a seguinte definição:

A diretiva ngModel se liga (bind) a um input , select , textarea (ou controle de formulário personalizado), para uma propriedade no ‘scope’ usando NgModelController, que é criado e exposto por esta diretiva.

Com isso, posteriormente é através dos ngModel que poderemos pegar os dados digitados em cada input e poderemos enviar para o servidor. Posteriormente, enviará para o email de contato.

ng-click

Na documentação oficial <https://docs.angularjs.org/api/ng/directive/ngClick> encontramos a seguinte definição:

A diretiva ngClick permite que você especifique o comportamento personalizado quando um elemento é clicado.

Na linha 61, usamos o ng-click para chamarmos a função que será responsável pelo envio dos dados do formulário para o servidor.

ng-input, ng-required, ng-minlenght e ng-maxlenght

Na documentação oficial <https://docs.angularjs.org/api/ng/input/input%5Btext%5D> a seguinte definição sobre ng-input é apontada:

Entrada de texto padrão HTML com ligação de dados angular, herdados pela maioria dos elementos input.

ngRequired

Adiciona o atributo required, necessário para restrição de validação do elemento, quando a expressão ngRequired avaliada como verdadeira. Use ngRequired em vez de required quando você quiser validar o required.

ngMinlenght

Atribui minLength (mínimo). Erro de validação se o valor for menor do que minlength.

ngMaxlenght

Seta maxLength (máximo). Erro de validação se o valor for maior do que maxlength.

Validação

Para podermos criar a validação o elemento <form> tem que ter o atributo name, e cada input também deve ter o atributo name. Ex: nomeForm.nomeInput

Com isso podemos acessar algumas propriedades:

  • $error -> retorna true se existe erro
  • $valid -> retorna true quando está válido
  • $dirty -> quando o campo foi modificado (geralmente na digitação)

Na propriedade $error, podemos acessar os filhos que compõe a validação como required, minlenght, maxlenght, entre outros. Na linha 9 usamos no ngIf para verificarmos se no frmContato.nome$error existem erros. Já na linha 10 exibiremos a mensagem de obrigatório, caso o frmContato.nome.$error.required estiver vazio após a edição do campo.

Controller

Agora iremos trabalhar no controller que criamos anteriormente no main.js

app.controller('ContatoCtrl', function ($scope, $location, $http) {
	//criando o objeto em branco, porém após o submit todos os dados estaram nessa variável
	$scope.formData = {};
	//variavel para ebir ou não a mensagem que o email foi enviado
	$scope.emailEnviado = false;
	//variável para exibir mensagem de erro ao enviar o email
	$scope.emailNaoEnviado = false;
	
	//função que será usada para preparar os dados no formato que poderemos usar no servidor para envio do email
	var param = function(data) {
        var returnString = '';
        for (d in data){
            if (data.hasOwnProperty(d))
               returnString += d + '=' + data[d] + '&';
        }
        // Remove o último & que não é necessário
        return returnString.slice( 0, returnString.length - 1 );
	};
	
	$scope.enviarEmail = function() {
		$http({
			method : 'POST',
			url : 'email.php',
			data : param($scope.formData),
			headers : { 'Content-Type': 'application/x-www-form-urlencoded' }
		})
		//função de callback quando a promise for sucesso
		.success(function(data) {
			//verifica o retorno do servidor se o email foi enviado
			if (data.enviado) {
			   $scope.emailEnviado = true; //ocultamos o formulário e exibimos mensagem de sucesso
			} else {
			  	$scope.emailNaoEnviado = true;
			}
		})
		//função de callback quando a promise for erro (geralmente problema de conexão ou página não existente)
		.error(function(error){
			$scope.emailNaoEnviado = true;
		});
	};
});

No início do controller, definimos as 3 variáveis de controle de nossa página de contato, onde $scope.formData terá os dados preenchidos no formulário. Podemos perceber que no html contemos nos input formData.nome pelo fato de ser um objeto e no angular a palavra $scope não é necessária no template html. O mesmo vale para as outras duas variáveis que usamos para mostrar ou não a mensagem de envio, ou se houve algum erro de envio do formulário.

Em seguida temos 2 funções. A primeira é responsável por incluir os dados do formData no formato que iremos pegar no php. A segunda função é que vinculamos ao botão de envio, ele prepara os dados e envia para a url que definimos, e seu correspondente método, nesse caso POST. Isso porque usamos um serviço que o AngularJS possui, o $http, que permite a comunicação com algum servidor. Nesse caso estamos enviando os dados do formulário que será processado e enviado por email.

Este serviço é denominado promise ou promessa, que envia uma solicitação e aguarda este retorno para dar continuidade, neste caso, ao envio de dados. Duas funções são atribuídas a este processo: O success que significa basicamente que o processo obteve êxito em encontrar a url desejada e proceder com o envio de dados, recebendo true como resposta. Caso o retorno seja de fato um true, o email será enviado. Em caso de false, algum problema ocorreu no processo. E o error que neste caso, significa que ele não conseguiu achar essa url, ou de fato encontrou, mas retornou com um erro 404.

Parte do Servidor

E agora criaremos na raiz do projeto onde temos o arquivo index.html, criaremos o arquivo email.php

<?php
header('Access-Control-Allow-Origin: *');
	
$remetente = $_POST['nome'] . " <" . $_POST['email'] . ">";
$nome = $_POST['nome'];
$email = $_POST['email'];
$assunto = $_POST['assunto'];
$msg = $_POST['mensagem'];

$destino = "[email protected]"; // o email que irá receber os emails do site

$html_msg = "
            <html>
                <head>
                    <title>Contato - Site</title>
                    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
                </head>
                <body>
                    <font size="1" face="verdana">
                        <strong>EmpresaSA (Contato pelo Site)</strong>
                    </font>
                    <font face="verdana">
                        <p>
                            <font size="1">
                                <strong>Nome:</strong>  $nome <br>
                                <strong>E-mail:</strong>  $email <br>
                                <strong>Assunto:</strong> $assunto <br>
                                <strong>Mensagem:</strong> $msg 
                            </font>
                        </p>
                    </font>
                </body>
            </html>
            "; //MENSAGEM NO FORMATO HTML
                
$headers  = "MIME-Version: 1.0rn";
$headers .= "Content-type: text/html; charset=utf-8rn";
$headers .= "From: ". $remetente ."rn";
$headers .= "Reply-To: ". $remetente ."rn";
$headers .= "X-Priority: 1rn";
$headers .= "X-MSMail-Priority: Highrn";
$headers .= "X-Mailer: Just My Server";
    
    
if (imap_mail($destino, $assunto, ($html_msg), $headers)) {
    $data = array('enviado' => true );
    echo json_encode($data);
}else{
 	$data = array('enviado' => false);
    echo json_encode($data);
}

Na linha 10 você coloca o email que deseja receber as mensagens. Com isso poderemos testar, porém no servidor local não conseguiremos enviar email. Ao enviar os arquivos do projeto no servidor poderemos realizar este teste, e veremos a mensagem informando que o formulário foi enviado com sucesso. para saber como enviar os arquivos para o servidor veja este artigo. Até a próxima!

Download do Projeto

[wpdm_package id=’464′]

Share this