How to delete and add widget to dynamic list of Widgets

Question

Asked by Jan D on November 03, 2021 (source).

I want to create dynamic form, where user will be able to delete row or add it. I created it before in a static version where I know how many rows will be at start. I'm creating a list of Rows from tags in Widget build method. Each row is combined from Label(with key), TextField (with value) and Delete button. On delete button click i want to delete specific Row. What is a best approach to do it? Later I want to add also one 'Add' button to add new Row.

import 'package:flutter/material.dart';

class EditJdataForm2 extends StatefulWidget {
  var tags = <MapEntry>{
    new MapEntry('city', 'Chicago'),
    new MapEntry('name', 'John'),
    new MapEntry('fullname', 'Doe'),
    new MapEntry('age', '30')
  };

  @override
  _EditJdataForm2State createState() => _EditJdataForm2State();
}

class _EditJdataForm2State extends State<EditJdataForm2> {
  var _rows = <Row>[];

  @override
  Widget build(BuildContext context) {
    widget.tags.forEach((element) {
      _rows.add(new Row(children: [
        Expanded(
          flex: 3,
          child: Container(
            margin: const EdgeInsets.only(left: 30.0, right: 30.0),
            child: Text(element.key,
                style: TextStyle(
                  color: Colors.black54,
                  fontSize: 20.0,
                  letterSpacing: 0,
                  fontWeight: FontWeight.normal,
                )),
          ),
        ),
        Expanded(
            flex: 6,
            child: Container(
                margin: const EdgeInsets.only(right: 30.0),
                child: TextFormField(initialValue: element.value.toString()))),
        Container(
          margin: const EdgeInsets.only(right: 30.0),
          child: Ink(
            decoration: ShapeDecoration(
              color: Colors.red,
              shape: CircleBorder(),
            ),
            child: IconButton(
              icon: Icon(
                Icons.remove,
                color: Colors.white,
              ),
              onPressed: () {
                print(element.value.toString());
              },
            ),
          ),
        ),
      ]));
    });

    return Column(children: this._rows);
  }
}

Answer

Question answered by Jim C (source).

simplest way is:

      List<MapEntry> _items = [
        MapEntry('city', 'Chicago'),
        MapEntry('name', 'John'),
        MapEntry('fullname', 'Doe'),
        MapEntry('age', '30')
      ];
    
      @override
      Widget build(BuildContext context) {
          return Column(
            children: _rowItems(),
          );
      }
    
      List<Row> _rowItems(){
        return _items.map((element) {
          return Row(children: [
            Expanded(
              flex: 3,
              child: Container(
                margin: const EdgeInsets.only(left: 30.0, right: 30.0),
                child: Text(element.key,
                    style: TextStyle(
                      color: Colors.black54,
                      fontSize: 20.0,
                      letterSpacing: 0,
                      fontWeight: FontWeight.normal,
                    )),
              ),
            ),
            Expanded(
                flex: 6,
                child: Container(
                    margin: const EdgeInsets.only(right: 30.0),
                    child: TextFormField(key: UniqueKey(), 
 initialValue: element.value.toString()))),
            Container(
              margin: const EdgeInsets.only(right: 30.0),
              child: Ink(
                decoration: ShapeDecoration(
                  color: Colors.red,
                  shape: CircleBorder(),
                ),
                child: IconButton(
                  icon: Icon(
                    Icons.remove,
                    color: Colors.white,
                  ),
                  onPressed: () {
                    _items.remove(element);
                    setState((){});
                  },
                ),
              ),
            ),
          ]);
        }).toList();
      }

      void _addItems(){
        _items.add(MapEntry('sex', 'Male'));
        setState((){});
      }
DART FLUTTER
SHARE: