segunda-feira, 27 de dezembro de 2010

AutoComplete extends TextInput

Blz?!

Quando comecei a trabalhar com Flex um dos componentes mais bacanas que eu encontrei foi o AutoComplete da Adobe.
Mas olhando o source o compenente vi que é baseado em um ComboBox oque para mim não ajuda muito porque eu já tenho um componente baseado no TextInput que contém várias implementações, máscara, UpperCase, Numerico, ou seja, ter que reescrever essas implementações para o AutoComplete seria perder tempo e aumentar o nível de complexidade de manutenção, oque é um tiro no pé e como eu não gosto de atirar no meu pé eu escrevi o componente FAutoComplete que é baseado em um TextInput. Vão observar que eu fiz extends para o FTextInput, basta substituir por TextInput.

Há comentários no fonte então a história acaba aqui e vamos ao source.

Source da classe

package Componente {
  import flash.events.Event;
  import flash.events.KeyboardEvent;
  
  import mx.collections.ArrayCollection;
  import mx.controls.ComboBox;
  import mx.controls.TextInput;
  import mx.events.DropdownEvent;
  
  public class FAutoComplete extends FTextInput {
    private var
      FField: String = '',
      FDataProvider: ArrayCollection = new ArrayCollection(),
      _uCombo: ComboBox = new ComboBox();
    
    [Inspectable(
      category = "eduarmstrong", 
      defaultValue = ""
    )]
    public function get LabelField(): String {
      return(FField);
    }
    public function set LabelField(AField: String): void {
      FField = AField;
    }
    
    [Inspectable(
      category = "eduarmstrong", 
      defaultValue = ""
    )]
    public function get DataProvider(): ArrayCollection {
      return FDataProvider;
    }
    public function set DataProvider(ADataProvider: ArrayCollection): void {
      var
        I: int;
        
      // Faz add do todos os item usando um for para não alterar a estrutura do arrayCollection
      for (I = 0; I < ADataProvider.length; I++)  
        FDataProvider.addItem(ADataProvider[I]);
    }

    public function FAutoComplete() {
      // Listener para os eventos observados
      addEventListener(Event.CHANGE, proChangeEvent);
      addEventListener(KeyboardEvent.KEY_DOWN, proKeyDownEvent);
      super();
    }

    private function proKeyDownEvent(EvKey: KeyboardEvent): void {
      // Quando o usuário pressionar a seta para baixo muda o foco para comboBox
      if (EvKey.keyCode == 40) {
        if (_uCombo.visible)
          _uCombo.setFocus();
      }
      // Quando usuário pressionar Ctrl + ESPAÇO abre a lista completa  
      else if (EvKey.ctrlKey && EvKey.keyCode == 32) {
        // Removo o filtro
        FDataProvider.filterFunction = null;
        FDataProvider.refresh();
        // Exibe a comboBox
        _uCombo.open();
        _uCombo.visible = true;
        _uCombo.selectedIndex = 0;
      }
    }

    private function proChangeEvent(EvChange: Event): void {
      if (text != '') {
        FDataProvider.filterFunction = fncFiltraDataProvider;
        FDataProvider.refresh();
        
        function fncFiltraDataProvider(Item: Object): Boolean {
          var
            _rConsiste: Boolean,
            _rTamanho: int;
         
          // Tamanho da String digitada
          _rTamanho = text.length;  
          
          // Filtro para simular like ' %' do SQL
          if (String(Item[FField]).toUpperCase().substr(0, _rTamanho) == text.toUpperCase())
            _rConsiste = true;
          else
            _rConsiste = false;
          
          return _rConsiste;
        }
        
        /* Depois de aplicar a filterFunction se ainda "existir" 
        dados no arrayCollection abre a comboBox */
        if (FDataProvider.length > 0) {
          _uCombo.open();
          _uCombo.visible = true;
        }
        else
          proHideCombo();
      }
      else
        proHideCombo();
    }
    
    private function proHideCombo(): void {
      _uCombo.close();
      _uCombo.visible = false;
      setFocus();
    }
    
    private function proCloseComboBox(EvClose: DropdownEvent): void {
      proHideCombo();
      text = _uCombo.selectedItem.DS;
    }
    
    override protected function createChildren(): void {
      super.createChildren();
      
      // Configuração para comboBox
      _uCombo.labelField = FField;
      _uCombo.selectedIndex = - 1;
      _uCombo.setStyle('arrowButtonWidth', '0');
      _uCombo.editable = true;
      _uCombo.visible = false;
      _uCombo.addEventListener(DropdownEvent.CLOSE, proCloseComboBox);
      _uCombo.dataProvider = FDataProvider;

      addChild(_uCombo);
    }

    override protected function updateDisplayList(w:Number, h:Number): void {
      super.updateDisplayList(w, h);
      
      _uCombo.width = width;
      _uCombo.x = 0;
      _uCombo.y = (height + 2);
    }
  }
}

Como utilizar
[Bindable]
private var
  _rDado: ArrayCollection = new ArrayCollection([
    {CD: '1', DS:'Andriano'},
    {CD: '2', DS:'Adriana'},
    {CD: '3', DS:'Ana'},
    {CD: '4', DS:'Amanda'},
    {CD: '5', DS:'Beatriz'},
    {CD: '6', DS:'Beti'},
    {CD: '7', DS:'Barbara'},
    {CD: '8', DS:'Bia'},
    {CD: '9', DS:'Francisco'},
    {CD: '10', DS:'Fred'},
    {CD: '11', DS:'Floriano'}
  ]);
 
 
 // DataProvider - Informa o ArrayCollection que servirá de base para o componente
 // LabelField - Qual field dentro do ArrayCollection deverá ser listado  

 





Bons estudos e bom trabalho a todos.

Abraços

2 comentários:

Perfeito.
Só fiz alguns ajustes, por exemplo: Quando seta pra baixo, não ia direto pro primeiro item do combo, ajustei pra ir; e Quando seleciona o item, mandar foco pro final da palavra, antes ficava na letra digitada.

Obrigada ;)

Muito obrigado, fico contente em saber que o post foi aproveitado.

Se puder compartilhar as melhorais =D

Obrigado.

Postar um comentário

Twitter Delicious Facebook Digg Stumbleupon Favorites More