CoreData: Filtrer un tableau sans SearchField

cestlogiquecestlogique Membre
20:49 modifié dans API AppKit #1
Hello!

La manière de spécifier un prédicat de recherche pour un SearchField est limpide. On peut facilement afficher uniquement les employés dont le manager est X en tapant tout ou partie de son nom grâce au prédicat suivant (basé sur le tutorial d'Apple
manager.fullNameAndID contains $value


Mais comment faire pour afficher tous les employés dirigés par X en sélectionnant son nom dans un pop-up menu??
Comment doit-on configurer le binding "value" de la tableView?
Doit-on, et si oui comment, configurer le binding " filterPredicate" de l'ArrayController (ce binding est très mal documenté, d'ailleurs)?

Si quelqu'un a des infos?

Merci! :why?:

Réponses

  • cestlogiquecestlogique Membre
    20:49 modifié #2
    Bon, il m'aura fallu la journée B) pour finalement me rabattre sur une solution programmatique. :crackboom:-

    Le pop-up menu envoie une action à  un controller qui se charge de fetcher (un nouveau terme à  transposer...) l'ArrayController:
    <br />-(IBAction)fetchEmployeesForManager:(id)sender {<br />NSString * manager = [sender titleOfSelectedItem];<br />NSPredicate *predicate = [NSPredicate predicateWithFormat:@&quot;manager.name like %@&quot;, manager];<br />[employeesAC setFetchPredicate:predicate];<br />/*En fait, un [employeesAC fetch:nil]; est inutile:<br />définir un nouveau prédicat a pour effet de refetcher le tableau...*/<br />}<br />
    


    Ce qui n'empêche pas que si vous avez une solution un peu plus bindante, vous êtes les bienvenus. :o
  • ClicCoolClicCool Membre
    20:49 modifié #3
    Bonjour cestlogique :)

    Désolé pour la réponse tardive mais j'ai à  peine eu le temps de tâter un peu du core data hier.

    Oui :), il y a une solution plus élégante faisant intervenir les bindings mais nécessitant un peu de code tout de même.

    En dehors des searchFields dont c'est le rôle (qu'ils assument admirablement) il ne me semble pas qu'il y ait de classe qui expose la clef "search/prédicate" aux bindings :(

    Alors plutot que de tenter de binder un hypothétique "search/prédicate" du popUp à  ton arrayController, il faut inverser l'approche et binder la clef "filterPredicate" du arrayController à  la sélection de ton popUp.

    Pour reprendre le tuto d'Apple dont tu sembles parler avec les Departments et Employees ...:

    -A- SOUS IB

    -1 Crées un 3 ème ArrayController (bindé comme les 2 autres pour le "contentSet" et le "managedObjetContext")
    -2 Crées ton pupUp et bindes le comme suis:
                . Content sur ton ArrayCtrl/ArrangedObjects
                . ContentValues sur ton ArrayCtrl/ArrangedObjects/fullNameAndID
                . SelectedIndex sur ton ArrayCtrl/SelectionIndex

    -3 Bindes le ArrayController qui gère la tableView par son "Controller content parameter / filterPrédicate" à  ton controllerDePopUp/selectedObjects". Et c'est là  qu'est l'astuce utilises le champ "value Transformer" du binding en y écrivant par exemple "predicateBossLastName".

    -B- SOUS Xcode: Crées ton transformer
    -1 crées une classe dérivée de NSObject en laissant le header vide:
    <br />#import &lt;Cocoa/Cocoa.h&gt;<br />@interface PredicateTransformer : NSValueTransformer {<br />}<br />@end<br />
    

    Et dans le fichier d'implémentation à  la sauvage et pour le test tu peux mettre:
    #import &quot;PredicateTransformer.h&quot;<br />@implementation PredicateTransformer<br />+ (Class)transformedValueClass {<br />    return [NSString class];<br />}<br />+ (BOOL)allowsReverseTransformation {<br />    return NO;<br />}<br />- (id)transformedValue:(id)aValue<br />{<br />	if ([aValue count]){<br />		id selectInPopUp = [aValue objectAtIndex:0];<br />		if (selectInPopUp) {<br />			NSPredicate *predicate = [NSPredicate predicateWithFormat:@&quot;manager.lastName like %@&quot;, //selectInPopUp];<br />				[selectInPopUp valueForKey:@&quot;lastName&quot;]];<br />			return predicate;<br />		}<br />	}<br />	return nil;<br />}<br />@end
    


    Enfin n'oublies pas de déclarer ton transformer pour que IB fasse la jonction avec le nom déclaré dans le binding.
    Dans le .m de myDocument, crée la méthode +initialise (si c'est pas déjà  fait) et écris simplement:
    + (void)initialize{<br />	// Créons une instance de notre &quot;value transformer&quot;<br />	NSValueTransformer *transformeur = [[PredicateTransformer alloc] init];<br />	// Déclarons la<br />	[NSValueTransformer setValueTransformer:transformeur forName:@&quot;predicateBossLastName&quot;]; // MEME NOM QUE DECLARE A I.B.<br />}
    


    Et voilà  ça roule ma poule ;)
    la TableVue affiche maintenant la liste des Employees ayant un Manager qui a le même prénom que celui sélectionné dans le popUp le tout bien gentilment mis à  jour par nos chers bindings  :)

    Evidemment il faut ajouter à  ce squelette la possibilité que le popUp ne sélectionne aucun Employee et gérer ce cas pour que la tableView affiche alors tous les employees.
    Et tant qu'à  faire le mieux est de créer un Transformer "passe partout" qui soit capable de créer un prédicate en fonction de la clef sélectionnée dans un autre PopUp par exemple.

    Mais bon l'idée est là , les détails ne sont bien compliqués à  gérer maintenant ;)

    @+
  • cestlogiquecestlogique Membre
    20:49 modifié #4
    Hello ClicCool!

    Chapeau pour cette solution qui représente un bon modèle pour utiliser le binding "filter predicate".

    À propos, as-tu vu mon nouveau message là ?

    Cestlogique.
Connectez-vous ou Inscrivez-vous pour répondre.