How to pass a notifyListeners method to an onPressed button function?

1.2k Views Asked by At

I have a LoginButtonProvider class and that class has two purposes.

First: it should provide an onPressed method to my LoginButton widget once the user has typed in both text form fields. The class calls notifyListeners() method once it assigns a onPressed function to the button.

Second: it should create a spinning circle inside that button once the user has pressed that button and called the onPressed method. It should also call notifyListeners() once the user has pressed the button in order for boolean flag _isLoading to be set to true.

The problem is that I don't know how to implement the onPressed method in order for the Consumer widget to rebuild itself once the onPressed method is triggered by the user. I think that the notifyListeners is never called once the user presses the button and therefore the spinning circle never appears on the button, but it should! I have also tried sending the reference to the notifyListeners method. The widget doesn't rebuild itself when the notifyListeners() is called inside the onPressed function. Why is that? Thank you very much for your help!

Here is the LoginButtonProvider class.

class LoginButtonProvider with ChangeNotifier {

  TokenViewModel _tokenViewModel = new TokenViewModel();
  Function _onPressed;
  bool _isLoading = false;

  get onPressed => _onPressed;
  get isLoading => _isLoading;

  void updateButton(BuildContext context, FocusNode focusNode, Validator validator) {
    if (!validator.areFieldsEmpty()) {
      _onPressed = () {
        if (validator.validateFields()) {
          _isLoading = true;
          notifyListeners();
          _tokenViewModel.getToken(validator.email, validator.password, context, focusNode);
          _isLoading = false;
          notifyListeners();
        } else {
          SimpleShowDialog.createSimpleShowDialog(
            title: "Invalid Input",
            buttonText: "OK",
            context: context,
            message: validator.errorMessage,
            focusNode: focusNode,
          );
          validator.reset();
        }
      };
      notifyListeners();
    } else {
      _onPressed = null;
      notifyListeners();
    }
  }
}
1

There are 1 best solutions below

5
On BEST ANSWER

I believe the problem is that this method is never called because the onPressed handler is inside the ChangeNotifier. And this is all the wrong way to do it. do not pass the instance of Widget logic like FocusNode, context, validator inside your ChangeNotifier instead do all of the validation in the onPressed handler of the button and then call the method in Notifier using Provider.

...
  Widget build(BuildContext context){
   final login = Provider.of<LoginButtonProvider>(context);
   
    return login.isLoading? 
    Center(child: CircularProgressIndicator()):
    Flatbutton(
    child: Text('Login')
    onPressed : 
         validator.areFieldsEmpty()) ?  /// Now the button should not be clickbale, till the field is filled.
         null:
         () {
      // do all your validation here
        if (!validator.areFieldsEmpty()) {

          login.updateButton(validator.email, validator.password);      

          } else {

          SimpleShowDialog.createSimpleShowDialog(
            title: "Invalid Input",
            buttonText: "OK",
            context: context,
            message: validator.errorMessage,
            focusNode: focusNode,
          );
          validator.reset();
        }
    );

  } 




and the LoginButtonProvider,

class LoginButtonProvider with ChangeNotifier {

  TokenViewModel _tokenViewModel = new TokenViewModel();

  bool _isLoading = false;


  get isLoading => _isLoading;

  void updateButton(String email, String password)async {
          _isLoading = true; 
           notifyListeners();

           await _tokenViewModel.getToken(email ,password); /// not sure what this is, but if its an API call would not recommend passing in context and node again,

          _isLoading = false;
          notifyListeners();
    }

Make sure you have the ChangeNotifierProvider<LoginButtonProvider> above your MaterialApp to access through Provider.