I keep getting this error that res is not defined, so I am trying to figure out how to run the column code after res is defined like in js you can do {res && (code)}.
Column(
children: res['rooms'].map((r) => Card(
'name',
'${r['messages'][r['messages'].length - 1]['content']}',
'${r['_id']}'
)),
),
You can check if your res variable is equal to null.
This is the non nullable approach to your problem, but you should check to migrate your project to null safety to avoid all those null checks.
res == null
? Column(
children: res['rooms'].map((r) => Card(
'name',
'${r['messages'][r['messages'].length - 1]['content']}',
'${r['_id']}')),
)
: Container(),
It can be hard to read ternary expressions sometimes if you have a large widget within a expression. It also requires you to provide an "else" widget.
I approach this with the spread operator, with a single if statement
Column(
children: <Widget>[
if (res != null)
...res.map((r) => Card(
'name',
'${r['messages'][r['messages'].length - 1]['content']}',
'${r['_id']}')),
],
)
Simple use ternary login like this -
Container(
child: res != null
? Column(
children: []
)
: SizedBox() //Use SizedBox instead of Container for better efficiency
)
And update the UI again once "res" is populated.
Related
I am working on a UI where I have 3 checks in the same container.
I am able to achieve only one condition but not able to the second one or third one.
till now I have created a container where I have made a column and included all things and used a bool variable which changes when I click the text and it reverts back when I click the close button.
But now the problem is How can I use 3 conditions in the same column?
my code till now
bool makePayment = false;
makePayment ? Column( crossAxisAlignment:
children: [
const Text('Quick actions'),
const SizedBox(),
Row(),
Row()
]) : Column()
you could use a lot of condition in the same way as you did just the question will be more complicated , example :
A.isNumber ? do1 : A.isAlpha? do2 : A.isSymbol ? do3 : do4
You can use else-if into your column children.
The Syntax is
Column(
children: <Widget>[
if(your condition) ...[
//YOUR CODE
] else if(your condition) ...[
//YOUR CODE
] else ...[
//YOUR CODE
]
]
)
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')],
)
Before Flutter introduced the null-safety feature, I was able to conditionally add Widgets within a list like so:
actions: <Widget>[
canCancel
? CupertinoDialogAction(
child: Text(cancelActionText),
onPressed: () {
Navigator.pop(context);
},
)
: null,
].where(notNull).toList()
notNull being a homemade filter that filters off the null objects...
Now with null-safety it's impossible because the list of Widgets strictly has to be non-null.
What would be a better approach?
Just use if inside the List:
<Widget>[
if (true) Widget(),
]
Example with your code:
actions: <Widget>[
if (canCancel)
CupertinoDialogAction(
child: Text(cancelActionText),
onPressed: () {
Navigator.pop(context);
},
),
]
Just replace your null with an empty, size zero, SizedBox.
SizedBox(width: 0, height: 0)
Or as suggested in comments:
SizedBox.shrink()
As YoBo suggested, using collection-if is the better approach here, but if for some reason you need to be able to store nulls in a List and filter them out later (or if you just prefer your existing style), you can:
Change your List type to allow nullable elements. That is, use <Widget?>[] instead of <Widget>[].
Use Iterable.whereType with a non-nullable type to filter out null values.
actions: <Widget?>[
canCancel
? CupertinoDialogAction(
child: Text(cancelActionText),
onPressed: () {
Navigator.pop(context);
},
)
: null,
].whereType<Widget>().toList();
if is not new as it was added in Dart 2.3 a few years ago. Even before null-safety, you were not allowed to return a null for a widget. You might not see a compile-time warning before NNBD, but it is a runtime error.
As I mentioned in this answer (although that answer isn't for your case), you can use if condition or even ternary operator like this:
Column(
children: [
if (condition) Text(''),
condition ? Text('') : Container(),
],
)
Why does the first work, but the second does not? The issue with the first is that null throws assertion exception since the widget cannot be null. what is the best practice in this scenario?
Row(
children: listOfWidgets != null ? listOfWidgets : null
)
Row(
children: if (listOfWidgets != null) listOfWidgets;
)
Current workaround:
void List<Widget> _rowWidgets() {
if(listOfWidgets != null) return listOfWidgets;
}
Row(
children: _rowWidgets();
)
Each of the three options listed has its own problem, so I'll address them individually.
Issue:
Row(
children: listOfWidgets != null ? listOfWidgets : null,
)
Solution:
Row(
children: listOfWidgets != null ? listOfWidgets : [],
)
Explanation
This is fine except for if listofWidgets is null. That would cause the ternary operator to return null, and Row doesn't allow its children property to be null. You need to give it a non-null default value like [] instead.
Issue:
Row(
children: if (listOfWidgets != null) listOfWidgets;
)
Solution:
Row(
children: [ if (listOfWidgets != null) ...listOfWidgets ],
)
Explanation:
This syntax is wrong in Dart because you can't have a nested if statement like this. if statements have to either exist on their own live of code or (since Dart 2.3) nested within a list/map literal. If you do the nested-in-list-literal route, you will also need the spread operator ... on the listOfWidgets to expand it into the other list. Otherwise, you will end up trying to put a list within a list, which Row will not allow you to do.
Issue:
void List<Widget> _rowWidgets() {
if (listOfWidgets != null) return listOfWidgets;
}
Row(
children: _rowWidgets();
)
Solution:
List<Widget> _rowWidgets() {
if (listOfWidgets != null) return listOfWidgets;
return [];
}
Row(
children: _rowWidgets(),
)
Ignoring the more glaring syntax errors (semicolon where a comma is expected, dual return types), this one is similar to the ternary issue, albeit a bit more subtly. In Dart, every method that doesn't have void as a return type has to return something. If you don't explicitly return something, the method will return null by default. This is what happens in your _rowWidgets method - you don't state what would be returned if listOfWidgets is null, so Dart will return null for you in that case. And just like the ternary issue, Row will not allow children to be null.
Overall Suggestion:
Row(
children: listOfWidgets ?? [],
)
Explanation:
Ultimately, all you are concerned with is making sure the Row receives a non-null value if listOfWidgets happens to be null. Dart has the perfect operator for this: the null-coalescing operator ??. What it does is it returns the value on the left unless that value is null, in which case it returns the value on the right.
To illustrate it more clearly, the following lines of code perform identically:
// If option
if (listOfWidgets != null) return listOfWidgets;
else return [];
// Ternary option
return listOfWidgets != null ? listOfWidgets : [];
// Null-coalescing option
return listOfWidgets ?? [];
The first case, the ternary has the form statement? a : b, and always returns or a or b. Thats the trick, the ternary always has a return statement even if we cant see it. The if doesnt has that statement by default, so you need to explicitly declare the return if you want one.
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: