DClick

Formulários dinâmicos com validadores


Twitter!

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.

ACTIONSCRIPT:
  1. package core.events
  2. {
  3.  
  4.         import flash.events.Event;
  5.        
  6.         import mx.events.FlexEvent;
  7.         import mx.validators.EmailValidator;
  8.         import mx.validators.StringValidator;
  9.        
  10.         public class CustomEvent extends FlexEvent
  11.         {
  12.                 static public const VALIDATECHANGE:String ='validatechange';
  13.                 private var _validateType:Object;
  14.                 private var _validator:*;
  15.                
  16.                 public function CustomEvent(type:String,validateType:Object, bubbles:Boolean=false,cancelable:Boolean=false)
  17.                 {
  18.                         super(type, bubbles,cancelable);
  19.                         setValidator(validateType);
  20.                 }
  21.  
  22.                 public override function clone() : Event {
  23.                         return new CustomEvent(CustomEvent.VALIDATECHANGE,validateType);
  24.                 }
  25.  
  26.                 public override function toString():String {
  27.                         return formatToString('CustomEvent','type', 'bubbles', 'cancelable', 'validateType','validator');
  28.                 }
  29.  
  30.                 public function get validateType():Object
  31.                 {
  32.                         return _validateType;
  33.                 }
  34.  
  35.                 public function get validator():*
  36.                 {
  37.                         return _validator;
  38.                 }
  39.  
  40.                 private function setValidator(params:Object):void
  41.                 {
  42.                         if(params.validateType.length <1){
  43.                                 return;
  44.                         }
  45.                         _validateType = params;
  46.                         switch(params.validateType){
  47.                                 case 'string':
  48.                                 case 'noblank':
  49.                                    _validator = new StringValidator();
  50.                                     if(params.message.length> 0){
  51.                     _validator.requiredFieldError =
  52.                     _validator.requiredFieldError =
  53.                     _validator.tooLongError =
  54.                     _validator.tooShortError = params.message;
  55.                                     }
  56.                                     _validator.minLength = 1;
  57.                                 break;
  58.                                 case 'email':
  59.                                _validator = new EmailValidator();   
  60.                                 if(params.message.length> 0){
  61.                                     _validator.requiredFieldError =
  62.                                     _validator.invalidCharError =
  63.                                     _validator.invalidDomainError =
  64.                                     _validator.invalidIPDomainError =
  65.                     _validator.invalidPeriodsInDomainError =
  66.                                     _validator.missingAtSignError =
  67.                     _validator.missingPeriodInDomainError =
  68.                                    _validator.missingUsernameError = params.message;
  69.                                 }                   
  70.                                break;
  71.                         }
  72.                     _validator.source = params.source;
  73.             _validator.property = params.property;
  74.                     _validator.required = params.required;
  75.                         _validator.triggerEvent = params.triggerEvent;           
  76.                     _validator.enabled = true;
  77.                 }               
  78.         }
  79. }

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.

ACTIONSCRIPT:
  1. package core.mxml
  2. {
  3.  
  4.         import core.events.CustomEvent;
  5.         import core.model.CustomModelLocator;
  6.        
  7.         import mx.events.FlexEvent;
  8.         import mx.utils.ObjectUtil;
  9.        
  10.         import spark.components.TextInput;
  11.  
  12.         [Event(name="validatechange", type="core.events.CustomEvent")]
  13.                
  14.         public class CustomInput extends TextInput
  15.         {
  16.  
  17.                 private var _initialized:Boolean = false;
  18.                 private var _params:Object       = {validateType:'',message:'',source:'',index:'',property:'text',required:false,triggerEvent:'change'};
  19.                 private var _validator:* ;
  20.                 private var _model:CustomModelLocator;
  21.                 private var _validateType:String;
  22.                 private var _message:String      = '';
  23.                 private var _required:Boolean    = false;
  24.                 private var _index:int;
  25.                 private var _source:String;
  26.                
  27.                 public function CustomInput()
  28.                 {
  29.                         _model = CustomModelLocator.getInstance();
  30.                         super();
  31.             addEventListener(FlexEvent.CREATION_COMPLETE,onCreationComplete);
  32.                 }
  33.                
  34.                 private function dispatchEventCustom():void{
  35.                         _params.validateType = _validateType;
  36.                         _params.message      = _message;
  37.                         _params.required     = _required;
  38.                         _params.source       = this;
  39.                         _params.index        = _index;
  40.                         dispatchEvent(new CustomEvent(CustomEvent.VALIDATECHANGE,_params));
  41.                 }
  42.  
  43.                 private function onCreationComplete(event:FlexEvent):void {
  44.                         id = this.id = super.id = name;
  45.             addEventListener(CustomEvent.VALIDATECHANGE,setValidator);
  46.                         dispatchEventCustom();
  47.                          _initialized = true;
  48.                 }
  49.                
  50.                 public function get validator():* {
  51.                         return _validator;
  52.                 }
  53.  
  54.                 private function setValidator(event:CustomEvent):void
  55.                 {
  56.                         enabled = true;
  57.                         _validator = event.validator;
  58.             _model[_source][event.validateType.index].validator = event.validator;
  59.                 }
  60.                
  61.                 public function get validateType():String
  62.                 {
  63.                         return _validateType;
  64.                 }
  65.                
  66.                 [Bindable(event="validatechange")]
  67.                 [Inspectable(enumeration="noblank,string,email", name='validateType')]
  68.                 public function set validateType(v:String):void
  69.                 {
  70.                         _validateType = v;
  71.                         if(_initialized){
  72.                                 dispatchEventCustom();
  73.                         }
  74.                 }
  75.                
  76.                 public function get message():String
  77.                 {
  78.                         return _message;
  79.                 }
  80.  
  81.                 [Inspectable(type='String', name='message')]
  82.                 public function set message(v:String):void
  83.                 {
  84.                         _message = v;
  85.                 }
  86.  
  87.                
  88.                 public function get source():String
  89.                 {
  90.                         return _source;
  91.                 }
  92.  
  93.                 [Inspectable(type='String', name='source')]
  94.                 public function set source(v:String):void
  95.                 {
  96.                         _source = v;
  97.                 }
  98.  
  99.                 public function get required():Boolean
  100.                 {
  101.                         return _required;
  102.                 }
  103.                
  104.                 [Inspectable(type='Boolean', name='required')]
  105.                 public function set required(v:Boolean):void
  106.                 {
  107.                         _required = v;
  108.                 }
  109.  
  110.                 public function get index():int
  111.                 {
  112.                         return _index;
  113.                 }
  114.  
  115.                 public function set index(v:int):void
  116.                 {
  117.                         _index = v;
  118.                 }
  119.  
  120.  
  121.         }
  122. }

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).

ACTIONSCRIPT:
  1. package core.mxml
  2. {
  3.         import core.model.CustomModelLocator;
  4.        
  5.         import flash.events.MouseEvent;
  6.        
  7.         import mx.collections.ArrayCollection;
  8.         import mx.containers.Form;
  9.         import mx.controls.Alert;
  10.         import mx.events.FlexEvent;
  11.         import mx.validators.Validator;
  12.        
  13.         import spark.components.Button;
  14.  
  15.         public class CustomFormBase extends Form
  16.         {
  17.                 public var send:Button;
  18.                 private var _source:ArrayCollection;
  19.                 private var _model:CustomModelLocator;
  20.                 private var _dataConfig:String;
  21.                
  22.                
  23.                
  24.                 public function CustomFormBase()
  25.                 {
  26.                         _model = CustomModelLocator.getInstance();
  27.                         super();
  28.             addEventListener(FlexEvent.CREATION_COMPLETE,doCreationComplete);
  29.                 }
  30.                
  31.                 private function doCreationComplete(event:FlexEvent):void
  32.                 {                       
  33.             send.addEventListener(MouseEvent.CLICK,submit);
  34.                 }
  35.                
  36.                 protected function submit(event:MouseEvent):void
  37.                 {
  38.                          var _validators:Array = new Array();
  39.                         for(var i:int=0;i<_source.length;i++){
  40.                 _validators.push(_source[i].validator);
  41.                         }
  42.                     _validators = Validator.validateAll(_validators);
  43.             if (_validators.length == 0) {
  44.                 Alert.show("Preenchimento correto", "SUCCESSO");
  45.             }
  46.                 }               
  47.  
  48.                
  49.                 public function get source():ArrayCollection
  50.                 {
  51.                         return _source;
  52.                 }
  53.                
  54.                 public function get dataConfig():String
  55.                 {
  56.                         return _dataConfig;
  57.                 }
  58.                
  59.                 [Bindable]
  60.                 [Inspectable(type='String', name='dataConfig')]
  61.                 public function set dataConfig(v:String):void
  62.                 {
  63.                         _dataConfig = v;
  64.                         _source = _model[v];
  65.                 }
  66.  
  67.                
  68.         }
  69. }

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)

CODE:
  1. <mxml:CustomFormBase
  2.                 xmlns:fx="http://ns.adobe.com/mxml/2009"
  3.                 xmlns:s="library://ns.adobe.com/flex/spark"
  4.                 xmlns:mx="library://ns.adobe.com/flex/halo"
  5.                 xmlns:mxml="core.mxml.*">
  6.                 <mx:Repeater id="configure" dataProvider="{source}">
  7.                         <mx:FormItem label="{configure.currentItem.label}" width="100%">
  8.                                 <mxml:CustomInput width="100%"
  9.                                         source="{dataConfig}"
  10.                     name="{configure.currentItem.id}" 
  11.                     message="{configure.currentItem.message}"
  12.                     required="{configure.currentItem.required}"
  13.                     validateType="{configure.currentItem.validateType}"
  14.                     text="{configure.currentItem.text}"
  15.                     index="{configure.currentIndex}" />
  16.                         </mx:FormItem>           
  17.         </mx:Repeater>
  18.         <mx:FormItem width="100%" horizontalAlign="right">
  19.                  <s:Button id="send" label="Submit" />       
  20.         </mx:FormItem>
  21. </mxml:CustomFormBase>

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.

ACTIONSCRIPT:
  1. package core.mxml {
  2.     import core.model.CustomModelLocator;
  3.    
  4.     import mx.collections.ArrayCollection;
  5.    
  6.     import spark.components.Application;
  7.  
  8.    
  9.    
  10.     public class CustomApplication extends Application
  11.     {
  12.        
  13.            
  14.         [Bindable] private var _model:CustomModelLocator;
  15.        
  16.         public function CustomApplication()
  17.         {
  18.             _model = CustomModelLocator.getInstance();
  19.             super();
  20.         }
  21.    
  22.         public function get dataConfig1():String
  23.         {
  24.             return _model.DATASOURCE1;
  25.         }
  26.        
  27.         public function get dataConfig2():String
  28.         {
  29.             return _model.DATASOURCE2;
  30.         }
  31.  
  32.     }
  33. }

E adicionamos os dados (fake) fixos.

ACTIONSCRIPT:
  1. package core.model
  2. {
  3.         import mx.collections.ArrayCollection;
  4.  
  5.         [Bindable]
  6.         public class CustomModelLocator
  7.         {
  8.                 public const DATASOURCE1:String'dataConfig1';
  9.                 public const DATASOURCE2:String'dataConfig2';
  10.                
  11.                 public var dataConfig1:ArrayCollection;
  12.                
  13.                 public var dataConfig2:ArrayCollection;           
  14.    
  15.                
  16.                 static private var instance:CustomModelLocator;
  17.                
  18.         static public function getInstance() : CustomModelLocator
  19.         {
  20.             if ( instance == null ){
  21.              instance = new CustomModelLocator(new CustomSingleton());
  22.             }
  23.             return instance;
  24.        }
  25.                
  26.                
  27.        public function CustomModelLocator(singleton:CustomSingleton)
  28.        {
  29.            if ( singleton == null ){
  30.                 throw new Error( "Construção inválida" );
  31.            }else{
  32.                 dataConfig1 = new ArrayCollection([
  33.                     {label:'Nome',message:'Nome inválido',validateType:'noblank',id:'nome',text:'Pedro Claudio',required:true},
  34.             {label:'E-mail',message:'E-mail inválido', validateType:'email',id:'email',text:'',required:true}
  35.                ]);     
  36.                 dataConfig2 = new ArrayCollection([
  37.             {label:'Endereço',message:'Endereço inválido',validateType:'noblank',id:'end',text:'',required:true },
  38.                         {label:'Bairro',message:'Bairro inválido',validateType:'noblank',id:'bairro',text:'',required:false},
  39.                         {label:'Cidade',message:'Cidade inválida',validateType:'noblank',id:'bairro',text:'',required:true }
  40.            ]);             
  41.            }                   
  42.        }
  43.    }
  44. }
  45. class CustomSingleton {}

Por fim nossa chamada mãe.

CODE:
  1. <mxml:CustomApplication
  2.         xmlns:fx="http://ns.adobe.com/mxml/2009"
  3.         xmlns:s="library://ns.adobe.com/flex/spark"
  4.         xmlns:mx="library://ns.adobe.com/flex/halo"
  5.         xmlns:mxml="core.mxml.*" viewSourceURL="srcview/index.html">
  6.         <mx:HDividedBox>
  7.                 <s:Panel width="350">
  8.                         <mxml:CustomForm dataConfig="{dataConfig1}"  width="100%" />
  9.                 </s:Panel>
  10.                 <s:Panel width="350">
  11.                         <mxml:CustomForm dataConfig="{dataConfig2}"  width="100%" />
  12.                 </s:Panel>
  13.         </mx:HDividedBox>
  14. </mxml:CustomApplication>

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.

Compartilhe:

  • RSS
  • Twitter
  • del.icio.us
  • Facebook
  • MySpace
  • LinkedIn
  • Google Bookmarks
Por Pedro Silva em 30/September/2009 | Comentar | Trackback


No Translations

Adicionar comentário

(requerido)
(requerido, não será publicado)