Home > front end >  Flutter 'setState' of other Widget
Flutter 'setState' of other Widget

Time:01-31

i want to code a POS for german 'Fischbrötchen'. My problem is that the "View" of the Ordertabel dosn't update. I tried man things but nothing worked... can someone help me to point out my Problem ? So when i click a button a Order should add to the Orders List and then update the View to display the order.

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      home: MyHomePage(),
      debugShowCheckedModeBanner: false,
      theme: CupertinoThemeData(
          brightness: Brightness.light, primaryColor: Colors.black54),
    );
  }
}

ValueNotifier<int> KundenId = ValueNotifier<int>(0);
List<Map<String, dynamic>> orders = [];

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

final List Getraenke = ["Fritz", "Wasser", "Bier"];

List<Map<String, dynamic>> items = [
  {'name': 'Möltenorter', 'price': '4 Euro'},
  {'name': 'Matjes', 'price': '4 Euro'},
  {'name': 'Bismarkt', 'price': '4 Euro'},
  {'name': 'Krabben', 'price': '5,50 Euro'},
  {'name': 'Lachs', 'price': '5.50 Euro'},
  {'name': 'Lachs Kalt', 'price': '5.50 Euro'},
];

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      child: RightSideContainer(),
    );
  }
}

class RightSideContainer extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => RightSideContainerState();
}

class RightSideContainerState extends State<RightSideContainer> {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        //left side, eingabe
        Column(
          children: [
            Text("Kasse"),
            Container(
                height: 600,
                width: MediaQuery.of(context).size.width / 2,
                child: Padding(
                    padding: EdgeInsets.all(5.0),
                    child: Container(
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(10),
                        color: Colors.black54,
                      ),
                      alignment: AlignmentDirectional.topStart,
                      child: OrderTable(),
                    ))),
          ],
        ),

        //right side, Ausgabe
        Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(0),
              color: Colors.black.withOpacity(0.5),
            ),
            width: MediaQuery.of(context).size.width / 2,
            alignment: Alignment.centerRight,
            child: Column(
              children: [
                Container(
                  height: 500,
                  color: Colors.red,
                  child: GridView.builder(
                      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                          crossAxisCount: 4),
                      itemCount: items.length,
                      itemBuilder: (BuildContext context, int index) {
                        return ButtonPrefab(items_: items[index]);
                      }),
                ),
              ],
            ))
      ],
    );
  }
}

class ButtonPrefab extends StatelessWidget {
  final Map<String, dynamic> items_;

  const ButtonPrefab({required this.items_});

  void addOrder(name, price) {
    orders.add({
      'kundenId': 0,
      'bestellung': name,
      'price': price,
    });
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: CupertinoButton(
        child: Text(items_['name']),
        color: Colors.black54,
        padding: EdgeInsets.all(3),
        onPressed: () {
          print(orders);
          addOrder("name", 2.4);
          KundenId.value  ;
          print(KundenId.value);
        },
      ),
    );
  }
}

class OrderTable extends StatefulWidget {
  @override
  State<OrderTable> createState() => _OrderTableState();
}

class _OrderTableState extends State<OrderTable> {
  @override
  void initState() {
    super.initState();
    setState(() {});
  }

  void update() {
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: [
          StatefulBuilder(
              builder: (BuildContext context, StateSetter setState) {
            return DataTable(
              columnSpacing: 20,
              columns: [
                DataColumn(
                  label: Text(
                    'Kunden ID',
                    style: TextStyle(
                      fontWeight: FontWeight.bold,
                      fontSize: 16,
                    ),
                  ),
                ),
                DataColumn(
                  label: Text(
                    'Bestellung',
                    style: TextStyle(
                      fontWeight: FontWeight.bold,
                      fontSize: 16,
                    ),
                  ),
                ),
                DataColumn(
                  label: Text(
                    'Preis',
                    style: TextStyle(
                      fontWeight: FontWeight.bold,
                      fontSize: 16,
                    ),
                  ),
                ),
              ],
              rows: orders
                  .map(
                    (order) => DataRow(
                      cells: [
                        DataCell(
                          Text(
                            order['kundenId'].toString(),
                            style: TextStyle(fontSize: 16),
                          ),
                        ),
                        DataCell(
                          Text(
                            order['bestellung'],
                            style: TextStyle(fontSize: 16),
                          ),
                        ),
                        DataCell(
                          Text(
                            order['price'].toString(),
                            style: TextStyle(fontSize: 16),
                          ),
                        ),
                      ],
                    ),
                  )
                  .toList(),
            );
          })
        ],
      ),
    );
  }
}

I tried to use 'set State' in my Statefull Widget but is dosn't change anything..

CodePudding user response:

Deleted my previous answer and tested your code... and got it working now.

I see you have a Function named update() and you're even using it there, but should use it somewhere else as a callback Function. A callback Function helps you to edit values in your "previous" Widget that called this Widget. Read more here: How to pass callback in Flutter

Also you have setState() in initState. Don't see the reason to have this there either. You should use setState in initState only for some kind of asyncronus reason, as explained here: Importance of Calling SetState inside initState

Call setState in "previous" Widget on button press after adding your item by using a callback Function (for short keeping, here is only the modified code):

class RightSideContainerState extends State<RightSideContainer> {
  void update() { //this is a new Function
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        //left side, eingabe
        Column(
          children: [
            Text("Kasse"),
            Container(
                height: 600,
                width: MediaQuery.of(context).size.width / 2,
                child: Padding(
                    padding: EdgeInsets.all(5.0),
                    child: Container(
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(10),
                        color: Colors.black54,
                      ),
                      alignment: AlignmentDirectional.topStart,
                      child: OrderTable(),
                    ))),
          ],
        ),

        //right side, Ausgabe
        Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(0),
              color: Colors.black.withOpacity(0.5),
            ),
            width: MediaQuery.of(context).size.width / 2,
            alignment: Alignment.centerRight,
            child: Column(
              children: [
                Container(
                  height: 500,
                  color: Colors.red,
                  child: GridView.builder(
                      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                          crossAxisCount: 4),
                      itemCount: items.length,
                      itemBuilder: (BuildContext context, int index) {
                        return ButtonPrefab(items_: items[index], callbackFunction: update); //give the "update (setState)" Function to the "next" Widget for calling it later
                      }),
                ),
              ],
            ))
      ],
    );
  }
}

class ButtonPrefab extends StatelessWidget {
  final Map<String, dynamic> items_;
  final Function callbackFunction; //get the callback Function of the calling Widget

  const ButtonPrefab({required this.items_, required this.callbackFunction}); //get the callback Function of the calling Widget

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: CupertinoButton(
        child: Text(items_['name']),
        color: Colors.black54,
        padding: EdgeInsets.all(3),
        onPressed: () {
          print(orders);
          // addOrder("name", 2.4); // you are always giving "name" and 2.4, but probably need to give the item that's being pushed
          addOrder(items_['name'], items_['price']); //like this
          KundenId.value  ;
          print(KundenId.value);
          callbackFunction(); //this is the "update" Function I created in the calling Widget, but in this Widget it has a name "callbackFunction"
        },
      ),
    );
  }
}

class _OrderTableState extends State<OrderTable> {
  @override
  void initState() {
    super.initState();
    // setState(() {}); // not necessary
  }

  // void update() { // not necessary
  //   setState(() {});
  // }

}

CodePudding user response:

There is so many problems here, that I cannot list them one by one.

The basic underlying problem here is that you think having a global variable is a good method to keep your state. It is not. Never has been. In no programming language in the last quarter of a century.

To hold your state (in your case I guess it's orders) use one of the state management patterns.

I suggest taking a look at Provider first. Not because it's the best, but because it is the easiest and explains your problem clearly:

Simple app state management

Once your applications get larger, my personal preference is BLoC, but that is a little to complex for this problem.

  • Related