Técnico

Formulários dinâmicos com validadores

Em minha estréia, trago para você este script para agilizar a construção de formulários Flex, ele apenas aponta “o caminho”, você deverá implementar com os demais validadores.

Para isso vamos começar pela classe Event. chamaremos essa classe de CustomEvent, seu objetivo será criar o validador dentro do evento (mx.events.FlexEvent) creationComplete do campo, para isto foi necessário adicionar três propriedades à classe, que são: validateType do tipo Object que receberá as informações para configurar o validador, o validator do tipo coringa para que fique mais fácil de trabalhar com vários validadores diferentes (aqui vou trabalhar apenas com mx.validators.StringValidator e mx.validators.EmailValidator), e a constante contendo o nome do evento que vai caracterizar a configuração que chamamos de VALIDATECHANGE.

package core.events
{

import flash.events.Event;

import mx.events.FlexEvent;
import mx.validators.EmailValidator;
import mx.validators.StringValidator;

public class CustomEvent extends FlexEvent
{
static public const VALIDATECHANGE:String ='validatechange';
private var _validateType:Object;
private var _validator:*;

public function CustomEvent(type:String,validateType:Object, bubbles:Boolean=false,cancelable:Boolean=false)
{
super(type, bubbles,cancelable);
setValidator(validateType);
}

public override function clone() : Event {
return new CustomEvent(CustomEvent.VALIDATECHANGE,validateType);
}

public override function toString():String {
return formatToString('CustomEvent','type', 'bubbles', 'cancelable', 'validateType','validator');
}

public function get validateType():Object
{
return _validateType;
}

public function get validator():*
{
return _validator;
}

private function setValidator(params:Object):void
{
if(params.validateType.length < 1){ return; } _validateType = params; switch(params.validateType){ case 'string': case 'noblank': _validator = new StringValidator(); if(params.message.length > 0){
_validator.requiredFieldError =
_validator.requiredFieldError =
_validator.tooLongError =
_validator.tooShortError = params.message;
}
_validator.minLength = 1;
break;
case 'email':
_validator = new EmailValidator();
if(params.message.length > 0){
_validator.requiredFieldError =
_validator.invalidCharError =
_validator.invalidDomainError =
_validator.invalidIPDomainError =
_validator.invalidPeriodsInDomainError =
_validator.missingAtSignError =
_validator.missingPeriodInDomainError =
_validator.missingUsernameError = params.message;
}
break;
}
_validator.source = params.source;
_validator.property = params.property;
_validator.required = params.required;
_validator.triggerEvent = params.triggerEvent;
_validator.enabled = true;
}
}
}

Os validadores são classes/tags separadas do campo, para agilizar o desenvolvimento precisamos dos validadores nos campos, para isso vamos manipular uma classe baseada no TextInput (spark.components.TextInput), de forma a permitir a passagem da configuração básica do validador na tag, trabalharemos com a tag CustomInput adicionando esses atributos, que são eles: validateType que distinguirá o tipo do validador, message contendo a mensagem que será enviada ao navegador em caso de erro, required caracteriza como requerido ou não, index que ocupará o lugar do id. Para manipulação interna foram criadas as propriedades: _initialized responsável por informar se é a primeira vez que o validador será criado,_params responsável por armazenar as configurações para criação do validador, e _validator o próprio validador.

package core.mxml
{

import core.events.CustomEvent;
import core.model.CustomModelLocator;

import mx.events.FlexEvent;
import mx.utils.ObjectUtil;

import spark.components.TextInput;

[Event(name="validatechange", type="core.events.CustomEvent")]

public class CustomInput extends TextInput
{

private var _initialized:Boolean = false;
private var _params:Object = {validateType:'',message:'',source:'',index:'',property:'text',required:false,triggerEvent:'change'};
private var _validator:* ;
private var _model:CustomModelLocator;
private var _validateType:String;
private var _message:String = '';
private var _required:Boolean = false;
private var _index:int;
private var _source:String;

public function CustomInput()
{
_model = CustomModelLocator.getInstance();
super();
addEventListener(FlexEvent.CREATION_COMPLETE,onCreationComplete);
}

private function dispatchEventCustom():void{
_params.validateType = _validateType;
_params.message = _message;
_params.required = _required;
_params.source = this;
_params.index = _index;
dispatchEvent(new CustomEvent(CustomEvent.VALIDATECHANGE,_params));
}

private function onCreationComplete(event:FlexEvent):void {
id = this.id = super.id = name;
addEventListener(CustomEvent.VALIDATECHANGE,setValidator);
dispatchEventCustom();
_initialized = true;
}

public function get validator():* {
return _validator;
}

private function setValidator(event:CustomEvent):void
{
enabled = true;
_validator = event.validator;
_model[_source][event.validateType.index].validator = event.validator;
}

public function get validateType():String
{
return _validateType;
}

[Bindable(event="validatechange")]
[Inspectable(enumeration="noblank,string,email", name='validateType')]
public function set validateType(v:String):void
{
_validateType = v;
if(_initialized){
dispatchEventCustom();
}
}

public function get message():String
{
return _message;
}

[Inspectable(type='String', name='message')]
public function set message(v:String):void
{
_message = v;
}

public function get source():String
{
return _source;
}

[Inspectable(type='String', name='source')]
public function set source(v:String):void
{
_source = v;
}

public function get required():Boolean
{
return _required;
}

[Inspectable(type='Boolean', name='required')]
public function set required(v:Boolean):void
{
_required = v;
}

public function get index():int
{
return _index;
}

public function set index(v:int):void
{
_index = v;
}

}
}

Os campos serão criados no modelo da classe Form (mx.containers.Form), e como quero deixar meu formulário mais genérico, ou seja, quero que os ids, labels e validadores, sejam flexíveis, possibilitando uma criação dinâmica, foi criada então a tag CustomFormBase, que receberá os dados para configuração do formulário, dinamicamente, em uma única propriedade, e ainda receberá a ação do submit (que não foi trabalhada tão profundamente).

package core.mxml
{
import core.model.CustomModelLocator;

import flash.events.MouseEvent;

import mx.collections.ArrayCollection;
import mx.containers.Form;
import mx.controls.Alert;
import mx.events.FlexEvent;
import mx.validators.Validator;

import spark.components.Button;

public class CustomFormBase extends Form
{
public var send:Button;
private var _source:ArrayCollection;
private var _model:CustomModelLocator;
private var _dataConfig:String;

public function CustomFormBase()
{
_model = CustomModelLocator.getInstance();
super();
addEventListener(FlexEvent.CREATION_COMPLETE,doCreationComplete);
}

private function doCreationComplete(event:FlexEvent):void
{
send.addEventListener(MouseEvent.CLICK,submit);
}

protected function submit(event:MouseEvent):void
{
var _validators:Array = new Array();
for(var i:int=0;i<_source.length;i++){ _validators.push(_source[i].validator); } _validators = Validator.validateAll(_validators); if (_validators.length == 0) { Alert.show("Preenchimento correto", "SUCCESSO"); } }public function get source():ArrayCollection { return _source; }public function get dataConfig():String { return _dataConfig; }[Bindable] [Inspectable(type='String', name='dataConfig')] public function set dataConfig(v:String):void { _dataConfig = v; _source = _model[v]; }} }

Nosso primeiro MXML é bem simples, utilizando a classe Repeater (mx.core.Repeater), dispondo as tag da maneira que desejamos que sejam vizualizadas. (atenção UX)










Já que criamos um padrão de construção, vamos continuar nele, separando o ActionScript do MXML, durante a criação do arquivo de referência da aplicação.
package core.mxml {
import core.model.CustomModelLocator;

import mx.collections.ArrayCollection;

import spark.components.Application;

public class CustomApplication extends Application
{

[Bindable] private var _model:CustomModelLocator;

public function CustomApplication()
{
_model = CustomModelLocator.getInstance();
super();
}

public function get dataConfig1():String
{
return _model.DATASOURCE1;
}

public function get dataConfig2():String
{
return _model.DATASOURCE2;
}

}
}

E adicionamos os dados (fake) fixos.

package core.model
{
import mx.collections.ArrayCollection;

[Bindable]
public class CustomModelLocator
{
public const DATASOURCE1:String = 'dataConfig1';
public const DATASOURCE2:String = 'dataConfig2';

public var dataConfig1:ArrayCollection;

public var dataConfig2:ArrayCollection;

static private var instance:CustomModelLocator;

static public function getInstance() : CustomModelLocator
{
if ( instance == null ){
instance = new CustomModelLocator(new CustomSingleton());
}
return instance;
}

public function CustomModelLocator(singleton:CustomSingleton)
{
if ( singleton == null ){
throw new Error( "Construção inválida" );
}else{
dataConfig1 = new ArrayCollection([
{label:'Nome',message:'Nome inválido',validateType:'noblank',id:'nome',text:'Pedro Claudio',required:true},
{label:'E-mail',message:'E-mail inválido', validateType:'email',id:'email',text:'',required:true}
]);
dataConfig2 = new ArrayCollection([
{label:'Endereço',message:'Endereço inválido',validateType:'noblank',id:'end',text:'',required:true },
{label:'Bairro',message:'Bairro inválido',validateType:'noblank',id:'bairro',text:'',required:false},
{label:'Cidade',message:'Cidade inválida',validateType:'noblank',id:'bairro',text:'',required:true }
]);
}
}
}
}
class CustomSingleton {}

Por fim nossa chamada mãe.











exemplo
source

Este material foi registrado no http://cookbooks.adobe.com, local onde, a comunidade de desenvolvedores e usuários de tecnologias Adobe, podem compartilhar informações. E ainda no http://blog.pcsilva.com, origem do post.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Compartilhe isso: