Índice


Objetivo


O objetivo deste guia é descrever o desenvolvimento de formulários avançados no fluig, abordando algumas regras iniciais para dar uma base para outras personalizações e customizações.


Pré-requisitos


Antes de iniciar o desenvolvimento de formulários, assista aos vídeos how to no item Criação de formulários.


Não utilize a declaração <!DOCTYPE> HTML


Ao publicar um formulário não recomendamos a utilização de declarações <!DOCTYPE>:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

A utilização dessas pode impactar em algumas funcionalidades da definição de formulário ou do Workflow na utilização do navegador Microsoft® Internet Explorer®.


Pré-requisitos


Antes de iniciar o desenvolvimento de formulários, assista aos vídeos how to no item Criação de formulários.


Desenvolvimento de Formulários


Para facilitar o desenvolvimento do formulários, você pode usar o Fluig Studio 


  • Para a criação de uma definição de formulário, na visão Explorador de pacotes (Package Explorer) deve-se acessar a pasta forms do projeto fluig, clicar com o botão direito e no menu acessar Novo (New) > Formulário

Figura 1 - Novo Formulário.



  • Na tela de criação de definição de formulário, basta preencher o nome desejado e clicar em concluir.

Figura 2 - Nova Definição de Formulário.



  • Ao concluir, um pacote referente à definição de formulário é criado na pasta forms e o editor de formulário fica disponível para edição.

Figura 3 - Nova Definição de Formulário.



  • A partir do editor, todo o conteúdo HTML é desenvolvido. No exemplo abaixo um formulário simples de cadastro foi desenvolvido:

Figura 4 - Novo Formulário.


Exportando o formulário para o Fluig


Após o desenvolvimento, você pode enviar para o fluig o seu formulário. Para saber como e ter mais informações sobre as formas de armazenamento de dados, você pode consultar a nossa documentação sobre Exportando formulários e Modelos de Armazenamento de Formulários.

Garantindo a criação dos campos

Apenas são considerados os campos dentro da tag <form> do html principal usando o atributo name do html. Caso tenha outros arquivos html que compõe o formulário ou criação de campos dinâmicos, estes podem não conseguir ser persistidos corretamente no banco de dados.

Caso necessário, você pode criar os campos como não visíveis para que o fluig entenda que existe aquele campo (ainda que depois será substituído pela sua customização)

Boas práticas de desenvolvimento

Evite a inserção de scripts diretamente no arquivo html. Opte por usar um arquivo .js separado para isso e importe-o no seu html através da tag 

<script src="minhasfuncoes.js"></script>

Estrutura de pastas

O Fluig não tem suporte a estrutura de pastas no formulário. Por isso, mesmo que você organize seus arquivos em pastas, como no exemplo abaixo:

.
├── Cadastro de itens.html
├── img
│   └── logo.png
└── js
    └── itens.js



Para o fluig, o seu formulário será entendido assim:

.
├── Cadastro de itens.html
├── logo.png
└── itens.js


Ainda que nenhum arquivo seja perdido, para evitar confusões nas declarações no formulário o ideal é criar os formulário com todos os arquivos na raiz. A exceção são os eventos de formulário como será visto nessa documentação 










<mover toda essa parte pra personalização de formulários>



Serviços de Dados


O fluig possui integração com dois tipos de serviços de dados, são eles: Dataset e Serviços Externos. Ambos podem ser usados em todos os eventos disponíveis para customização de definição de formulário.

Ao construir formulários utilizando a antiga técnica (formulário avançado) onde se faz o uso de datasets, é necessário atenção quanto aos dados incluídos no mesmo, pois ao marcar o formulário como Documento público o dataset respeitará a condição do formulário se tornando público também.

Com isso, orientamos o uso da nova técnica de construção de formulário, muito mais prática e dinâmica facilitando o uso e a construção dos formulários. Confira nossa documentação sobre a nova técnica de construção de formulário.


Dataset

É um serviço de dados que fornece acesso às informações, independente da origem dos dados. O fluig fornece Datasets internos que permitem acesso as entidades, como Usuários, Grupos de Usuários, entre outros.

Os exemplos abaixo utilizam a função getDatasetValues, disponível somente para os Datasets de entidade e definição de formulário(quando informado o número da definição de formulário). Para a utilização de Datasets customizados consulte o Guia de Referência Customização de Datasets.


Na função getDatasetValues, NÃO são retornados os valores de todos os campos por questões de segurança. Para obter todos os dados é utilizado o DatasetFactory, exemplificado em Desenvolvimento de Datasets.

Por exemplo, para acessar o Dataset de usuários do fluig no evento displayFields de uma definição de formulário:

function displayFields(form,customHTML) {
     // Obtendo o usuario via dataset
     filter = new java.util.HashMap();
     filter.put("colleaguePK.colleagueId","adm");
     usuario = getDatasetValues('colleague',filter);
     form.setValue('RNC_colab_abertura',usuario.get(0).get("colleaguePK.colleagueId"));
}

Também é possível fazer uma chamada aos Datasets dentro da definição de formulário através de funções JavaScript.


O acesso aos Datasets também pode ser realizado diretamente no formulário da definição de formulário. Por exemplo, para acessar o Dataset de usuário e inserir os valores nos campos do HTML:

 <html>
    <head>
        <title>
            Teste XMLRPC
        </title>
        <script language="javascript">      
            function init(){                            
                var filter = new Object();
                filter["colleaguePK.colleagueId"] = "adm";  
                var colleagues = DatasetFactory.getDatasetValues("colleague", filter);
                if(colleagues.length > 0){        
					document.getElementById("colleagueName").value = colleagues[0].colleagueName;
                	document.getElementById("colleagueId").value = colleagues[0].colleagueId;
               	 	document.getElementById("login").value = colleagues[0].login;
               	 	document.getElementById("extensionNr").value = colleagues[0].extensionNr;                
					document.getElementById("groupId").value = colleagues[0].groupId;
					document.getElementById("mail").value = colleagues[0].mail;
                }else{
                    alert("Nenhum Usuário Encontrado");
				}
            }
        </script>
    </head>
    <script type="text/javascript" src="/webdesk/vcXMLRPC.js"></script>
    <body onload="init()">
    <form id="form1">
        <b> Nome do Usuário: </b>
        <input type="text" name="colleagueName" id="colleagueName" />
	    <br><br>    
		<b> Matricula do Usuário: </b>
        <input type="text" name="colleagueId" id="colleagueId" />
		<br><br>
		<b>Login do Usuário:</b>
        <input type="text" name="login" id="login" />
        <br><br>            
		<b> Ramal do Usuário: </b>
        <input type="text" name="extensionNr" id="extensionNr" />
        <br><br>
        <b> Grupo do Usuário: </b>
        <input type="text" name="groupId" id="groupId" />
        <br><br>
        <b> E-mail do Usuário: </b>
        <input type="text" name="mail" id="mail" />
        <br><br>
    </form>
    </body>
</html>

Para atualizações anteriores ao fluig 1.5.6, utilizar da seguinte maneira:

(...)
var colleagues = getDatasetValues("colleague", filter);
(...)


O Dataset para definição de formulário utiliza a mesma chamada do Dataset de entidades, como no caso do usuário. Entretanto ao invés de passarmos como parâmetro o nome do Dataset passaremos o número da definição de formulário, por exemplo:

function displayFields(form,customHTML) {
     // Obtendo o usuario via dataset
     filter = new java.util.HashMap();
     filter.put("RNC_nr_solicitacao",new java.lang.Integer(20));
     registrosform = DatasetFactory.getDatasetValues(Number(676),filter);
	 log.info("Usuário de Abertura: "+ registrosform.get(0).get("RNC_colab_abertura"));
}

Para atualizações anteriores ao fluig 1.5.6, utilizar da seguinte maneira:

function displayFields(form,customHTML) {
     // Obtendo o usuario via dataset
     filter = new java.util.HashMap();
     filter.put("RNC_nr_solicitacao",new java.lang.Integer(20));
     registrosform = getDatasetValues(Number(676),filter);
	 log.info("Usuário de Abertura: "+ registrosform.get(0).get("RNC_colab_abertura"));
}

Download de exemplo de Formulário Combobox e Dataset: form.html.


Apresentação de dados com componentes com múltiplos valores:

Os campos possíveis de selecionar mais de um valor posteriormente são armazenados em um array. Quando são recuperados esses valores, é feito um tratamento para apresentar os valores separados por colchetes. Exemplo: [valor1] [valor2].


DataService

É um serviço de dados que permite o acesso de aplicações de terceiros através do fluig. Este serviço de dados suporta dois tipos de conexão, são eles: AppServer do Progress® e Web Services.

Os serviços de dados são cadastrados e configurados a partir da função Visualização de Serviços do fluig Studio.

Para mais informações sobre o cadastro dos serviços consulte: Integração Com Aplicativos Externos. E para informações de utilização dos serviços nos eventos consulte: Desenvolvimento de Workflow.


Pai x Filho


A técnica Pai X Filho foi modificada e agora a posição da tag tablename é feita dentro da tag "table" do código html.

No novo modelo implementado agora o parser do formulário aplicará as mudanças do pai filho da seguinte forma:

<table tablename="teste"> - A propriedade tablename determina que Agora abaixo dessa tabela será implementado um sistema de pai filho dentro da definição de formulário. A tag <table> terá seus parâmetros varridos na busca de outros parâmetros relacionados à técnica que serão explicados mais adiante nesse texto. Será criada uma outra <table> ao redor da tabela principal que conterá um  botão que permite adicionar novos filhos. Isso não ocorrerá apenas em casos em que a propriedade noaddbutton também seja informada em conjunto com  a propriedade tablename.                                                                                                    

<TR> (primeiro abaixo do table) - A primeira tag de <TR> encontrada dentro da tabela é visualizada como uma tag que conterá os labels da tabela pai filho a esta tag será adicionada uma coluna <TD> contendo o ícone e a função de eliminar filhos existentes em tela. Está nova coluna será a primeira coluna a esquerda da tabela.

<TR> (Segundo abaixo do table) - A técnica pai filho irá ocultar a linha <TR> original e transforma lá no seu “template mestre” para criação dos filhos daquela tabela. Cada vez que o botão “novo” for acionado todo o conjunto de campos existentes dentro desse segundo <TR> será replicado em tela com os dados iniciais definidos para estes campos.

</table>  - Fim do escopo da técnica.

Não é recomendada a utilização de underscore - "___" - na propriedade name de uma coluna (tag <td>) em formulário que utilizem Pai x Filho pois não é renderizada no Mobile.


A técnica também suporta novos atributos que podem ser passados eu usados para customizar a técnica pai e filho. São elas:

noaddbutton - Remove o botão “adicionar” da tela no momento da edição do formulário. Isso permite ao desenvolvedor escolher aonde ele vai colocar a função  que criará os filhos em tela podendo amarrar a chamada da função em um link texto ou uma figura ou outro objeto do html.

<table tablename="teste" noaddbutton=true>


nodeletebutton - Remove o botão “lixeira” da tela no momento da edição do registro de formulário. Isso permite ao desenvolvedor impedir a eliminação dos registros ou definir outra forma de executar a função que removerá os filhos da tabela.

 <table tablename="teste" nodeletebutton=true>


addbuttonlabel - Determina que texto será posto no botão de adicionar filhos da técnica. Caso não seja informado o botão virá com o texto padrão (novo).                                    

 <table tablename="teste" addbuttonlabel="Adicionar novo ingrediente">

                         

addbuttonclass - Permite definir qual classe css será utilizada pelo botão. Essa classe css deverá estar disponível no documento html do formulário.

 <table tablename="teste" addbuttonclass="wdkbuttonClass">


deleteicon - Permite determinar qual será a imagem que funcionará como ícone da eliminação de filhos em tela. Essa imagem deverá ser um anexo da definição de formulário e deverá ser informada na classe como uma imagem qualquer utilizada como anexo na definição de formulário.

<table tablename="teste" deleteicon="teste.jpg">       


customFnDelete - Permite a customização da função que é chamada ao clicar no botão que elimina um filho da tabela. A função customizada deverá estar disponível no documento html da definição de formulário e, obrigatoriamente, chamar a função padrão.

<table tablename="teste" customFnDelete="fnCustomDelete(this)">
    function fnCustomDelete(oElement){

    //Customização
	alert ("Eliminando filho!");

    // Chamada a funcao padrao, NAO RETIRAR
    fnWdkRemoveChild(oElement);

    //Customização
    alert ("Filho eliminado!");
}


É possível usar a combinação de um ou mais atributos na mesma tabela pai filho. Contudo se a propriedade noaddbutton for utilizada os valores das propriedades addbuttonlabel e addbuttonclass serão ignoradas. Não será gerada uma mensagem de erro na publicação ou versionamento dessa definição de formulário, porém no momento da edição do formulário a mesma não irá apresentar o botão padrão que permite cadastrar novos filhos na definição de formulário. A propriedade deleteicon não é afetada pela propriedade noaddbutton. Exemplo de uso combinado de parâmetros:

<table tablename="teste" addbuttonlabel="Adicionar novo ingrediente" addbuttonclass="wdkbuttonClass" deleteicon="teste.jpg">

Sobre os campos de uma tabela pai e filho:

não estão disponíveis para serem utilizados como descrição dos registros de formulários na configuração do formulário;

não devem ser colocados no "head" ou "footer" de um HTML pois eles não serão considerados, coloque os campos apenas no "body".


Para mais informações sobre os eventos de formulários PaixFilho acesse Eventos Formulários.

O índice de formulário pai e filho é utilizado da seguinte forma ex: indice___1. Em input dinâmicos não é recomendado adicionar valores no atributo name após o indice.


A técnica 2.0 do pai Filho não permite o uso de todos os componentes HTML. É possível utilizar apenas:

Expanda a macro e veja o exemplo:

<html>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/portal/resources/style-guide/css/fluig-style-guide.min.css">
<link rel="stylesheet" type="text/css" href="/portal/resources/style-guide/css/fluig-style-guide-filter.min.css">
<script src="/portal/resources/js/jquery/jquery.js"></script>
<script src="/portal/resources/js/jquery/jquery-ui.min.js"></script>
<script src="/portal/resources/js/mustache/mustache-min.js"></script>
<script src="/portal/resources/style-guide/js/fluig-style-guide.min.js"></script>
<script  src="/portal/resources/style-guide/js/fluig-style-guide-filter.min.js"></script>
<title>Formulario pai e filho</title>
<body>
<span class="NumSecao">
<strong>&nbsp;Cadastro</strong></span>
<HR>
<br>
<form>
<table>
  <tr> 
    <td align="right" width="100" class="Labels"><b>Data:</b></td>
    <td class="Normal"><strong><input type="text" size="30" name="data"></strong></td>
  </tr>
  <tr> 
    <td align="right" width="100" class="Labels"><b>Solicitação:</b></td>
    <td class="Normal"><strong><input type="text" size="30" name="num_solic"></strong></td>
  </tr>
  <tr> 
    <td align="right" width="100" class="Labels"><b>Atividade:</b></td>
    <td class="Normal"><input type="text" size="30" name="num_ativ"></td>
  </tr>
  <tr> 
    <td align="right" width="100" class="Labels"><b>Processo:</b></td>
    <td class="Normal"><input type="text" size="30" name="cod_proc"></td>
  </tr>
  <tr> 
    <td align="right" width="100" class="Labels"><b>Versão:</b></td>
    <td class="Normal"><p><input type="text" size="30" name="ver_proc"></p></td>
  </tr>
  <tr> 
    <td align="right" width="100" class="Labels"><b>Usuário:</b></td>
    <td class="Normal"><p><input type="text" size="30" name="usuario"></p></td>
  </tr>
  <tr> 
    <td align="right" width="100" class="Labels"><b>Empresa:</b></td>
    <td class="Normal"><p><input type="text" size="30" name="empresa"></p></td>
  </tr>
  <tr>
    <td align="right" width="100" class="Labels"><b>Observações:</b></td>
    <td class="Normal"><p><input type="text" size="30" name="obs"></p></td>
  </tr>
   <td class="label">
        Autoriza?
        <input type="radio"
           name="aut"
           id="aut"
           value="branco"
           style="display:none">
        Sim:                                       
            <input name="aut"
               type="radio"
               value="aut_yes" checked>                        
        Não:
            <input name="aut"
               type="radio"
               value="aut_no">
    </td> 
</table>
<table>
  <tr>
    <td><b>Responsáveis:</b></td><br></br>
        <table border="1" tablename="teste" addbuttonlabel="Adicionar Responsável">
            <thead>
                <tr>
                    <td>
                        <b>Responsável:</b>
                    </td>
                    <td>
                          Check
                    </td>
                    <td>
                        Observação
                    </td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>
                        <select name="colaboradores" dataset="colleague" datasetkey="colleagueName" datasetvalue="colleagueName"></select>
                    </td>
                    <td>
                        <input type="checkbox" name="validado" value="a">
                    </td>
                    <td>
                        <input type="text" name="mat_er_ial" id="mat_er_ial">
                    </td>
                </tr>
            </tbody>
        </table>
  </tr>
</table>
</form>
</body>
</html>

Clique aqui e baixe um exemplo de formulário Pai e Filho usando o fluig Style Guide.


Radio Button

Para utilizar campos radio button, além da definição padrão do componente html, é necessário que seja utilizado o atributo ‘value’ para os dados serem salvos corretamente.

<table border="1" tablename="teste" addbuttonlabel="Adicionar Filho"  nodeletebutton="true">
	<thead>
		<tr>
			<td><b>Nome</b></td>
			<td><b>Idade</b></td>
			<td><b><font face =	"arial" size=5 color ="blue">Sim:</b></td>
		 	<td><b><font face = "arial" size=5 color ="blue">Não:</b></td>
	 	</tr>
	</thead>
	<tr>
		<td><input type="text" name="nomefilho"></td>
		<td><input type="text" name="idadefilho"></td>
 		<td><input type="radio" name="nameradiofilho" id = "idsimfilho" value="ant_yes"></td>
	 	<td><input type="radio" name="nameradiofilho" id = "idnaofilho" value="ant_no"></td>
	</tr>
</table>


Texto Rico



LGPD


O LGPD - Lei Geral de Proteção de Dados (LGPD, Lei nº 13.709) foi implementado a fim de garantir transparência no uso dos dados das pessoas físicas em quaisquer meios. No que diz respeito aos formulários codificados publicados na plataforma, serão fornecidos os mecanismos para que os desenvolvedores de formulário via código, possam identificar quais campos de um formulário irão possuir dados pessoais ou sensíveis de usuários, preservando seu desenvolvimento e deixando-os compatíveis com a Lei Geral de Proteção de Dados.

Para configurar campos que possuem dados que devem ser monitorados, o desenvolvedor deve adicionar alguns atributos ao campo "input" do html.

Campo normal:
<input type="text" name="client-name" >

Campo LGPD:
<input type="text" name="client-name" data-protection="Nome do cliente" data-protection-anonymizable data-protection-sensitive data-protection-name data-protection-class-consent="Necessário para futuras ofertas">

Atributos:
Dado que será monitorado:

data-protection

Dado monitorado com descrição:
data-protection="description"

Dado que permite ser anonimizado:
data-protection-anonymizable ou data-protection-anonymizable="true"

Dado sensível:
data-protection-sensitive ou data-protection-sensitive="true"

Tipo de dado:
data-protection-name
data-protection-mail
data-protection-cpf
data-protection-id (rg)
data-protection-driver-license (cnh)
data-protection-voter-id (título eleitoral)
data-protection-work-card (carteira de trabalho)
data-protection-passport
data-protection-other

Classificação:
data-protection-class-contract (execução de contrato)
data-protection-class-legal-obligation (obrigação legal)
data-protection-class-consent (consentimento)
data-protection-class-public-policies (execução de políticas públicas)
data-protection-class-scientific-analysis (estudos por órgão de pesquisa)
data-protection-class-dedicated-law (exercício regular de direito)
data-protection-class-life-protection (proteção da vida)
data-protection-class-health-guardianship (tutela de saúde)
data-protection-class-legitimate-interests (interesse legítimo)
data-protection-class-credit-protection (Proteção de crédito)

Classificação com justificativa:
data-protection-class-contract="".

Para saber mais detalhes sobre o LGPD e sua implementação, acesse LEI GERAL DE PROTEÇÃO AOS DADOS PESSOAIS.




Tradução de formulários


Para traduzir formulários é necessário utilizar a função i18n.translate(“literal_da_tradução”) nos pontos do arquivo HTML que devem ser traduzidos, conforme exemplo a seguir:

<label>i18n.translate("nm_cliente")</label>
<input name=”nm_cliente”>
<br>
<label>i18n.translate("contato_cliente")</label>
<input name=”contato_cliente”>
As literais e seus respectivos valores são informados em arquivos de propriedades com a extensão .properties para cada um dos idiomas desejados. Os idiomas suportados para a tradução são os mesmos suportados pelo fluig:

Português (pt_BR);

Inglês (en_US);

Espanhol (es).


Os arquivos contendo as literais têm a seguinte nomenclatura:

Português: nome_do_formulario_pt_BR.properties;

Inglês: nome_do_formulario_en_US.properties;

Espanhol: nome_do_formulario_es.properties.


Os arquivos de propriedades são criados de acordo com os passos apresentados a seguir:


  • Para gerar os arquivos de propriedades, na visão Explorador de Pacotes, deve-se acessar o arquivo HTML do formulário a ser traduzido, clique com o botão direito e acessar a opção Externalizar Strings.

Figura 1 - Menu Contextual Externalizar Strings.



  • Os arquivos contendo as literais são criados na pasta do formulário.

Figura 2 - Arquivos Properties na Pasta do Formulário.



  • Informe os valores correspondentes às literais para o idioma de cada arquivo.

Figura 3 - Edição de um Arquivo Properties.


Ao exportar um formulário para o fluig, os arquivos de propriedades contendo as literais são publicados como anexos dele.
O formulário é apresentado no idioma que está configurado para o usuário corrente.


Traduzindo Eventos de formulários 


Da mesma forma que é possível traduzir a interface do formulário é possível traduzir também mensagem retornadas nos eventos do formulário. Para isso basta utilizar a função i18n.translate dentro dos eventos passando uma propriedade que esteja pré-definida no arquivos .properties deste mesmo formulário. Abaixo exemplo de uma implementação que irá retornar para o usuário uma mensagem de acordo com o definido no arquivo properties.

if (form.getValue('meeting') == null || form.getValue('meeting').trim().length() == 0) {
		throw i18n.translate("proidade_definida_no_arquivo_properties");
	}


Regras de formulário


No editor web de formulário é possível criar validações avançadas para os campos, dependendo da atividade.

Para isso, no editor, clique em “Regras de formulário”, Adicionar, selecione o campo e a atividade e em ação, escolha “Validar”. Clique na lupinha.

Essa validação serve para bloquear alguns valores. O usuário não vai informar quais são os valores permitidos, pelo contrário, ele vai configurar quais os valores proibidos.

Por exemplo, se quiser configurar para que um campo idade só permita valores maiores que 18, a configuração deve ser: idade menor 18. Ou seja, é uma validação restritiva e não permissiva.

No caso de uma combinação de fatores, como idade entre 12 e 18 anos:

Satisfazer UMA das condições
idade menor que 12
idade maior que 18
Ou então, caso queira excluir um determinado grupo intermediário, ou seja, ninguém com idades entre 18 e 60:


Satisfazer TODAS as condições
idade maior que 18
idade menor que 60



Para ficar por dentro do assuntos relacionados à formulários para dispositivos móveis, acesse a página Desenvolvimento de formulário Mobile e confira todos os detalhes!


Skin do fluig Style Guide


Os formulários renderizados dentro da plataforma vão respeitar a skin do Style Guide selecionada na configuração de tema da empresa, conforme a FAQ FORM 011 - Como utilizar a skin flat em formulários?.

<!-- Hotjar Tracking Code for tdn.totvs.com -->
<script>
    (function(h,o,t,j,a,r){
        h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
        h._hjSettings={hjid:577655,hjsv:5};
        a=o.getElementsByTagName('head')[0];
        r=o.createElement('script');r.async=1;
        r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
        a.appendChild(r);
    })(window,document,'//static.hotjar.com/c/hotjar-','.js?sv=');
</script>