Home > other >  Is there a way I can have my HookWidget rebuild when the text of the TextEditingController changes?
Is there a way I can have my HookWidget rebuild when the text of the TextEditingController changes?

Time:03-07

I have a test edit field. When there is no text, I want a button disabled. When there is text in the TextField, I want the button enabled.

I am using flutter_hooks to reduce boiler plate code for controllers.

In the following example, when I enter test into the text field, the button never enables, because build is not triggered? How can I trigger a build when using a text editing controller with flutter hooks?

class MyHomePage extends HookWidget {
  const MyHomePage({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    var ctrl = useTextEditingController();
    VoidCallback? onPressed;
    if (ctrl.text.isNotEmpty) {
      onPressed = () => print("Pressed!");
    }
    return Scaffold(
      body: Column(
        children: [
          TextField(
            controller: ctrl,
          ),
          ElevatedButton(onPressed: onPressed, child: Text("Button")),
        ],
      )
    );
  }
}

CodePudding user response:

To rebuild you widget use a useEffect Hook. The Hook takes a function callback as a parameter and runs side effects in a widget.

useEffect is called synchronously on every build, unless keys is specified. In which case useEffect is called again only if any value inside keys as changed.

Change your code like below

class MyHomePage extends HookWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final ctrl = useTextEditingController(text: '');
    VoidCallback? onPressed;
    final fieldsIsEmpty =
        useState<bool>(true);

    bool fieldsEmpty() {
      return ctrl.text.toString().isEmpty
    }

    useEffect(() {
      ctrl.addListener(() {
        fieldsIsEmpty.value = fieldsEmpty();
      });
    }, [
      ctrl
    ]);
    
    return Column(
      children: [
        TextField(
          controller: ctrl,
        ),
        fieldsIsEmpty.value ? const ElevatedButton(
                child: Text('Disabled'),
                onPressed: null,
              ): ElevatedButton(
                child: const Text('Enabled'),
                onPressed: onPressed,
              )
      ],
    );
  }
}

CodePudding user response:

enter image description here

You can Achieve this using useState and useTextEditingController

var istextchanged = useState<bool>(false);
ctrl.addListener(() {
  if (ctrl.text.isEmpty) {
    istextchanged.value = false;
  } else {
    istextchanged.value = true;
  }
});

Yourwidget

class MyHomePages2 extends HookWidget {
  const MyHomePages2({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    var ctrl = useTextEditingController();
    var istextchanged = useState<bool>(false);
    ctrl.addListener(() {
      if (ctrl.text.isEmpty) {
        istextchanged.value = false;
      } else {
        istextchanged.value = true;
      }
    });

    VoidCallback? onPressed = () {
      print("change");
    };
    if (ctrl.text.isNotEmpty) {
      onPressed = () => print("Pressed!");
    }
    return Scaffold(
        body: Column(
      children: [
        TextField(
          controller: ctrl,
          onChanged: (v) {},
        ),
        ElevatedButton(
            onPressed: istextchanged.value ? onPressed : null,
            child: Text("Button"))
      ],
    ));
  }
}

Package used flutter_hooks: ^0.18.2 1 pub.dev/flutter_hooks

SampleCode

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

int myvalue = 0;

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  @override
  void initState() {
    // functions().then((int value) {
    //   setState(() {
    //     myvalue = value;
    //   });
    // future is completed you can perform your task
    // });
  }

  Future<int> functions() async {
    // do something here
    return Future.value();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: MyHomePages2(),
    );
  }
}

class MyHomePages2 extends HookWidget {
  const MyHomePages2({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    var ctrl = useTextEditingController();
    var istextchanged = useState<bool>(false);
    ctrl.addListener(() {
      if (ctrl.text.isEmpty) {
        istextchanged.value = false;
      } else {
        istextchanged.value = true;
      }
    });

    VoidCallback? onPressed = () {
      print("change");
    };
    if (ctrl.text.isNotEmpty) {
      onPressed = () => print("Pressed!");
    }
    return Scaffold(
        body: Column(
      children: [
        TextField(
          controller: ctrl,
          onChanged: (v) {},
        ),
        ElevatedButton(
            onPressed: istextchanged.value ? onPressed : null,
            child: Text("Button"))
      ],
    ));
  }
}
  • Related