react-native icon indicating copy to clipboard operation
react-native copied to clipboard

TextInput clears text when secureTextEntry is true

Open AlgoRoots opened this issue 2 years ago • 6 comments

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

2022-12-17 08 15 35

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.)

AlgoRoots avatar Dec 17 '22 03:12 AlgoRoots

Hey I have the same problem but I can't find the code inside node_modules/react-native to change it. Please help!!!

NarekAvagyan777 avatar Jun 01 '23 11:06 NarekAvagyan777

@NarekAvagyan777 Sorry for late reply, you can change native code below path. node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m

AlgoRoots avatar Jul 28 '23 12:07 AlgoRoots

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.

github-actions[bot] avatar Jan 25 '24 05:01 github-actions[bot]

This issue still exists. Do you have any workarouns?

D4uS1 avatar Jan 31 '24 12:01 D4uS1

Issue is still happening on IOS.

saqlaan avatar Mar 02 '24 00:03 saqlaan

how to get rid of that yellow background for inputs when u choose to "use a strong password"?

musiinator avatar Mar 03 '24 00:03 musiinator

@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;
}
```

adnan-khan1122 avatar Aug 08 '24 21:08 adnan-khan1122

@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!

angvp avatar Aug 08 '24 21:08 angvp

https://github.com/facebook/react-native/issues/46154

shubhamguptadream11 avatar Aug 28 '24 10:08 shubhamguptadream11

I believe @adnan-khan1122 is waiting for feedback on #45964 that PR should close this and #46154

angvp avatar Aug 29 '24 01:08 angvp

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 avatar Sep 20 '24 11:09 alimurad-1

@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.

adnan-khan1122 avatar Sep 20 '24 15:09 adnan-khan1122

@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.

reinstalling the app resolved the issue...thank you

alimurad-1 avatar Sep 23 '24 10:09 alimurad-1