Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What is the best way to optionally include a widget in a list of children #3783

Closed
drewwarren opened this issue May 6, 2016 · 13 comments

Comments

Projects
None yet
9 participants
@drewwarren
Copy link

commented May 6, 2016

I often find myself optionally wanting a child in a column component. For example let's say I have a Column with a title, body, and optional footer. What is the best way to achieve this?

Option 1: explicitly build the children, omitting the optional child

List<Widget> buildChildren() {
  var builder = [
    new Title(),
    new Body()
  ];
  if (shouldShowFooter) {
    builder.add(new Footer());
  }
  return builder;
}

Widget build() {
  return new Column(children: buildChildren());
}

Option 2: ternary operator using an empty widget when the optional child should not be shown

Widget build() {
  return new Column(
    children: [
      new Title(),
      new Body(),
      shouldShowFooter ? new Footer() : new Container(width: 0, height: 0)
    ]
  );
}

Option 3...: You show me!

I have been using option 2 but referencing a final Widget emptyWidget = new Container(width: 0, height: 0) to make it more readable.

What approach would you suggest?

@drewwarren

This comment has been minimized.

Copy link
Author

commented May 6, 2016

This is a re-post from flutter-users. One suggestion there was to allow null in child lists to represent this case.

@Hixie

This comment has been minimized.

Copy link
Contributor

commented May 6, 2016

Option 1 is the currently optimal path.

Supporting nulls in child lists seems reasonable. It actually might work already, since we use nulls internally to represent children that have been removed by GlobalKey regrafting.

@drewwarren

This comment has been minimized.

Copy link
Author

commented May 6, 2016

assert(!children.any((Widget child) => child == null));
prevents null in slow mode.

The following exception is thrown with --no-checked

I/flutter : ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter : The following NoSuchMethodError was thrown building DefaultTextStyle(inherit: false; color:
I/flutter : Color(0xdd000000); size: 14.0; weight: 400; baseline: alphabetic):
I/flutter : The null object does not have a getter 'key'.
I/flutter : NoSuchMethodError: method not found: 'key'
I/flutter : Receiver: null
I/flutter : Arguments: []
I/flutter : When the exception was thrown, this was the stack:
I/flutter : #0      Object._noSuchMethod (dart:core-patch/object_patch.dart:42)
I/flutter : #1      Object.noSuchMethod (dart:core-patch/object_patch.dart:45)
I/flutter : #2      Element.inflateWidget (package:flutter/src/widgets/framework.dart:1069)
I/flutter : #3      MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:2233)
I/flutter : #4      Element.inflateWidget (package:flutter/src/widgets/framework.dart:1083)
I/flutter : #5      Element.updateChild (package:flutter/src/widgets/framework.dart:964)
I/flutter : #6      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:1506)
I/flutter : #7      BuildableElement.rebuild (package:flutter/src/widgets/framework.dart:1405)
I/flutter : #8      ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:1469)
I/flutter : #9      ComponentElement.mount (package:flutter/src/widgets/framework.dart:1464)
I/flutter : #10     Element.inflateWidget (package:flutter/src/widgets/framework.dart:1083)
...
@drewwarren

This comment has been minimized.

Copy link
Author

commented May 6, 2016

With this question I'm less concerned about efficiency and more concerned with readability.

@Hixie

This comment has been minimized.

Copy link
Contributor

commented May 6, 2016

Ok, looks like we have to add null checks in more places then.

@abarth

This comment has been minimized.

Copy link
Contributor

commented May 7, 2016

@yjbanov has a proposal that would make the moral equivalent of this code work:

Widget build() {
  return new Column(
    children: [
      new Title(),
      new Body(),
      if (shouldShowFooter) { new Footer() }
    ]
  );
}

However, that would require changes to the language, which means it's a bit further out than allowing nulls.

@Hixie Hixie modified the milestone: Flutter 1.0 May 20, 2016

@Hixie

This comment has been minimized.

Copy link
Contributor

commented Jan 29, 2017

I think we should just go with option 1 for now. You can use where to allow nulls if you want:

bool notNull(Object o) => o != null;
Widget build() {
  return new Column(
    children: <Widget>[
      new Title(),
      new Body(),
      shouldShowFooter ? new Footer() : null
    ].where(notNull).toList(),
  );
}
@pavel-ismailov

This comment has been minimized.

Copy link

commented Jul 11, 2018

Issue is still here and I have to use method from my BaseState class

  @protected
  widgets(List<Widget> widgets) {
    return widgets..removeWhere((widget) => widget == null);
  }

and then in the code

    Column(
      children: widgets ([
        widget1,
        widget2,
        (a != null) ? Text(...) : null    
      ]),
    )

Do you have plans add support nulls in child lists?

@zoechi

This comment has been minimized.

Copy link
Contributor

commented Jul 11, 2018

@pavel-ismailov you might want to upvote #17862

@Zhuinden

This comment has been minimized.

Copy link

commented Jan 2, 2019

#3783 (comment) In Kotlin you'd just do something like

fun build(): Widget =
  Column(
    children: buildArray {
        add(Title())
        add(Body())
        if(shouldShowFooter) add(Footer())
    }
  )

where your buildArray is receiving a method like ArrayBuilder.() -> Unit which at the end returns the new array, or so.

And crazier DSLs overrode the unary plus to replace add(Title()) with +Title() but I personally think that is overkill.

@yjbanov

This comment has been minimized.

Copy link
Contributor

commented Jan 3, 2019

@juliusspencer

This comment has been minimized.

Copy link

commented Feb 19, 2019

Check out the Visibility widget. Just found it after reading all this. :)

@i-schuetz

This comment has been minimized.

Copy link
Contributor

commented Mar 2, 2019

Concerning null support (though this is a bit out of topic here as it's not about lists), it makes sense for example when using a FutureBuilder and wanting to return "nothing" when the state is none or waiting (if you expect the future to be almost immediate).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.