Home > Net >  How to pass TextEditingController to add into list
How to pass TextEditingController to add into list

Time:10-21

I'm learning flutter and have a floating action button which opens a bottom sheet with some field inputs and date input to create an expense item.

I want to add the inputs to a dummy list of expenses I've already hardcoded. I believe I do this with a function and call setState((){variable.add(argument);});

The thing I really struggle with in Flutter is passing data between widgets, using arguments and constructors etc. Sorry for the dump of code - unsure how to share.

enter image description here enter image description here

main.dart

import 'package:flutter/material.dart';

import 'screens/home.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.dark(),
      debugShowCheckedModeBanner: false,
      home: const HomePage(),
    );
  }
}

home.dart

import 'package:expenses_v2/widgets/expenses_summary.dart';
import 'package:flutter/material.dart';

import '../widgets/floating_action_button.dart';
import '../widgets/transactions_list.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color.fromARGB(255, 27, 27, 38),
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            children: const [
              ExpensesSummary(),
              SizedBox(
                height: 10,
              ),
              TransactionList(),
            ],
          ),
        ),
      ),
      floatingActionButton: const CustomFloatingActionButton(),
    );
  }
}

transactions_list.dart

import 'package:expenses_v2/k_constants.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

import '../models/transactions.dart';

final List<Transaction> transactions = [
  Transaction(
    id: '1',
    title: 'New shoes',
    amount: 69.99,
    date: DateTime.now(),
  ),
  Transaction(
    id: '2',
    title: 'Weekly groceries',
    amount: 42.99,
    date: DateTime.now(),
  ),
];

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

  void addTransaction(String item, double cost) {}

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: ListView.builder(
          itemCount: transactions.length,
          itemBuilder: (context, index) {
            return Column(
              children: [
                ListTile(
                  tileColor: kprimaryColour,
                  title: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Text(transactions[index].title),
                      Column(
                        children: [
                          Text('£${transactions[index].amount}'),
                          Text(
                            DateFormat('d-mm-yy')
                                .format(transactions[index].date),
                            style: TextStyle(
                              color: ksecondaryColour,
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
                const SizedBox(height: 2)
              ],
            );
          }),
    );
  }
}

floatingactionbutton.dart

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

import 'package:expenses_v2/k_constants.dart';

class CustomFloatingActionButton extends StatefulWidget {
  const CustomFloatingActionButton({
    Key? key,
  }) : super(key: key);

  @override
  State<CustomFloatingActionButton> createState() =>
      _CustomFloatingActionButtonState();
}

class _CustomFloatingActionButtonState
    extends State<CustomFloatingActionButton> {
  //
  final itemInput = TextEditingController();
  final costInput = TextEditingController();
  DateTime? dateInput;

  @override
  Widget build(BuildContext context) {
    return FloatingActionButton(
        backgroundColor: kaccentColour,
        child: const Icon(Icons.add),
        onPressed: () {
          showModalBottomSheet(
              constraints: const BoxConstraints(maxHeight: 600),
              isScrollControlled: true,
              backgroundColor: ksecondaryColour,
              context: context,
              builder: (context) {
                return SingleChildScrollView(
                  child: Padding(
                    padding: const EdgeInsets.all(20.0),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.end,
                      children: [
                        const Text('Add an expense item'),
                        const SizedBox(
                          height: 10,
                        ),
                        TextField(
                          controller: itemInput,
                          decoration: const InputDecoration(
                            border: OutlineInputBorder(),
                            hintText: 'Item',
                          ),
                        ),
                        const SizedBox(
                          height: 10,
                        ),
                        TextField(
                          controller: costInput,
                          keyboardType: TextInputType.number,
                          decoration: const InputDecoration(
                            border: OutlineInputBorder(),
                            hintText: 'Cost',
                          ),
                        ),
                        const SizedBox(
                          height: 10,
                        ),
                        // TextField(
                        //   onChanged: (value) => dateInput = value,
                        //   keyboardType: TextInputType.datetime,
                        //   decoration: const InputDecoration(
                        //     border: OutlineInputBorder(),
                        //     hintText: 'Date',
                        //   ),
                        // ),
                        const SizedBox(
                          height: 10,
                        ),
                        SizedBox(
                          height: 200,
                          // Quick means to get a date picker in
                          child: CupertinoDatePicker(
                              onDateTimeChanged: (newDate) =>
                                  dateInput = newDate),
                        ),
                        ElevatedButton(
                            onPressed: () {
                              Navigator.pop(context);
                              debugPrint(itemInput.text);
                              debugPrint(costInput.text);
                              debugPrint(dateInput.toString());
                              //TODO: Not sure if I need to clear the variables after submiting - unsure of best practice
                              // itemInput.text = '';
                              // costInput.text = '';
                              // dateInput = '';
                            },
                            child: const Text('Submit'))
                      ],
                    ),
                  ),
                );
              });
        });
  }
}

transactions.dart

class Transaction {
  Transaction({
    required this.id,
    required this.title,
    required this.amount,
    required this.date,
  });
  final String id;
  final String title;
  final double amount;
  final DateTime date;
}

k_constants.dart

import 'package:flutter/material.dart';

Color kprimaryColour = const Color.fromARGB(255, 23, 37, 54);
Color ksecondaryColour = const Color.fromARGB(255, 73, 99, 130);
Color kaccentColour = const Color.fromARGB(255, 29, 209, 209);

CodePudding user response:

Use a callback method to return data from CustomFloatingActionButton widget. and pass transactions to the TransactionList instead of creating global variable. Also the HomePage needed to be statefulWiget to update the UI.

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final List<Transaction> transactions = [
    Transaction(
      id: '1',
      title: 'New shoes',
      amount: 69.99,
      date: DateTime.now(),
    ),
    Transaction(
      id: '2',
      title: 'Weekly groceries',
      amount: 42.99,
      date: DateTime.now(),
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color.fromARGB(255, 27, 27, 38),
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            children: [
              // ExpensesSummary(),
              SizedBox(
                height: 10,
              ),
              TransactionList(transactions: transactions),
            ],
          ),
        ),
      ),
      floatingActionButton: CustomFloatingActionButton(
        callback: (transaction) {
          if (transaction != null) {
            transactions.add(transaction);

            print(transaction);
            setState(() {});
          }
        },
      ),
    );
  }
}

class TransactionList extends StatelessWidget {
  final transactions;
  const TransactionList({
    Key? key,
    required this.transactions,
  }) : super(key: key);

  void addTransaction(String item, double cost) {}

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: ListView.builder(
          itemCount: transactions.length,
          itemBuilder: (context, index) {
            return Column(
              children: [
                ListTile(
                  tileColor: kprimaryColour,
                  title: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Text(transactions[index].title),
                      Column(
                        children: [
                          Text('£${transactions[index].amount}'),
                          Text(
                            DateFormat('d-mm-yy')
                                .format(transactions[index].date),
                            style: TextStyle(
                              color: ksecondaryColour,
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
                const SizedBox(height: 2)
              ],
            );
          }),
    );
  }
}

class CustomFloatingActionButton extends StatefulWidget {
  final Function(Transaction? transaction) callback;

  const CustomFloatingActionButton({
    Key? key,
    required this.callback,
  }) : super(key: key);

  @override
  State<CustomFloatingActionButton> createState() =>
      _CustomFloatingActionButtonState();
}

class _CustomFloatingActionButtonState
    extends State<CustomFloatingActionButton> {
  //
  final itemInput = TextEditingController();
  final costInput = TextEditingController();
  DateTime? dateInput;

  @override
  Widget build(BuildContext context) {
    return FloatingActionButton(
        backgroundColor: kaccentColour,
        child: const Icon(Icons.add),
        onPressed: () async {
          showModalBottomSheet(
              constraints: const BoxConstraints(maxHeight: 600),
              isScrollControlled: true,
              backgroundColor: ksecondaryColour,
              context: context,
              builder: (context) {
                return SingleChildScrollView(
                  child: Padding(
                    padding: const EdgeInsets.all(20.0),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.end,
                      children: [
                        const Text('Add an expense item'),
                        const SizedBox(
                          height: 10,
                        ),
                        TextField(
                          controller: itemInput,
                          decoration: const InputDecoration(
                            border: OutlineInputBorder(),
                            hintText: 'Item',
                          ),
                        ),
                        const SizedBox(
                          height: 10,
                        ),
                        TextField(
                          controller: costInput,
                          keyboardType: TextInputType.number,
                          decoration: const InputDecoration(
                            border: OutlineInputBorder(),
                            hintText: 'Cost',
                          ),
                        ),
                        const SizedBox(
                          height: 10,
                        ),
                        // TextField(
                        //   onChanged: (value) => dateInput = value,
                        //   keyboardType: TextInputType.datetime,
                        //   decoration: const InputDecoration(
                        //     border: OutlineInputBorder(),
                        //     hintText: 'Date',
                        //   ),
                        // ),
                        const SizedBox(
                          height: 10,
                        ),
                        SizedBox(
                          height: 200,
                          // Quick means to get a date picker in
                          child: CupertinoDatePicker(
                              onDateTimeChanged: (newDate) =>
                                  dateInput = newDate),
                        ),
                        ElevatedButton(
                            onPressed: () {
                              Navigator.pop(context);
                              debugPrint(itemInput.text);
                              debugPrint(costInput.text);
                              debugPrint(dateInput.toString());

                              final result = Transaction(
                                  amount: double.tryParse(costInput.text) ?? 0,
                                  date: dateInput ?? DateTime.now(),
                                  id: "your Id",
                                  title: itemInput.text);

                              widget.callback(result);
                            },
                            child: const Text('Submit'))
                      ],
                    ),
                  ),
                );
              });
        });
  }
}
  • Related