injectTextEditing method Null safety

InjectedTextEditing injectTextEditing(
  1. {String text = '',
  2. TextSelection selection = const TextSelection.collapsed(offset: -1),
  3. TextRange composing = TextRange.empty,
  4. List<String? Function(String? text)>? validators,
  5. bool? validateOnTyping,
  6. bool? validateOnLoseFocus,
  7. void onTextEditing(
    1. InjectedTextEditing textEditing
    )?,
  8. bool isReadOnly = false,
  9. bool isEnabled = true,
  10. bool autoDispose = true,
  11. @Deprecated('Use validators instead') String? validator(
    1. String? text
    )?}
)

Inject a TextEditingController

This injected state abstracts the best practices to come out with a simple, clean, and testable approach deal with TextField and form validation.

The approach consists of the following steps:

     final email =  RM.injectTextEditing():
  • Instantiate an InjectedTextEditing object using RM.injectTextEditing
  • Link the injected state to a TextField (No need to TextFormField even inside a OnFormBuilder).
       TextField(
          controller: email.controller,
          focusNode: email.focusNode, //It is auto disposed of.
          decoration:  InputDecoration(
              errorText: email.error, //To display the error message.
          ),
          onSubmitted: (_) {
              //Focus on the password TextField after submission
              password.focusNode.requestFocus();
          },
      ),
    

See also :

Parameters:

text: Optional String. Defaults to empty string.

The initial text the linked TextField displays.

selection: Optional TextSelection. Defaults to empty TextSelection.collapsed(offset: -1).

The initial text selection the linked TextField starts with.

composing: Optional TextRange. Defaults to empty TextRange.empty

The initial range of text the linked TextField starts with.

validators: Optional List of callbacks.

Set of validation rules the field should pass.

Validators expose the text that the user entered.

If any of the validation callbacks return a non-empty string, the filed is considered non valid. For the field to be valid all validators must return null.

example:

     final _email = RM.injectTextEditing(
      validators: [
        (value) {
           //Frontend validation
           if (!Validators.isValidEmail(value)) {
             return 'Enter a valid email';
           }
         },
      ]
    );

The validations performed here are frontend validation. To do backend validation you must use InjectedForm.

validateOnTyping: Optional bool.

Whether to validate the input while the user is typing.

The default value depends on whether the linked TextField is inside or outside OnFormBuilder:

If validateOnTyping is set to false, the text is not validate on typing. The text can be validate manually by invoking InjectedTextEditing.validate.

validateOnLoseFocus: Optional bool.

Whether to validate the input just after the user finishes typing and the field loses focus.

It defaults to true if the linked TextField is inside OnFormBuilder and defaults to false if it is outside.

Once the TextField loses focus and if it fails to validate, the field will auto-validate on typing the next time the user starts typing.

For validateOnLoseFocus to work you have to set the TextField's FocusNode to use InjectedTextEditing.focusNode

Example:

    final email =  RM.injectTextEditing():

    // In the widget tree
   TextField(
      controller: email.controller,
      focusNode: email.focusNode, //It is auto disposed of.
    ),

isReadOnly: Optional bool. Defaults to false.

If true the TextField is clickable and selectable but not editable. Later on, you can set it using InjectedTextEditing.isReadOnly

All input fields are set to be read-only if they are inside a OnFormBuilder and the form is waiting for submission to resolve.

isEnabled: Optional bool. Defaults to true.

If false the TextField is disabled. Later on, you can set it using InjectedTextEditing.isEnable.

You can enable or disable all input fields inside OnFormBuilder using InjectedForm.isEnabled setter.

For isEnabled to work you have to set the TextField's enable property to use InjectedTextEditing.isEnabled

Example:

    final email =  RM.injectTextEditing():

    // In the widget tree
   TextField(
      controller: email.controller,
      enabled: email.isEnabled,
    ),

onTextEditing: Optional callback.

Callback for side effects. It is fired whenever the input text or selection changes

isReadOnly: Optional bool. Defaults to false.

If true the input is clickable and selectable but not editable. Later on, you can set it using InjectedTextEditing.isReadOnly.

See OnFormBuilder.isReadOnlyRM to set a group of input fields to read only.

isEnabled: Optional bool. Defaults to true.

If false the OnFormFieldBuilder is disabled. Later on, you can set it using InjectedTextEditing.isEnabled.

See OnFormBuilder.isReadOnlyRM to disable a group of input fields.

autoDisposeWhenNotUsed: Optional bool (Default true)

Whether to auto dispose the injected model when no longer used (listened to).

It is important to note that:

  • A state never listened to for rebuild, never auto dispose even after it is mutated.
  • By default, all states consumed in the widget tree will auto dispose.
  • It is recommended to manually dispose state that are not auto disposed using InjectedBaseState.dispose. You can dispose all states of the app using RM.disposeAll.
  • A state will auto dispose if all states it depends on are disposed of.
  • Non disposed state may lead to unexpected behavior.
  • To debug when state is initialized and disposed of use debugPrintWhenNotifiedPreMessage parameter (See below)

Implementation

static InjectedTextEditing injectTextEditing({
  String text = '',
  TextSelection selection = const TextSelection.collapsed(offset: -1),
  TextRange composing = TextRange.empty,
  List<String? Function(String? text)>? validators,
  bool? validateOnTyping,
  bool? validateOnLoseFocus,
  void Function(InjectedTextEditing textEditing)? onTextEditing,
  bool isReadOnly = false,
  bool isEnabled = true,
  bool autoDispose = true,
  //
  @Deprecated('Use validators instead')
      String? Function(String? text)? validator,
}) {
  return InjectedTextEditingImp(
    text: text,
    selection: selection,
    composing: composing,
    validator: validators ?? (validator != null ? [validator] : null),
    validateOnTyping: validateOnTyping,
    validateOnLoseFocus: validateOnLoseFocus,
    autoDispose: autoDispose,
    onTextEditing: onTextEditing,
    isReadOnly: isReadOnly,
    isEnabled: isEnabled,
  );
}