Acentuação no Sort do DataGrid
Continuando o caso do Sort no DataGrid, que no post anterior em http://blog.dclick.com.br/2007/06/02/alterando-o-sort-default-do-datagrid-de-case-sensitive-para-case-insensitive/
onde foi relatado como se utilizar a propriedade caseInsensitive, chegamos agora no problema de tratamento de ordenação de palavras acentuadas com palavras não acentuadas. O sort executado, não consegue identificar, a partir do locale de países de língua portuguesa, que palavras acentuadas devem ser tratadas da mesma maneira que palavras sem acentuação para o caso de ordenação. Ou seja, árvore é igual a arvore quando mostramos em ordem num grid.
A solução para este caso, reside no fato da classe SortField ser responsável pela definição de qual função de comparação será usada em objetos do tipo string, para identificar a ordem. Assim com a simples extensão desta classe (ExtendedSortField), conseguimos indicar qual função de ordenação de strings deve ser usada internamente para o resultado esperado.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | package sort { import mx.collections.SortField; import mx.utils.ObjectUtil; import mx.core.mx_internal; use namespace mx_internal; public class ExtendedSortField extends SortField { override mx_internal function initCompare(obj:Object):void { var isStringField:Boolean = false; // if the compare function is not already set then we can set it if (!usingCustomCompareFunction) { if (!numeric) { if (caseInsensitive) isStringField = true; else { // we need to introspect the data a little bit var value:Object; if (name) { try { value = obj[name]; } catch (error:Error) { } } //this needs to be an == null check because !value will return true //where value == 0 or value == false if (value == null) { value = obj; } var typ:String = typeof(value); switch (typ) { case "string": isStringField = true; break; case "object": if (!(value is Date)) { isStringField = true; var test:String; try { test = value.toString(); } catch (error2:Error) {} if (!test || test == "[object Object]") { isStringField = false; } } break; } } // else } } // if if (isStringField) { compareFunction = stringCompare; } super.initCompare(obj); } /** * Pull the strings from the objects and call the implementation. */ private function stringCompare(a:Object, b:Object):int { var fa:String; try { fa = name == null ? String(a) : String(a[name]); } catch (error:Error) { } var fb:String; try { fb = name == null ? String(b) : String(b[name]); } catch (error:Error) { } var sa:String = ""; if (fa != null) { sa = String(mx.utils.ObjectUtil.copy(fa)); sa = removeSpecialChars(sa); } var sb:String = ""; if (fb != null) { sb = String(mx.utils.ObjectUtil.copy(fb)); sb = removeSpecialChars(sb); } return mx.utils.ObjectUtil.stringCompare(sa, sb, caseInsensitive); } /** * * @param value String de entrada que será modificada de acorde com a tabela ASCII extendida * @return String alterada * */ public static function removeSpecialChars(value:String):String { var patternTable:Object = new Object(); patternTable["A"] = /À|Á|Â|Ã|Ä|Å/g; patternTable["E"] = /È|É|Ê|Ë/g; patternTable["I"] = /Ì|Í|Î|Ï/g; patternTable["O"] = /Ò|Ó|Ô|Õ|Ö/g; patternTable["U"] = /Ù|Ú|Û|Ü/g; patternTable["a"] = /à|á|â|ã|ä/g; patternTable["e"] = /è|é|ê|ë/g; patternTable["i"] = /ì|í|î|ï/g; patternTable["o"] = /ò|ó|ô|õ|ö/g; patternTable["u"] = /ù|ú|û|ü/g; patternTable["C"] = /Ç/g; patternTable["c"] = /ç/g; patternTable["N"] = /Ñ/g; patternTable["n"] = /ñ/g; var result:String = value; for (var letter:String in patternTable) { result = result.replace(patternTable[letter], letter); } return result; } } } |
Mas para que isso funcione, devemos antes preparar o sort do dataProvider do DataGrid, adicionando neste, conforme o usuário interage com a coluna em questão, os fields do tipo de nossa classe extendida (ExtendedSortField).
Estendendo também a classe DataGrid, adicionamos no seu construtor um listener para o evento DataGridEvent.HEADER_RELEASE.
1 2 3 4 5 6 7 8 9 10 11 | public function ExtendedDataGrid() { // Como o listener foi criado com a mesma prioridade do listener da classe mãe, // este deve ser adicionado ANTES da adição do mesmo da classe mãe, // para que esta implementação seja executada da mesma forma, ANTES. addEventListener(DataGridEvent.HEADER_RELEASE, headerReleaseHandler, false, EventPriority.DEFAULT_HANDLER, true); super(); } |
No handler desse evento, preparamos o dataProvider com o sort adequado.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | private function headerReleaseHandler(event:DataGridEvent):void { if (!event.isDefaultPrevented()) { prepareGridColumnSort(this, dataProvider as ICollectionView, event.dataField, !sortCaseSensitive); } } /** * * @param grid Instância do DataGrid que será preparado para utilização do caseInsensitive e Numeric * @param gridDataProvider DataProvider do DataGrid, que será observado para criação da classe Sort * @return DataProvider modificado, contendo a classe Sort e SortField definida para cada DataGridColumn do DataGrid * */ private function prepareGridColumnSort(grid:DataGrid, gridDataProvider:ICollectionView, dataField:String, caseInsensitive:Boolean=true):void { var sort:Sort; var field:SortField; var column:DataGridColumn; var bFieldFound:Boolean = false; if (gridDataProvider && dataField) { sort = gridDataProvider.sort; if (sort == null) { sort = new Sort(); } for each (field in sort.fields) { if (field.name == dataField) { field.caseInsensitive = caseInsensitive; bFieldFound = true; break; } } if (!bFieldFound) { for each (column in grid.columns) { if (dataField == column.dataField) { field = new ExtendedSortField(); field.name = column.dataField; field.descending = column.sortDescending; field.caseInsensitive = caseInsensitive; if (column.sortCompareFunction != null) { field.compareFunction = column.sortCompareFunction; } field.numeric = isDataFieldNumber(gridDataProvider, dataField); sort.fields = [field]; break; } } } gridDataProvider.sort = sort; } } /** * * @param gridDataProvider Instância do DataGrid no qual será testado o campo do tipo Number * @param dataField Nome do campo que será testado * @return Resultado boolean indicando se é Number ou não * */ private function isDataFieldNumber(gridDataProvider:ICollectionView, dataField:String):Boolean { if (gridDataProvider && gridDataProvider.length > 0 && dataField) { var obj:Object = gridDataProvider[0]; if (obj.hasOwnProperty(dataField) && ((obj[dataField] is Number) || (obj[dataField] is uint) || (obj[dataField] is int))) { return true; } } return false; } |
Após estes passos, toda vez que o usuário clicar no cabeçalho de uma coluna, este evento será capturado primeiro pela nossa função handler que irá preparar o sort do dataProvider do DataGrid com nossa classe ExtendedSortField.
Esta por sua vez, sabe como comparar valores string acentuadas, retirando os caracteres especiais antes de efetuar a comparação.

Um comentário
Show de bola!!!
Deixe Seu Comentário