react-native
react-native copied to clipboard
TextInput clears text when secureTextEntry is true
Description
Hi, I am having an issue with my UITextField, When a secureTextEntry is true and I try to edit it, it keeps getting cleared. I understand that it works as intended by IOS, but I would like to keep password value when I try to edit.
Version
0.70.0
Output of npx react-native info
System: OS: macOS 12.3.1 CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz Memory: 30.74 MB / 16.00 GB Shell: 5.8 - /bin/zsh Binaries: Node: 16.15.0 - /usr/local/bin/node Yarn: 1.22.17 - /usr/local/bin/yarn npm: 9.2.0 - ~/reactnative/node_modules/.bin/npm Watchman: 2022.10.03.00 - /usr/local/bin/watchman Managers: CocoaPods: 1.11.3 - /usr/local/bin/pod SDKs: iOS SDK: Platforms: DriverKit 21.4, iOS 15.5, macOS 12.3, tvOS 15.4, watchOS 8.5 Android SDK: Not Found IDEs: Android Studio: 2021.3 AI-213.7172.25.2113.9014738 Xcode: 13.4.1/13F100 - /usr/bin/xcodebuild Languages: Java: 11.0.16.1 - /usr/bin/javac npmPackages: @react-native-community/cli: Not Found react: ^18.2.0 => 18.2.0 react-native: ^0.70.0 => 0.70.6 react-native-macos: Not Found npmGlobalPackages: react-native: Not Found
Steps to reproduce

Snack, code example, screenshot, or link to a repository
After looking for a workaround, I was able to modify native code in node module using patch-package
Here is the path i tried to edit code
// node_modules/react-native/
// Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m
Before
// node_modules/react-native/
// Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m
- (BOOL)textField:(__unused UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *newText =
[_backedTextInputView.textInputDelegate textInputShouldChangeText:string inRange:range];
if (newText == nil) {
return NO;
}
if ([newText isEqualToString:string]) {
_textDidChangeIsComing = YES;
return YES;
}
NSMutableAttributedString *attributedString = [_backedTextInputView.attributedText mutableCopy];
[attributedString replaceCharactersInRange:range withString:newText];
[_backedTextInputView setAttributedText:[attributedString copy]];
// Setting selection to the end of the replaced text.
UITextPosition *position =
[_backedTextInputView positionFromPosition:_backedTextInputView.beginningOfDocument
offset:(range.location + newText.length)];
[_backedTextInputView setSelectedTextRange:[_backedTextInputView textRangeFromPosition:position toPosition:position]
notifyDelegate:YES];
[self textFieldDidChange];
return NO;
}
After
// node_modules/react-native/
// Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m
- (BOOL)textField:(__unused UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
//Setting the new text.
NSString *updatedString = [textField.text stringByReplacingCharactersInRange:range withString:string];
textField.text = updatedString;
//Setting the cursor at the right place
NSRange selectedRange = NSMakeRange(range.location + string.length, 0);
UITextPosition* from = [textField positionFromPosition:textField.beginningOfDocument offset:selectedRange.location];
UITextPosition* to = [textField positionFromPosition:from offset:selectedRange.length];
textField.selectedTextRange = [textField textRangeFromPosition:from toPosition:to];
//Sending an action
[textField sendActionsForControlEvents:UIControlEventEditingChanged];
return NO;
}
it solved the password reset problem. However As you can see, there is a major flaw in this code.
The variable called _backedTextInputView has disappeared, and modified code has applied to all textField, so consonants and vowels are separated when writing in Korean.
So, I wonder if there is a way to apply the after code written above only when secureTextEntry is true while maintaining the existing code.
p.s. I wonder if React-native team can generate the corresponding props. (e.g. textFiled.clearsOnBeginEditing.)
Hey I have the same problem but I can't find the code inside node_modules/react-native to change it. Please help!!!
@NarekAvagyan777 Sorry for late reply, you can change native code below path.
node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m
This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.
This issue still exists. Do you have any workarouns?
Issue is still happening on IOS.
how to get rid of that yellow background for inputs when u choose to "use a strong password"?
@AlgoRoots Thanks for sharing the solution, but it's leading to another issue. The swipe-to-type gesture was not working, and the IOS app was hanging and crashing. Here's the modified code with a solution to both issues.
- (BOOL)textField:(__unused UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string {
// Step 1: Handle secureTextEntry to avoid text clearing
if (textField.isSecureTextEntry) {
// Setting the new text to avoid the text clearing issue
NSString *updatedString = [textField.text stringByReplacingCharactersInRange:range withString:string];
textField.text = updatedString;
// Step 2: Set the cursor at the right place
NSRange selectedRange = NSMakeRange(range.location + string.length, 0);
UITextPosition* from = [textField positionFromPosition:textField.beginningOfDocument offset:selectedRange.location];
UITextPosition* to = [textField positionFromPosition:from offset:selectedRange.length];
textField.selectedTextRange = [textField textRangeFromPosition:from toPosition:to];
// Step 3: Send an action to notify of the change
[textField sendActionsForControlEvents:UIControlEventEditingChanged];
return NO;
}
// Step 4: Handle regular text entry to support swipe gestures
NSString *newText = [_backedTextInputView.textInputDelegate textInputShouldChangeText:string inRange:range];
if (newText == nil) {
return NO;
}
if ([newText isEqualToString:string]) {
_textDidChangeIsComing = YES;
return YES;
}
NSMutableAttributedString *attributedString = [_backedTextInputView.attributedText mutableCopy];
[attributedString replaceCharactersInRange:range withString:newText];
[_backedTextInputView setAttributedText:[attributedString copy]];
// Setting selection to the end of the replaced text.
UITextPosition *position = [_backedTextInputView positionFromPosition:_backedTextInputView.beginningOfDocument offset:(range.location + newText.length)];
[_backedTextInputView setSelectedTextRange:[_backedTextInputView textRangeFromPosition:position toPosition:position] notifyDelegate:YES];
[self textFieldDidChange];
return NO;
}
```
@AlgoRoots Thanks for sharing the solution, but it's leading to another issue. The swipe-to-type gesture was not working, and the IOS app was hanging and crashing. Here's the modified code with a solution to both issues.
// Step 1: Handle secureTextEntry to avoid text clearing if (textField.isSecureTextEntry) { // Setting the new text to avoid the text clearing issue NSString *updatedString = [textField.text stringByReplacingCharactersInRange:range withString:string]; textField.text = updatedString; // Step 2: Set the cursor at the right place NSRange selectedRange = NSMakeRange(range.location + string.length, 0); UITextPosition* from = [textField positionFromPosition:textField.beginningOfDocument offset:selectedRange.location]; UITextPosition* to = [textField positionFromPosition:from offset:selectedRange.length]; textField.selectedTextRange = [textField textRangeFromPosition:from toPosition:to]; // Step 3: Send an action to notify of the change [textField sendActionsForControlEvents:UIControlEventEditingChanged]; return NO; } // Step 4: Handle regular text entry to support swipe gestures NSString *newText = [_backedTextInputView.textInputDelegate textInputShouldChangeText:string inRange:range]; if (newText == nil) { return NO; } if ([newText isEqualToString:string]) { _textDidChangeIsComing = YES; return YES; } NSMutableAttributedString *attributedString = [_backedTextInputView.attributedText mutableCopy]; [attributedString replaceCharactersInRange:range withString:newText]; [_backedTextInputView setAttributedText:[attributedString copy]]; // Setting selection to the end of the replaced text. UITextPosition *position = [_backedTextInputView positionFromPosition:_backedTextInputView.beginningOfDocument offset:(range.location + newText.length)]; [_backedTextInputView setSelectedTextRange:[_backedTextInputView textRangeFromPosition:position toPosition:position] notifyDelegate:YES]; [self textFieldDidChange]; return NO; }
Care to create a patch and a PR? thanks!
https://github.com/facebook/react-native/issues/46154
I believe @adnan-khan1122 is waiting for feedback on #45964 that PR should close this and #46154
I am working on a project with react native "react-native": "0.74.1", and I've tried both the @adnan-khan1122 and @AlgoRoots solution by pasting the code in the file mentioned above as node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m
but I am still facing the issue
did i miss a step or the patch is no longer compatible with new version
@alimurad-1 patch is still valid. Don't forget to apply patching after adding code using npx patch-package react-native and re-install IOS app. It should work.
@alimurad-1 patch is still valid. Don't forget to apply patching after adding code using
npx patch-package react-nativeand re-install IOS app. It should work.
reinstalling the app resolved the issue...thank you