Re: NSTextField: edits are committed even when -control:isValidObject: returns NO
Re: NSTextField: edits are committed even when -control:isValidObject: returns NO
- Subject: Re: NSTextField: edits are committed even when -control:isValidObject: returns NO
- From: Matthew LeRoy <email@hidden>
- Date: Thu, 11 Jul 2013 18:23:34 +0000
- Thread-topic: NSTextField: edits are committed even when -control:isValidObject: returns NO
Right; I recognize that clicking the checkbox doesn't cause a change in the first responder, and so any pending edits just get discarded when the button is disabled in the action method for the checkbox. That's exactly what I'm seeing when the user enters an invalid value without pressing tab/return/enter and then unchecks the box -- the edit is just discarded without any attempt at being committed or validated, and the text field reverts back to the previous value from before the user made their edit. (Or rather, perhaps field editor is just dismissed and the text field never even sees the potential new, invalid, value?)
It's when the user *does* press tab/return/enter, or otherwise tries to change the first responder, that things behave strangely. In that case an attempt is made to commit the value, which calls my control:isValidObject: and I return NO, and the field editor remains first responder (or at least it appears to)… but if the user then unchecks the box, the text field shows the invalid value rather than the previous value. That's what makes me think that the invalid value is actually being committed to the underlying NSTextField upon pressing tab/return/enter or trying to change the first responder, even though I'm returning NO -- because otherwise I would expect the text field to still have the previous valid value.
I had previously considered the same approach you suggested regarding adding to the checkbox's action method. The problem is that our desired behavior is to allow the checkbox to be unchecked at any time, and any uncommitted edits simply be discarded whether they are valid or not. That's what we're getting in the first case above, but since it seems that the invalid value is getting committed from the field editor to the NSTextField even when control:isValidObject: returns NO, simply asking the field editor to discard any pending edits doesn't help; the NSTextField's object value has already been changed to the invalid text and that's what we see in the disabled text field.
I did some more looking through the docs and I see that the NSTextDelegate protocol (to which NSTextViewDelegate, the field editor's delegate protocol, conforms) also has a -textShouldEndEditing: method. Perhaps validating and rejecting the pending edit there would prevent it from being committed to the NSTextField? Though, my understanding is that a field editor's delegate is always the control for which it is the field editor (e.g. my NSTextField). That means I would either have to set the field editor's delegate to something else -- which could potentially break other code which expects the NSTextField to be the delegate -- or subclass NSTextField and implement textShouldEndEditing: there.
On Jul 11, 2013, at 12:39 PM, Keary Suska <email@hidden>
wrote:
> On Jul 11, 2013, at 9:00 AM, Matthew LeRoy wrote:
>
>> I'm trying to implement some input validation on an NSTextField using NSControlTextEditingDelegate's -control:isValidObject: method -- simple stuff like validating that the entered text is parsable as a number, falls within a certain range, etc. (I know that NSNumberFormatter is the obvious choice for this scenario, but I'm working with requirements that require more low-level customizability, particularly in the content of the error message and how it is presented to the user, than NSNumberFormatter allows.) I've got things generally working; the delegate method gets called, I validate the user's entry and return NO if it is invalid, and the text field remains first responder.
>>
>> The obstacle I've encountered is that in some cases my text field is a subordinate control that is enabled/disabled based on a checkbox elsewhere in my view. If the user enters something invalid and attempts to commit the edit by pressing tab/enter/return, I validate and display the error message and the text field remains first responder, as desired. However, if the user then unchecks the controlling checkbox -- causing the text field to be disabled via -setEnabled:NO in my view controller -- the text field is disabled but it keeps the invalid text.
>>
>> At this point, the user has successfully circumvented my input validation; they can just re-check the checkbox and the text field is reenabled containing the invalid text. Worse, if the user puts key focus in the NSTextField again but does not make any edits and then tabs out, the validation is not triggered because there are no pending edits. I do note that if the user enters invalid text but does not attempt to commit the edit and then unchecks the checkbox, the NSTextField is disabled and the text reverts back to what it was before the user made their edit. It seems that even though I'm returning NO from -control:isValidObject:, the edit is still 'committed' from the field editor to the NSTextField. What I want is for the text field to revert back to the previous valid entry upon unchecking the box, even after the user attempts to commit the invalid edit and is presented with an error message.
>>
>> So, it sounds like -control:isValidObject: might be too late in the pipeline to validate and prevent the edit from being committed in the first place. Any suggestions for an earlier point to hook in my validation? I did try -control:textShouldEndEditing:, but still see the same behavior. Or, a different approach to accomplish what I'm after?
>
> It may be more likely the case that because a checkbox is a button, buttons do not cause a change in the first responder so there is no explicit "commit" of the editing value. It is curious, however, that when the field is disabled it retains the invalid value. I would file a radar on that...
>
> Anyway, I would add to the action method for the checkbox to make the view controller commit any pending edits and if it fails to reject the change in the button state and hence disabling the NSTextField.
>
> HTH,
>
> Keary Suska
> Esoteritech, Inc.
> "Demystifying technology for your home or business"
>
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden