La librairie DataFilterLib disponible sur Maven (en + de Google Code)
Une petite news pour annoncer la présence de ma librairie DataFilterLib sur les repository publics Maven. Si vous ne connaissez pas la DataFilterLib, allez y jeter un coup d'oeil, cela peut vous enlever une fière chandelle du pied
:
DataFilterLib – Filtrez votre donnée de manière simple et dynamique
Et le projet sur Google Code:
http://code.google.com/p/flex-datafilterlib/
Grâce à un *énorme* boulot de Frédéric Thomas (@webdoublefx), cette librairie est maintenant disponible pour vos builds Maven, dans un repository public:
https://oss.sonatype.org/index.html#nexus-search;quick~datafilter
Le processus a été très laborieux pour Frédéric, un grand merci à lui qui a réussi à publier la librairie tout en contournant les bugs de Maven
. Si vous voulez faire un build de votre projet Google Code sur Maven, vous pouvez me demander, Frédéric m'a rédigé un document détaillé.
DataFilterLib – Le multi-filtrage par l'exemple sur droomhuiscostablanca.nl
Si vous suivez flex-tutorial depuis un moment, vous connaissez peut-être le projet DataFilterLib, une librairie que j'ai créé pour vous aider à faire du multi-filtrage sur une source de donnée comme un ArrayCollection. Un peu comme si vous pouviez avoir plusieurs filterFunction cumulatives.
Sinon, session de rattrapage:
DataFilterLib – Filtrez votre donnée de manière simple et dynamique
Le but est bien ici de vous simplifier la vie en écrivant vos filtres de manière déclarative (ou en AS si vous avez envie) avec possibilité de Binding et opérations de filtrage pré-configurées.
Il y a quelques jours, un certain Wout den Teuling est venu me demander un coup de main pour utiliser la DataFilterLib dans son application. Celle-ci reçoit des données par un script PHP, en l’occurrence une liste de résidence ayant des propriétés (région, nom, type, prix, …).
Le but était de faire un multi-filtrage sur ces propriétés et sur le résultat, de faire une pagination automatique.
Et voilà le résultat! :
http://www.droomhuiscostablanca.nl/
A gauche, vous avez le filtrage par propriété (LIKE sur le nom, emplacement, type de location, prix) et au dessus des résultats, la pagination:
Voilà, le site n'est certes pas "magnifique" (le header et le footer ne devraient pas faire partie de l'application selon moi) mais c'est un bon exemple de ce qu'il est possible de faire avec cette librairie. Elle est gratuite et open source (sur Google Code), n'hésitez pas à vous en servir !
DataFilterLib – Pagination de données filtrées (ArrayCollection avec filterFunction)
On m'a posé une question très intéressante sur la DataFilterLib:
Cedric
Bonjour moi j'aurais une petite question :
Comment intégrer les fonctionnalités de filtrage sur une dataGrid dont les données sont paginées (à l'aide du paginateur disponible sur ce site)?
En effet, la DataFilterLib permet de filtrer des données côté client selon plusieurs critères, de manière déclarative (MXML) ou dynamique (AS). Elle permet, pour simplifier, de donner plusieurs filterFunction à un ArrayCollection.
Et pour la pagination (côté client), le plus simple et le plus effectif est d'utiliser aussi une filterFunction sur une ICollectionView, un ArrayCollection par exemple. La question est alors, comment combiner les deux?
Application de test
Voilà le code utilisé pour tester l'application. Le dataProvider se trouve dans un fichier à part pour faciliter la lecture:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%"
paddingRight="20" xmlns:filter="com.fnicollet.datafilter.filter.*"
xmlns:pagination="pagination.*">
<mx:Script>
<![CDATA[
import pagination.event.PaginateEvent;
import com.fnicollet.datafilter.filter.DataFilterType;
import com.fnicollet.datafilter.filter.DataFilterSingleValueOperator;
[Bindable]
private var _startIdx:int = 0;
[Bindable]
private var _endIdx:int = 999999999;
private function pageChangeHandler(e:PaginateEvent):void {
var page:int = e.index;
_startIdx = (page * e.itemsPerPage) + 1;
_endIdx = Math.min((_startIdx + e.itemsPerPage - 1), e.itemsTotal);
//txt.text = "Results: " + String(_startIdx) + " - " + String(_endIdx) + " of " + e.itemsTotal;
}
]]>
</mx:Script>
<mx:Script source="/data/StateData.as"/>
<filter:DataFilterSet id="filterSet" data="{statesData}">
<filter:dataFilterParameters>
<filter:DataFilterParameters id="simpleParam" filterType="{DataFilterType.SINGLE_VALUE}"
filterKeys="state"
filterOperator="{DataFilterSingleValueOperator.LIKE}"
filterValues="{stateInput.text}"/>
</filter:dataFilterParameters>
</filter:DataFilterSet>
<mx:Label text="Filter By State Name (Contains)" fontSize="14" fontWeight="bold"/>
<mx:TextInput id="stateInput"/>
<mx:Label text="Pagination over the filtered elements" fontSize="14" fontWeight="bold"/>
<pagination:PageSelector id="paginator" itemsPerPage="6" rangeCount="6"
itemsTotal="{statesData.length}" selectedIndex="0"
pageChange="pageChangeHandler(event)"/>
<mx:Label text="Filtered Data" fontSize="14" fontWeight="bold"/>
<mx:DataGrid rowCount="7" dataProvider="{statesData}" width="100%">
<mx:columns>
<mx:DataGridColumn dataField="state" headerText="State Name"/>
<mx:DataGridColumn dataField="sales" headerText="Sales"/>
<mx:DataGridColumn dataField="employees" headerText="Number of Employees"/>
<mx:DataGridColumn dataField="population" headerText="Population"/>
</mx:columns>
</mx:DataGrid>
<mx:Label text="Unfiltered Data" fontSize="14" fontWeight="bold"/>
<mx:DataGrid rowCount="8" dataProvider="{statesData.source}" width="100%">
<mx:columns>
<mx:DataGridColumn dataField="state" headerText="State Name"/>
<mx:DataGridColumn dataField="sales" headerText="Sales"/>
<mx:DataGridColumn dataField="employees" headerText="Number of Employees"/>
<mx:DataGridColumn dataField="population" headerText="Population"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
Un composant générique de pagination est intégré et met seulement à jour 2 variables Bindable. Il n'effectue encore aucun filtrage:
Composant Flex – Interface de Pagination générique
Premier test: Ajouter un nouveau filtre pour la pagination
Dans un premier temps, la première idée que j'ai eu fut de simplement ajouter un nouveau filtre, se comportant comme un filtre de type Interval, dont l'intervalle irait entre l'index de mon premier élément de page et le dernier élément.
Pour créer ce nouveau filtre, qui n'existe pas par défaut, il suffit de créer une classe qui hérite de "DataFilterInterval": DataFilterIntervalPagination. Pour l'ajouter en tant que filtre, il suffit d'utiliser la technique que j'expose dans cet article:
DataFilterLib – Utilisation de filtres personnalisés
Pour une utilisation dans une application, il suffit ensuite de donner:
<filter:DataFilterParameters filterClass="{DataFilterIntervalPagination}"
id="intervalPagination" filterValues="{[_startIdx, _endIdx]}"/>
Et déjà, là, premier obstacle, la méthode de filtrage de base. Pour simplifier, la DataFilterLib boucle sur la méthode "apply" de chaque filtre dont la signature est la suiavnte:
public function apply(item:Object):Boolean {
On prend ensuite chaque résultat et si au moins un d'entre eux est false, l'objet est filtré. Pour les filtres sur valeur et sur intervalle, on cherche à comparer une certaine propriété de l'item (donnée par le paramètre "filterKeys"). En pseudo-code, on a :
public function apply(item:Object):Boolean {
var value:String = item[filterKey];
if (value == filterValue){
return true;
}
return false;
}
On fait ici la distinction par rapport à une propriété de l'objet. Seulement dans notre cas, on ne veut pas comparer une des propriétés de l'objet mais bien la position de l'objet dans le dataProvider. Si son index est dans la page courante on garde l'objet, sinon on le filtre.
DataFilterLib – Using the DataFilterLib with ActionScript code only
Someone raised an issue a while ago on my DataFilterLib project:
Creating DataSetFilter in Actionscript
If you are not familiar with the DataFilterLib capabilities, this article will explain everything you need to know about it, including examples:
DataFilterLib – Filtrez votre donnée de manière simple et dynamique
As the person who raised the issue doesn't seem to be a native French speaker, this will be my first post in english on this blog
.
So this issue is actually more of a lack of documentation than a bug or anything. Every example is written in MXML, using Binding mechanisms and if you are not so familiar with ActionScript code, you might run into some issues.
Here was the MXML code to create the "Very Simple Example":
...
<mx:Script source="../data/StateData.as"/>
<filter:DataFilterSet id="filterSet" data="{statesData}">
<filter:dataFilterParameters>
<filter:DataFilterParameters id="simpleParam" filterType="{DataFilterType.SINGLE_VALUE}" filterKeys="state" filterOperator="{DataFilterSingleValueOperator.STARTS_WITH}"
filterValues="{stateInput.text}"/>
</filter:dataFilterParameters>
</filter:DataFilterSet>
<mx:Label text="Filter By State Name (Starts With)" fontSize="14" fontWeight="bold"/>
<mx:TextInput id="stateInput"/>
...
The "StateData.as" file only contains an ArrayCollection filled with USA States and some more data, named "statesData". The data wont be dynamically changed, the Data Binding is only here to set the "data" property on the DataFilterSet once it's set. Also, the "filterType" and "filterOperator" properties use Data Binding on public static constants. The curly braces aren't used for Data Binding in that situation, just to set the properties to a non-String value (class constants). We could as well have set the String value corresponding to the constant but this way, we have compile-time type checking and auto-completion.
DataFilterLib – Utilisation des jokers /wildcards sur les filtres (v1.0.2)
La DataFilterLib voit aujourd'hui l'arrivée des jokers (wildcards) pour le paramétrage des filtres. Après avoir voulu utiliser la librairie que j'ai crée dans une véritable application professionnelle, j'ai vite compris que cette fonctionnalité était indispensable afin de pouvoir correctement filtrer sa donnée à l'aide d'un composant de choix ComboBox.
Prenons l'exemple d'un choix de type d'équipement. Dans notre donnée, on pourrait avoir différents types:
- "home"
- "auto"
- "computers"
- "electro"
On stocke ces éléments dans un ArrayCollection que l'on affiche dans une DataGrid. Pour une meilleure expérience utilisateur, vous laissez votre utilisateur filtrer la donnée affichée suivant le type. Ainsi, s'il choisit "electro" dans une liste de choix, il n'aura que les équipements électriques. Vous pouvez facilement réaliser cela avec les filtres de base qui étaient présents dans la DataFilterLib (voir les exemples).
Seulement, une fois que votre une fois que votre utilisateur a choisi un élément dans la ComboBox, il ne peut plus revenir à la vue initiale avec tous les éléments. L'idée est donc de rajouter un élément à votre liste appelé "Tous les types", que l'utilisateur pourra sélectionner pour ne plus filtrer selon le type. On aura donc dans notre liste:
- "Tous les types"
- "home"
- "auto"
- "computers"
- "electro"
Vous êtes maintenant face à un problème. Si l'utilisateur choisit "Tous les types", le Binding fait que on va filtrer tous les éléments dont le type est "Tous les types", ce qui ne retournera aucun élément. Dans ce cas, la valeur "Tous les types" est notre joker (wildcard).
Dans la version 1.0.2, vous verrez donc l'arrivée d'une propriété "filterJokers" sur la classe "DataFilterParameters". Celle-ci prend soit une valeur, soit un tableau de valeurs. Le principe est celui exposé au dessus. Si on essaie de filtrer selon une valeur "joker", on ne filtre pas l'élément.
L'implémentation des filterJokers dans le code
<filter:DataFilterSet id="filterSet" data="{productData}">
<filter:dataFilterParameters>
<filter:DataFilterParameters id="tstMultiValueParameter"
filterType="{DataFilterType.SINGLE_VALUE}"
filterKeys="productType"
filterOperator="{DataFilterSingleValueOperator.EQUALS_TO}"
filterValues="{typeChooserCB.selectedItem}"
filterJokers="Any Type"/>
</filter:dataFilterParameters>
</filter:DataFilterSet>
...
<mx:ComboBox id="typeChooserCB">
<mx:dataProvider>
<mx:Array>
<mx:String>Any Type</mx:String>
<mx:String>home</mx:String>
<mx:String>computers</mx:String>
<mx:String>auto</mx:String>
<mx:String>electro</mx:String>
</mx:Array>
</mx:dataProvider>
</mx:ComboBox>
Application en ligne (onglet Using Jokers)
Voici un petit exemple d'application. Si l'onglet Using Jokers n'est pas présent dans l'application, videz votre cache navigateur






