Meaning of Triple Dots [...] in Flutter Syntax - flutter

Can someone please clarify what is the meaning and usage of "..." in Flutter?
I wanted to learn about "triple dots" used in Flutter syntax. After some reading I found out that the word I was looking for was "spreading".
Widget _build() {
List<Widget> children = [
Text("first child"),
Text("second child"),
Text("third child"),
];
return Column(
children: <Widget>[
...children,
Text("fourth child"),
],
);
}
If I didn't have the ... right before the children, it will give an error The element type 'List<Widget>' can't be assigned to the list type 'Widget'.
I just thought that someone should post a question about it. What is "..." in flutter syntax? What does it mean?

Dart 2.3 introduced the spread operator (...) and the null-aware spread operator (...?), which provide a concise way to insert multiple elements into a collection.
For example, you can use the spread operator (...) to insert all the elements of a list into another list:
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
If the expression to the right of the spread operator might be null, you can avoid exceptions by using a null-aware spread operator (...?):
var list;
var list2 = [0, ...?list];
assert(list2.length == 1);
For more details and examples of using the spread operator, see the spread operator proposal.

I used to have this problem. I solved this problem by adding .toList(); to the List Widget.
Widget _build() {
List<Widget> children = [
Text("first child"),
Text("second child"),
Text("third child"),
].toList();
return Column(
children: <Widget>[
...children,
Text("fourth child"),
],
);
}
Hope it helps

spread operator (...) is used to provide a way to assign values to Collections, more commonly it found inside the column to render its child.
List<String> values = ['one', 'two', 'three'];
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
...values.map((value) {
return Text(value);
}),
],
),
),
);
Output:

Related

The return type 'Set<Text>' isn't a 'Widget', as required by the closure's context

The inner map function is causing the error in the title and I don't know how I can fix this. I want to make a calculation in the inner map function before returning the Widget.
var rowOnee = Column(children: [
...stampRows.map((i) => Row(
children: [
...[0,1,2,3,4].map((i) => {
return Text("hi");
})
],
))
]);
This is not the correct way to write an anonymous function in dart:
(i) => {
return Text("hi");
}
You can either do:
(i) {
return Text("hi");
}
or
(i) => Text("hi"),
Note that the anonymous function has either => for single expression anonymous functions or {} for multiline anonymous functions, but not both.
When you have both, the {} is interpreted instead as a set literal.
That said, you really should use collection-for instead of combining ... and .map. I suggest rewriting your code as the following:
var rowOnee = Column(children: [
for (var i in stampRows)
Row(children: [
for (var i in [0, 1, 2, 3, 4]) Text("hi")
]),
]);
There are a few ways to fix it. One way is to remove the arrow:
var rowOnee = Column(children: [
...stampRows.map((i) => Row(
children: [
...[0,1,2,3,4].map((i) {
return Text("hi");
})
],
))
]);
Or you could remove the curly brackets and return statement:
var rowOnee = Column(children: [
...stampRows.map((i) => Row(
children: [
...[0,1,2,3,4].map((i) => Text("hi"))
],
))
]);

How do I map a list of potentially null widgets?

I'm new to Flutter and haven't found much success in my brief online search for an answer to this, which is the reason for this post.
Here's the code in question:
// `myList` can potentially be null.
children: widget.myList?.map((item) {
return Text("Hi.");
}).toList(),
I'm trying to loop over a List<String>? of errors in my stateful widget, inside of the children: property of a Column.
Dart is telling me that I cannot map over a List<String>?, and suggests that I use myList?.map instead.
However, when I do that, the issue now becomes that children: expects a List<Widget> and can therefore not accept a List<Widget>? ...
I seem to be stuck in circuitous errors, but somehow I feel the solution is simple. I'm still learning about null-safety.
So tl;dr:
How do I reconcile between a potentially null list of widgets, and a property that expects a list of widgets that isn't null?
Solution
children: myList?.map((e) => Text(e)).toList() ?? [],
If your List is List<Widget>?, you can add simply a null check like so:
children: _widgets?.map((item) => item).toList() ?? [Text('List was null')],
If your List is List<Widget?>? you can change it to:
children: _widgets?.map((item) => item ?? Text('widget was null')).toList() ?? [Text('List was null')],
If you want to map a List<String?> inside a Column
Column(
children: _strings.map((e) => Text(e ?? 'String was null')).toList(),
)
OR
Column(
children: _strings.map((e) => e == null ? Text('was null') : Text(e)).toList(),
)
If your List is List<String>?
Column(
children: _strings?.map((e) =>Text(e)).toList() ?? [Text('The list was null')],
)

Flutter GridView "type 'List<Widget> is not a subtype of type Widget"

it feels like I am doing something out of the ordinary!
I have 2 sub collections (subColl1 and subColl2) within 1 Collection in firebase firestore.
I get access to them with CollectionGroup
children: [
FutureBuilder<List<dynamic>>(
//<QuerySnapshot>(
future: Future.wait([
FirebaseFirestore.instance.collectionGroup('subColl1').get(),
FirebaseFirestore.instance.collectionGroup('subColl2').get(),
]),
Now I want to display both collections into a GridView.count() here:
return GridView.count(
restorationId: 'dashboardGridView',
crossAxisCount: 2,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
padding: const EdgeInsets.all(8),
childAspectRatio: 1,
children: <Widget>[
snapshot.data[0].docs.map<Widget>((document) {
return _DashboardGridViewItem(
document: document,
);
}).toList(),
snapshot.data[1].docs.map<Widget>((document) {
return _DashboardGridViewItem(
document: document,
);
}).toList(),
],
);
I tried individually snapshot.data[0].... and snapshot.data[1].... and they worked. But doing it like the above (which is both at the same time) throws an error type 'List<Widget>' is not a subtype of type 'Widget'
I understand the error but there must be a way to display both collections in the same gridview...
you will notice that I pass a document to a private method _DashboardGridViewItem(document: document), which is used to display information from the document. The other way I was thinking is to use a for loop surrounding the gridview and use the index i inside the snapshot.data[i]..... but then am I not returning 2 Gridviews???
need direction..
It is expecting a [Widget, Widget, Widget ..], you are instead giving [[Widgets], [Widgets]]
Simplest way to solve is to use the spread operator '...' as in below:
children: <Widget>[
...snapshot.data[0].docs.map<Widget>((document) {
return _DashboardGridViewItem(
document: document,
);
}).toList(),
...snapshot.data[1].docs.map<Widget>((document) {
return _DashboardGridViewItem(
document: document,
);
}).toList(),
],

Return a list of widgets in Flutter

Column(
children: <Widget>[
...myObject
.map((data) => Text("Text 1"), Text("Text 2")),
]
);
This block of code will fail because I'm returning 2 widgets instead of one. How could I fix it and return as many widget as I want without creating another column inside the map?
First you cant use an arrow function to return multiple values, you need to change it to a normal function that returns a list of widgets. Second, you need to use the .toList() method since .map is lazy and you need to iterate in order to map execute.
With this 2 steps you are going to end with a List<List<Widget>> and you should flat it before return it to a column that needs a List<Widget>. This can be achieved with the Iterable.expand() with an identity function.
You can try something like this:
Column(
children: <Widget>[
..._generateChildrens(myObjects),
],
),
And the actual implementation to obtain the widgets is:
List<Widget> _generateChildrens(List myObjects) {
var list = myObjects.map<List<Widget>>(
(data) {
var widgetList = <Widget>[];
widgetList.add(Text("Text 1"));
widgetList.add(Text("Text 2"));
return widgetList;
},
).toList();
var flat = list.expand((i) => i).toList();
return flat;
}
Hope it helps!

flutter get value from object and display in Text()

How to get value from an object in flutter? i need to display name of products in Text()
List<Object> _dataResponse = [
{"item":"chakka"},
{"item":"manga"},
{"item":"thenga"},
];
ListView(
children: _productName
.map((f) => ListTile(
leading: Icon(Icons.check_circle,color: Colors.green,),
title: **Text('$f["item"]')**,
))
.toList(),
)
For complex expressions (not just simple identifiers) you need to use ${...} instead of $...
Text('${f["item"]}')