I. Gestion de la liste des contacts▲
I-A. Modification d'un contact▲
Pour continuer la réalisation du tutoriel, nous allons poursuivre à partir du fichier zip téléchargeable ici, celle-ci contient l'ensemble du code source de la partie 1 avec les fichiers nécessaires à la partie 2 que l'on va compléter pendant ce tutoriel.
Pour importer ce projet dans votre workspace, il faudra refaire la même manipulation que dans la partie 1, suivez donc cette procédure.
L'ajout, la modification et la suppression d'un contact utilisent la même procédure que pour la récupération de la liste de contacts, les seules différences sont dans le traitement de la réponse du service. Pour mettre en place ces fonctionnalités, il faut tout d'abord modifier MainView et son helper pour déclencher l'événement de mise à jour d'un contact.
//view/MainView.mxml
...
<
mx:
HBox
x=
"800"
styleName=
"saveBox"
id=
"saveBox"
moveEffect=
"{Move}"
width
=
"250"
height
=
"40"
>
<
mx:
Label text
=
"Save changes ?"
/>
<
mx:
Button
icon=
"{EmbeddedMedia.getInstance().saveContactImg}"
buttonMode=
"true"
styleName=
"btnTopContact"
width
=
"30"
height
=
"30"
click=
"{helper.updateContact()}"
/>
...
Quand l'utilisateur clique sur le bouton pour faire la mise à jour, la méthode updateContact dans MainViewHelper est appelée pour lancer le traitement par le contrôleur grâce à la méthode updateContact :
//helper/MainViewHelper.as
...
/**
* passe à l'état BTN_SAVE_VIEW_STATE : saveBox apparait / topButtonContact disparait
* appel à la méthode updateContact dans MainController
* */
public
function
updateContact
(
):
void
{
getMainView
(
).
currentState =
BTN_SAVE_VIEW_STATE;
if
(
getMainView
(
).
leftSmartForm.
isUpdate)
{
switchMode
(
);
var
updatedContactVO :
ContactVO =
getCurrentContact
(
);
MainController.
getInstance
(
).
updateContact
(
updatedContactVO );
}
}
/**
* Créer un contactVO du contact actuellement sélectionné
* @return ContactVO
* */
public
function
getCurrentContact
(
) :
ContactVO
{
var
dtLeft :
DictionaryTable =
getMainView
(
).
leftSmartForm.
source;
var
dtRight :
DictionaryTable =
getMainView
(
).
rightSmartForm.
source;
var
dtBottom :
DictionaryTable =
getMainView
(
).
bottomSmartForm.
source;
dtLeft.
putAll
(
dtRight );
dtLeft.
putAll
(
dtBottom );
var
contactOut :
ContactVO =
ContactVO
(
MapUtils.
getObjectFromDictionaryTable
(
dtLeft,
ContactVO ) );
return
contactOut;
}
...
Le contrôleur appelle le service distant en utilisant la classe ContactUpdateResponder :
//control/MainController.as
...
/**
* Appelle updateContact dans businessDelegate et passe en paramètre le responder qui traite la réponse
* */
public
function
updateContact
(
pContactVO :
ContactVO ) :
void
{
var
updatedContactTO :
ContactTO =
wrapContactVO
(
pContactVO );
getMainBusinessDelegate
(
).
updateContact
(
new
ContactUpdateResponder
(
),
updatedContactTO );
}
...
Créer la classe ContactUpdateResponder qui traite la réponse du service distant et appelle le modèle pour le mettre à jour :
//business/responder/UpdateContactResponder.as
...
public
class
ContactUpdateResponder implements
IBusinessResponder
{
public
function
ContactUpdateResponder
(
)
{
}
/**
* traitement du résultat renvoyé par le service
* Mise à jour du modèle
* */
public
function
result
(
data
:
Object
):
void
{
var
contactVO :
ContactVO =
ContactTO
(
ResultEvent
(
data
).
result ).
contacts.
getItemAt
(
0
) as ContactVO;
MainController.
getInstance
(
).
getContactModel
(
).
updateThisContact
(
contactVO );
}
public
function
fault
(
info:
Object
):
void
{
Alert.
show
(
"Error updating the contact !"
);
}
}
Le modèle met à jour la liste de contacts et notifie les « observers » qui vont rafraîchir l'affichage :
//model/ContactModel.as
...
**
*
Mise à jour du contact (
en fonction du contactId)
*
Déclenche l'événement indiquant que la liste de contact a changé
*
*/
public
function
updateThisContact
(
pContactVO :
ContactVO ) :
void
{
var
idx :
int
=
0
;
for
each (
var
contact :
ContactVO in
_contacts){
if
(
contact.
contactId ===
pContactVO.
contactId )
{
_contacts.
setItemAt
(
pContactVO,
idx );
_contacts.
refresh
(
);
notifyObservers
(
new
ContactListNotification
(
null
) );
break
;
}
idx++;
}
}
...
I-B. Ajout d'un contact▲
L'ajout et la suppression utilisent exactement le même processus sauf que le traitement est différent dans le modèle. Dans le cas de l'ajout d'un contact :
//model/ContactModel.as
...
**
*
crée un nouveau contact dans _contacts
*
Déclenche l'événement indiquant que la liste de contact a changé
*
*/
public
function
createContact
(
pContactVO :
ContactVO ) :
void
{
_contacts.
addItem
(
pContactVO );
_contacts.
refresh
(
);
notifyObservers
(
new
ContactListNotification
(
null
) );
}
...
I-C. Suppression d'un contact▲
Lors de la suppression d'un contact, on demande une validation grâce à la classe Alert :
//helper/MainViewHelper.as
/**
* Alert demandant confirmation avant suppression du contact
* */
public
function
confirmDeleteContact
(
e :
Event ) :
void
{
Alert.
show
(
"Do you really want to remove "
+
selectedContact.
firstName.
toString
(
) +
" "
+
selectedContact.
lastName.
toString
(
) +
" from your contact list ?"
,
"Remove "
+
selectedContact.
firstName.
toString
(
) +
" "
+
selectedContact.
lastName.
toString
(
) +
" :"
,
3
,
null
,
deleteContact);
}
Dans le cas de la suppression d'un contact :
//model/ContactModel.as
...
/**
* supprime un contact (en fonction du contactId)
* Déclenche l'événement indiquant que la liste de contact a changé
* */
public
function
deleteThisContact
(
pContactVO :
ContactVO ) :
void
{
var
idx :
int
=
_contacts.
getItemIndex
(
pContactVO );
var
i :
int
=
0
;
for
each (
var
contact :
ContactVO in
_contacts)
{
if
(
contact.
contactId ==
pContactVO.
contactId)
{
_contacts.
removeItemAt
(
i );
_contacts.
refresh
(
);
notifyObservers
(
new
ContactListNotification
(
null
) );
}
i++;
}
}
...
II. Création du moteur de recherche▲
Le fonctionnement du « Search Tree » est composé de deux étapes distinctes : premièrement, il faut indexer les données. « Search Tree » crée un graphe d'expressions de recherche et relie les mots aux objets qui les contiennent, d'après les options émises sur les éléments d'objet; deuxièmement, l'arborescence de recherche est à même d'effectuer des recherches en parcourant le graphe d'après une chaîne de caractères qui lui a été soumise. Cette technique est beaucoup plus performante qu'une recherche directe sur la collection, car le plus gros du travail est effectué durant la phase d'indexation. Plus la chaîne de caractères soumise est longue, plus le nombre de possibilités sur le graphe est mince.
II-A. Première étape : construire l'indexation▲
L'indexation est créée à l'aide des classes SearchTree et SearchProperty. Pour chaque propriété des objets de valeur à indexer, une SearchProperty doit être créée et un type d'indexation doit être défini. Les propriétés sont ensuite utilisées pour créer l'indexation.
//helper/MainViewHelper.as
...
/**
* passe à l'état BASE_VIEW_STATE
* appelle à la fonction initSearchTree
* déclare le premier contact de la liste comme le contact sélectionné
* */
public
function
refreshView
(
) :
void
{
baseContactView
(
);
initSearchTree
(
);
getMainView
(
).
contactList.
selectedItem =
getContactModel
(
).
getContacts
(
)[
0
]
as ContactVO;
dispatchEvent
(
new
Event
(
'selectedContactChange'
) );
}
...
/**
* on ContactListNotification :
* actualise la vue
* */
override public
function
update
(
o :
IObservable,
n:
Notification) :
void
{
dispatchEvent
(
new
Event
(
"contactListChange"
) );
refreshView
(
);
}
...
/**
* déclaration du tableau searchProperties : firstName, lastName
* début de l'indexation
* */
public
function
initSearchTree
(
) :
void
{
_tree =
new
SearchTree
(
);
var
searchProperties :
Array
=
[
new
SearchProperty
(
"firstName"
,
SearchProperty.
INDEX_TYPE_CONTAINS ),
new
SearchProperty
(
"lastName"
,
SearchProperty.
INDEX_TYPE_CONTAINS )
];
_tree.
index
(
getContactModel
(
).
getContacts
(
).
source ,
searchProperties );
}
...
Le type d'indexation impactera sur les performances plus que le nombre d'objets à indexer ou à rechercher. Le graphe de mots résultant d'une indexation à l'aide de INDEX_TYPE_CONTAINS sera plus complexe.
II-B. Seconde étape : effectuer la recherche▲
Pour effectuer la recherche, nous utilisons simplement la méthode de recherche avec une String comme critère de recherche.
//helper/MainViewHelper.as
...
/**
* on application init : renvoie par défaut tous les contacts sélectionnés dans le modèle
* Lors d'une recherche : renvoie le résultat de searchTree dans la liste de contacts du modèle
* */
[
Bindable
(
"contactListChange"
)]
public
function
get
getContactList
(
) :
Array
{
if
(
getMainView
(
).
filterTextInput.
text
==
null
||
getMainView
(
).
filterTextInput.
text
.
length
<
1
)
{
return
getContactModel
(
).
getContacts
(
).
source;
}
else
{
var
searchResult :
Array
=
_tree.
search
(
getMainView
(
).
filterTextInput.
text
).
values
(
);
return
searchResult;
}
}
...
On déclenche l'événement getContactList lors de la saisie dans DelayTextInput :
//view/MainView.mxml
...
<
elements:
DelayTextInput
width
=
"100%"
id=
"filterTextInput"
change=
"helper.dispatchEvent( new Event('contactListChange') );"
delay=
"200"
/>
...
En remplissant le champ de recherche en haut à gauche de l'application, la liste de contacts est filtrée.
Vous pouvez télécharger le code source de l'application finale ici.