how to handle empty array for text widget in build method? - flutter

How would I handle the objectA[0].name (a string) in the build method if the array is empty?
Text(objectB.objectC.objectA[0].name),

Assuming the array is objectC you can do something like:
Text(objectC.isEmpty? "" :objectC[0].name)
You can read more about ternary operators in dart here

There isn't a great way to do this inline but with a simple extension method to return the original null or the iterable depending on whether the item is null or empty you can make it work.
First
Extension Method
(requires dart v2.7 - update in your pubspec.yaml file)
extension IterableExtension<T> on Iterable<T> {
Iterable<T> get nullWhenEmpty =>
this == null || this.isEmpty ? null : this;
}
Second
To handle null values while you're traversing an object you can use the Dart's conditional member access operator (?.). This operator will only continue with the right-hand side if the left-hand side of the operator is not null. Use the elementAt method on a an iterable to be able to use the ?. operator in the chain. Then, use the ?. operations with the if null operator (??) to get your default value.
Solution
final String value = objectB?.objectC?.objectA?.nullWhenEmpty?.elementAt(0)?.name;
Text(value ?? 'Default Text');
You can, of course, inline the above code instead of using an additional variable.
Resources
Dart Language Tour: Other Operators
Dart Language Tour: Classes

Maybe checking if the list has an element, using isNotEmpty
child: (objectB.objectC.objectA.isNotEmpty)
? Text(objectB.objectC.objectA[0].name)
: Container(),

Related

Syntactic sugar for calling a function with a nullable value that might return null

I am looking for syntactic sugar with null-safe-operators to do this:
map["key"] == null ? default : (int.tryParse(map["key"]!) ?? default)
This however accesses map twice and requires default twice.
Better, but verbose code that also compiles:
String? val = map["key"];
int? res;
if (val != null) { res = int.tryParse(val) }
res ??= default;
In essence I am looking for a way to only call a function if the parameter is not null. E.g. in kotlin you could do (pseudocode)
map["key"].let{ int.tryParse(it) } ...
I found this related question, however writing helper methods is even more verbose and I cannot edit the function to take nullable parameters.
What i would love to see for dart (but afaik this does not exist):
int.tryParse(map["key"]?) ?? default;
I.e. func(null?) => null, no matter what func is, or sth similar.
Is there a smooth way to do that or is the verbose way for now the "accepted" way?
EDIT
I am aware of the int.tryParse("") or int.tryparse(default.toString() hacks, however both are somewhat naughty as they will call tryParse either way instead of skipping it if the value is null anyways. (imagine replacing tryParse with a very expensive factory method)
There is two things you can do:
int.parse(map["key"] ?? default.toString());
This would work if you are sure that map["key"] can be parsed if it is not null.
If you have to do this operation a lot you can also write your own extension function and then use the null-safe operator:
extension NullSaveParser on String {
int? tryToInt() {
return int.tryParse(this);
}
}
And then use this:
map["key"]?.tryToInt() ?? default;
This extension is neccessary because there is currently no way in dart to not call a method if an argument would be null, only if the object that you are calling it on is null can be caught.
I hope this helps.
It's sort of a hack and maybe ugly but for this case you might want to write something like
int.tryParse(map["key"] ?? '') ?? default
That is, put a fallback value inside the tryParse that you know will make the tryParse return null

Conditionally execute a funtion, throws error `Conditions must have a static type of 'bool'. Try changing the condition`

I want to feed Two to the function. When function receives Two as the data, it should print success to the console. But seems like it's not the correct way.
Error: Conditions must have a static type of 'bool'. Try changing the condition.
List
enum ButtonList {One, Two, Three}
Calling function
testFunc(ButtonList.Two)),
Function
testFunc( ButtonList type) {
if (type = ButtonList.Two ){print('sucess ')};
}
It should be:
testFunc(ButtonList type) {
if (type == ButtonList.Two) {
print('sucess ')
};
}
There's a big difference between = (assigning a value to a variable) and == (equality comparison). if expects a condition (==), not the assigning operation (=).
Formatting is important to read and understand the code. Please read Dart best code style practices: https://dart.dev/guides/language/effective-dart/style
You are trying to assign with =, use == instead

Flutter null-safety conditionals in object methods

I'm just working through this whole null-safety mode with my Flutter project and unsure what the difference is with ? and ! in calls to object methods.
For example, the hint was to add a ! conditional. Here's an example I have right now, and I'm unsure if this should be a ? or a ! at the findNbr!.replaceAll().
Future checkItem({String? findNbr}) async {
int? x = int.tryParse(findNbr!.replaceAll('-', ''));
...
Does this mean replaceAll() will not run if findNbr is null?
Or should it be a ? instead? findNbr?.replaceAll()
EDIT: I just noticed I cannot use findNbr?, it's telling String? can't be assigned parameter String.
Or does it mean I say it's not null and run it anyway?
For your information, I have not come close to running my app yet so I have no idea if it even works. But I figure I better know what it's doing before get too much more done. I'm still in the process of converting everything and there's 75-100 dart files. I'm not sure I get the point of it all to be honest, because I just add ? to everything, so its all nullable anyway.
Future checkItem({String? findNbr}) async {
int? x = int.tryParse(findNbr!.replaceAll('-', ''));
...
Does this mean replaceAll() will not run if findNbr is null?
Correct. If findNbr is null, then findNbr! will throw a runtime exception. That would be bad, especially since checkItem's function signature advertises that findNbr is allowed to be null, and therefore it would violate callers' expectations.
Or should it be a ? instead? findNbr?.replaceAll()
EDIT: I just noticed I cannot use findNbr?, it's telling String? can't be assigned parameter String.
You can't use findNbr?.replaceAll(...) because if findNbr is null, then it would be invoking int.tryParse(null), but int.tryParse is not allowed to take a null argument.
What you need to do is one of:
Make findNbr no longer optional:
Future checkItem({required String findNbr}) async {
int? x = int.tryParse(findNbr.replaceAll('-', ''));
...
Allow findNbr to be optional but have a non-null default value:
Future checkItem({String findNbr = ''}) async {
int? x = int.tryParse(findNbr.replaceAll('-', ''));
...
Allow findNbr to be optional but explicitly decide what to do if it is null. For example:
Future checkItem({String? findNbr}) async {
int? x = findNbr == null ? null : int.tryParse(findNbr.replaceAll('-', ''));
...
I'm not sure I get the point of it all to be honest, because I just add ? to everything, so its all nullable anyway.
If you blindly add ? to all types and add ! to all variables, then yes, null-safety would be pointless: doing that would give you the same behavior as Dart before null-safety.
The point of null-safety is to prevent things that shouldn't be null from ever being null. You could have written such code before, but without null-safety, that meant performing runtime null checks (e.g. assert(x != null);, if (x != null) { ... }, or relying on a null-pointer-exception to crash the program if null was used where it wasn't expected). Null-safety means that such checks now can be done at build-time by static analysis, which means that errors can be caught earlier and more completely. Furthermore, whereas previously functions needed to explicitly document whether arguments and return values were allowed to be null (and inadequate or incorrect documentation could be a source of errors), now they're self-documenting in that regard. It's just like using int foo(String s) versus dynamic foo(dynamic s); using strong types catches errors earlier and better describes the function's contract.
I recommend reading Understanding Null Safety if you haven't already done so.
I would like to advice you to use the ! operator, also the called bang operator, as little as possible. You should only use this operator when the dart analyser is wrong and you know for 100% that the value will never be null.
Below is an example of where the dart analyser would be wrong and you should use the bang operator.
// We have a class dog with a nullable name.
class Dog {
String? name;
Dog({this.name});
}
void main() {
// We create a dog without a name.
final dog = Dog();
// We assign the dog a name.
dog.name = 'George';
// The dart analyser will show an error because it can't know if the
// name of the object is not null.
//
// Will throw: `A value of type 'String?' can't be assigned to a
// variable of type 'String'`.
String myDogsName = dog.name;
// To avoid this, you should use the bang operator because you `know` it
// is not null.
String myDogsName = dog.name!;
}
The ? operator simply tells Dart that the value can be null. So every time you want to place a ? operator, ask yourself, can this value ever be null?
The null safety features in Dart are mainly created for helping the developer remember when a value can be null. Dart will now simply tell you when you made a variable nullable in order to force null checks or default values for example.

Multi if statement in class parameters setting

I know that in the latest version of dart we can use if else statements inside the build method. Does anyone know if we can use also if else statement when we setting class parameters? I know I can do inline statement there but inline is a bit hard to read when there are multiple conditions
const int i = 0;
class Person {
// NewClass n = NewClass(a: i == 0 ? 'a' : 'b'); //<- inline statement working
NewClass n = NewClass(a: if(i == 0) 'a' else 'b'); //<- if statement doesn't
}
class NewClass {
final String a;
const NewClass({this.a});
}
Edit:
Basically in my case I've got an TextField widget where I set its's type parameter from enum (Type.text, Type.numeric...) According to this parameter I want to set The textField parameters (textCapitalization, maxLength and so on)
As per your comment, you are already creating an enum for specifying the type of the fields.
enum Type {text, numeric}
Now for specifying the properties of that particular type, you can add an extension on this enum, as shown below:
extension TextFieldProperties on Type {
int get maxLength {
if (this == Type.text) {
return 10;
}
return 12;
}
}
So in your field class you already have a type defined, you can use that type variable to get the properties of that particular type of field.
Type type = Type.text;
print(type.maxLength); // Will print 10
type = Type.numeric;
print(type.maxLength); // Will print 12
Note: It will work only in Dart 2.7 and above
You want the conditional expression (?:), not the conditional statement or literal entry (if), as you have already discovered.
The reason if doesn't work is that if only works as a statement or as a collection literal entry. It doesn't work in arbitrary expressions.
The reason for the distinction is that the if syntax allows you to omit the else branch. That only makes sense in places where "nothing" is a valid alternative. For a statement, "doing nothing" is fine. For a collection, "adding nothing" is also fine.
In an expression context, you must evaluate to a value or throw. There is no reasonable default that we can use instead of "nothing", so an if is not allowed instead of an expression.
Doesn't work because this syntax doesn't exist in Dart. The only way to do what you would like to do is to use the ternary operator.
If you try it in the DartPad you will get an error.
I suggest you to use a function to return the right value.

What is "?." operator in flutter

I am using a library and in many places ?.
operator is used i am unable to understand it's purpose.
Timer _debounceTimer;
#override
initState() {
_textController.addListener(() {
// We debounce the listener as sometimes the caret position is updated after the listener
// this assures us we get an accurate caret position.
if (_debounceTimer?.isActive ?? false) _debounceTimer.cancel();
?. [Conditional member access] - Like ., but the leftmost operand can be
null; example: foo?.bar selects property bar from expression foo
unless foo is null (in which case the value of foo?.bar is null)
from Dart Language Tour (Other Operators)
TLDR: It is simply does a null check before accessing member. If left hand side of the operator is not null then it works simply as . and if it is null value then the whole thing is null.
In your example: _debounceTimer?.isActive - if _debounceTimer is null then _debounceTimer?.isActive <-> null and if _debounceTimer is not null then _debounceTimer?.isActive <-> _debounceTimer.isActive.
Also check: Dart Language tour (Conditional Expressions) for ?? and ? operator.