How to conditionally add widgets to a list?
Asked Answered
E

4

52

In flutter, widgets such as Row/ListView/Stack don't handle null children. So if we want to conditionally add widgets as children I usually do the following:

Row(
  children: <Widget>[
    foo == 42 ? Text("foo") : Container(),
  ],
);

But this feels weird to add an empty container.

Another solution is a where filter :

Row(
  children: <Widget>[
    foo == 42 ? Text("foo") : null,
  ].where((t) => t != null).toList(),
);

This solves the empty container problem but we still have an ugly ternary and it is tiresome to write.

Is there any better solution?

Enrika answered 28/8, 2018 at 14:56 Comment(0)
E
93

EDIT:

Since Dart 2.2, new syntaxes supports this natively:

Column(
  children: [
    if (foo != null) Text(foo),
    Bar(),
  ],
);

This problem is currently debated on github here.

But for now, you can use dart sync* functions:

Row(
  children: toList(() sync* {
    if (foo == 42) {
      yield Text("foo");
    }
  }),
);

where toList is:

typedef Iterable<T> IterableCallback<T>();

List<T> toList<T>(IterableCallback<T> cb) {
  return List.unmodifiable(cb());
}

Not only it solves the conditional addition problem; it also allows for a "spread operator" thanks to yield*. Example:

List<Widget> foo;

Row(
  children: toList(() sync* {
    yield Text("Hello World");
    yield* foo;
  }),
);
Enrika answered 28/8, 2018 at 14:56 Comment(3)
Brilliant! How about List.of(_buildChildren()), where _buildChildren is a sync* method?Posy
Works too. But it's a bit more boring to use when you want to pass arguments. The closure make it easierSharpshooter
Can I use Dart 2.2 syntax to add several items at once with the same condition?Motherwort
P
7

The new Dart syntax allows 'if' in lists, which leads to this simple solution:

Row(
  children: <Widget>[
    if (foo == 42) Text("foo"),
  ],
);
Palaeobotany answered 28/6, 2019 at 19:49 Comment(0)
E
7

Row(
    children: [
        if (_id == 0) ...[
          Container()
        ] else if(_id == 1)...[
          Text("Hello")
        ] else ...[
          SizedBox(width: 20)
        ],
    ],
 ),
Edwinaedwine answered 19/1, 2022 at 6:5 Comment(0)
B
4

Here's a simpler version I use:

Row(
  children: [
    Text("always included"),
    skipNulls([
      icon,
      label,
    ]),
  ],
);

skipNulls<T>(List<T> items) {
  return items..removeWhere((item) => item == null);
}
Bugaboo answered 7/3, 2019 at 11:37 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.