Flutter Provider: How do I listen to a change of a class field inside a class field?

9,224

Here's an example on how you could use callback functions. Without the callback, A won't call notifyListeners and your Home widget doesnt get rebuild. Here's a short video on what a VoidCallback is: https://www.youtube.com/watch?v=fWlPwj1Pp7U

Main function and a simple Home view:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'a.dart';

void main() {
  runApp(
    ChangeNotifierProvider<A>(
      create: (context) => A(),
      child: MaterialApp(
        home: Home(),
      ),
    )
  );
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<A>(
      builder: (context, model, child) {
        return Scaffold(
          body: Container(
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text('${model.element1.x}'),
                  RaisedButton(
                    child: Text("Set x of element1."),
                    onPressed: () {
                      Provider.of<A>(context, listen: false).element1.setX = 'Set to new value';
                    },
                  ),
                ],
              ),
            ),
          )
        );
      },
    );
  }
}

And then Class A:

import 'package:flutter/material.dart';
import 'package:tryout/b.dart';

class A extends ChangeNotifier {
  B _element1 = B();
  B _element2 = B();
  
  B get element1 => _element1;
  B get element2 => _element2;

  A() {
    _element1.callback = () => notifyListeners();
    _element2.callback = () => notifyListeners();
  }

  set element1(B value) {
    _element1 = value;
    _element1.callback = () => notifyListeners();
    notifyListeners();
  }

  set element2(B value) {
    _element2 = value;
    _element2.callback = () => notifyListeners();
    notifyListeners();
  }
}

And class B:

import 'package:flutter/cupertino.dart';

class B {
  String x = "";
  String y = "";
  VoidCallback? callback;

  B({
    this.callback
  });

  set setX(String newValueX) {
    x = newValueX;
    if(callback != null) callback!();
  }

  void setY(String newValueY) {
    y = newValueY;
    if(callback != null) callback!();
  }
}
Share:
9,224
THE-E
Author by

THE-E

Updated on December 20, 2022

Comments

  • THE-E
    THE-E over 1 year

    Given the following Dart/Flutter class structure:

    import 'package:flutter/material.dart';
    
    class A with ChangeNotifier {
      B _element1;
      B _element2;
    
      B get element1 => _element1;
      B get element2 => _element2;
    
      set element1(B value) {
        _element1 = value;
        notifyListeners();
      }
    
      set element2(B value) {
        _element2 = value;
        notifyListeners();
      }
    }
    
    class B {
      String x;
      String y;
    }
    

    I am trying to listen to a change of A.element1.x but the problem is, the setter of class B can't call the notifyListeners() of the class A, so either I am Listening to A and won't notice a change or I am listening to B and I am losing the context to A.

    I am using the Provider package in my Flutter project. But I am not sure, if I am misunderstanding the concept of Provider package or ChangeListeners. Either way I am not able to find a elegant solution.

    Is there a possibility to overwrite the setter of class B from class A? I could obviously implement a function for each element1 and element2 fields(x,y). But this is not good code style I guess.

    • JJuice
      JJuice about 4 years
      There’s multiple (as always;)) ways in which you could solve this: you could register a callback inside class B which then calls a function of class A, so that class A knows when to notify listeners because of changes in B. Or use a Stream, exposed by B and listened to by A. But maybe best is to look to ProxyProvider package. I don’t have experience with it but I think it could suit your use case. Here’s an article on it.
    • THE-E
      THE-E about 4 years
      Could you help me out with the callback function? I am not to familiar with callback functions. I looked into the article but could not see a solution for my particular problem. I also looked into the documentation, but couldn't figure out how to use ProxyProvider, to solve my problem as well.
    • JJuice
      JJuice about 4 years
      Posted an example below. This is how the callback calls the notifyListeners inside A. I am not sure if this is better than the alternative of just calling a method on A, which then sets the property on B and calls notifyListeners directly.