I've a Core Data model class with a customer ID attribute. It's bound to a form cell. When the user finishes editing the text I want a chance to convert their entry to upper case, using logic which depends on the old and new values.
Ideally I want to keep the behavior close to the view where it belongs, using an object I can instantiate in the nib and hook up to the text cells. But I'd settle for an object I had to hook up to the model.
I've implemented this three different ways:
NSControlTextEditingDelegate
All three implementations have problems. The issues, respectively:
controlTextDidBeginEditing:
calls (and the old value is gone by the time controlTextDidEndEditing:
is called). Furthermore tabbing in and out of the field without typing anything triggers a call to controlTextDidEndEditing:
.How would you solve this problem?
After some discussion here, it sounds like some possible ways to do tho:
I tried both. More issues:
editWithFrame:inView:editor:delegate:event:
isn't always called upon entering a field, so it's difficult to access the old value in endEditing:
.New solution is a refinement on my original #2: text editing delegate implementing NSControlTextEditingDelegate
.
Instead of controlTextDidBeginEditing:
and controlTextDidEndEditing:
, implement only control:textShouldEndEditing:
. In that method, manipulate the text if necessary, then return YES.
I instantiate this in the nib and make it the form's delegate (not the cells'). In the code below I get the old value using infoForBinding:
but if you aren't using bindings, you could add an outlet to the model object instead.
-(BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor {
NSCell *cell = [(NSForm *)control selectedCell];
NSString *identifier = [(NSCell *)[(NSForm *)control selectedCell] identifier];
if (!identifier) return YES;
NSDictionary *bindingInfo = [cell infoForBinding:@"value"];
if (!bindingInfo) return YES;
NSString *oldValue = [[bindingInfo valueForKey:NSObservedObjectKey] valueForKeyPath:[bindingInfo valueForKey:NSObservedKeyPathKey]];
NSString *newValue = cell.stringValue;
if ([identifier isEqualTo:@"firstField"]) {
if (criteria)
cell.stringValue = ....;
} else if ([identifier isEqualTo:@"secondField"]) {
if (criteria)
cell.stringValue = ....;
}
return YES;
}