NSTokenField does not check token on blur
Asked Answered
A

3

7

I have an NSTokenField which allows the user to select contacts (Just like in Mail.app). So the NSTextField is bound to an array in my model.recipient instance variable.

The user can now select an entry from the auto completion list e.g. Joe Bloggs: [email protected] and as soon as he hits Enter the token (Joe Bloggs) is displayed and model.recipients now contains a BBContact entry.

Now if the user starts to type some keys (so the suggestions are shown) and then hits Tab instead of Enter the token with the value of the completion text (Joe Bloggs: [email protected]) is created and the NSTokenFieldDelegate methods did not get called, so that I could respond to this event. The model.recipient entry now contains an NSString instead of a BBContact entry.

Curiously the delegate method tokenField:shouldAddObjects:atIndex: does not get called, which is what I would expect when the user tabs out of the token field.

enter image description here

Ampersand answered 16/8, 2011 at 12:24 Comment(0)
C
6

Pressing tab calls isValidObject on the delegate so return NO for NSTokenField in it however you want to return YES if there are no alphanumeric characters in it otherwise the user won't be able to focus away from the field (the string contains invisible unicode characters based on how many tokens exist)

The less fragile implementation i could come up with is:

- (BOOL)control:(NSControl *)control isValidObject:(id)token
{
    if ([control isKindOfClass:[NSTokenField class]] && [token isKindOfClass:[NSString class]])
    {
        if ([token rangeOfCharacterFromSet:[NSCharacterSet alphanumericCharacterSet]].location == NSNotFound) return YES;
        return NO;
    }
    return YES;
}
Colly answered 5/2, 2014 at 16:39 Comment(0)
A
0

I was able to solve the problem using @valexa's suggestions. In case of a blur with TAB I have to go through all entries and look up my contact-objects for any strings.

- (BOOL)control:(NSControl *)control isValidObject:(id)token{
    if ([control isKindOfClass:[NSTokenField class]] && [token isKindOfClass:[NSString class]])
    {
        NSTokenField *tf = (NSTokenField *)control;

        if ([token rangeOfCharacterFromSet:[NSCharacterSet alphanumericCharacterSet]].location == NSNotFound){
            return YES;
        } else {

            // We get here if the user Tabs away with an entry "pre-selected"
            NSMutableArray *set = @[].mutableCopy;
            for(NSObject *entry in tf.objectValue){

                GSContact *c;
                if([entry isKindOfClass:GSContact.class]){
                    c = (GSContact *)entry;
                }

                if([entry isKindOfClass:NSString.class]){

                    NSString *number = [[(NSString *)entry stringByReplacingOccurrencesOfString:@">" withString:@""]
                                        componentsSeparatedByString:@"<"][1];
                    c = [self findContactByNumber:number];
                }

                if(c) [set addObject:c];
            }

            [control setObjectValue:set];
        }
    }
    return YES;
}

enter image description here

Ampersand answered 14/2, 2014 at 13:17 Comment(1)
And you award your specific implementation of my solution the points for answering this question ? I think that might be against the rules of stackoverflow.Colly
T
-1

This could be because the "enter" key might send the event of the token field to it's action where the "tab" key just adds text to it. You could try to set the -isContinuous property to YES and see if you get the desired results.

Toughen answered 8/11, 2011 at 20:0 Comment(2)
That sounded promising so I quickly tried it out, but the issue persists so I still have the same behaviour.Ampersand
I got it working now using the isValidObject callbackAmpersand

© 2022 - 2024 — McMap. All rights reserved.