How do I conditionally pass argument to Widget in Flutter/Dart? - flutter

I want to conditionally pass an argument while using the widget. Is there any way to do so?
...
return ListTile(
title: Text("${product.name}"),
// want to conditionally pass subtitle, which is not the right syntax (???)
if(condition) subtitle: Text("subtitle"),
// I know about this
subtitle: condition? Text("subtitle"): null,
);
},
...
I know we can conditionally pass the value as null using ternary operator here but what I am looking for is to skip the argument itself.
The above example is for ListTile widget. But my curiosity is to know the syntax for doing so for any widget.

Using optional named parameters, using parameter:value when a parameter is required pass its value else it can be skipped completely. Inside the called method null handling is required to be done by the developer(not handled internally).
This is a simplified sample:
void main() {
doNothing();
doNothing(index: 1);
doNothing(description: 'Printing');
doNothing(index: 1,description: 'Printing');
}
void doNothing({int index, String description}) {
print('Received => $index : $description');
}
Output:
Received => null : null
Received => 1 : null
Received => null : Printing
Received => 1 : Printing
Note: Default values can be assigned in the Widget/methods implementation and may not necessarily be always null.
Example:
void doNothing({int index, String description, String otherDesc = 'Provided By Default'}) {
print('Received => $index : $description : $otherDesc ');
}
Output:
Received => null : null : Provided By Default

Since not explicitly initialized variables in dart get automatically initialized to null (if they don't have a default value), for the widget there is no difference between not giving an argument to the optional parameter and giving the argument null.
Because of that setting it to null is actually skipping the argument. I would recommend just using the ternary operator in case you don't want to give an argument.

Related

In dart what is the difference between ? and ! for nullable types?

I am new to Dart and Flutter.
In dart what is the difference between using ? and ! for null-able types?
validator: ((value) {
if (value?.isEmpty) {
return "Field is required";
}
return null;
}),
validator: ((value) {
if (value!.isEmpty) {
return "Field is required";
}
return null;
}),
Thanks in advance!
Good topic about it : What is Null Safety in Dart?
But in short, you use "?" when you want to allow the value to be null and use it accordingly, like this:
String? test;
if (test?.isEmpty == true) { // And is not null, but you don't need to check it
// If null, will never pass there but without error
}
And use "!" when you want to be sure to have a non nullable value, like this:
String? test;
if (test!.isEmpty == true) { // Will throw an error
...
}
the difference between the two,one can be null initially, but the other cannot.
I hope you understand in the example below.
To specify if the variable can be null, then you can use the nullable type ?
operator, Lets see an example:
String? carName; // initialized to null by default
int? value = 36; // initialized to non-null
value = null; // can be re-assigned to null
Note: You don’t need to initialize a nullable variable before using it. It is initialized to null by default.
The Assertion Operator (!)
Use the null assertion operator ( ! ) to make Dart treat a nullable expression as non-nullable if you’re certain it isn’t null.
int? someValue = 30;
int data = someValue!; // This is valid as value is non-nullable
In the above example, we are telling Dart that the variable someValue is null, and it is safe to assign it to a non-nullable variable i.e. data
I hope you understand????
As for your example;
if you notice, the validator {String? value} value can initially be null. but the only difference between both works in the code you wrote will be the running cost. '?' it will cost some time when you define it again. because it is already stated in the function that it will be null as a start.
It's a good question and the answer is here as a person.
'?' it means it will get value later or it can be null( initially or at any instance) for example
String? carName;
'!' it means you are going to receive the value and it can not be null. it will check the value if the value is null it will give exception.
have a look on example for clear difference:
List? blocks;
...
// you are not sure blocks variable is initialized or not.
// block is nullable.
final Block? block = blocks?.first;
// you are sure blocks variable is initialized.
// block is not nullable.
final Block block = blocks!.first;
hope you got it if yes accept the answer or comment me if you have question

Can't assign non-nullable type to a nullable one

error: The argument type 'Future<List<GalleryPictureInfo>>' can't be assigned to the parameter type 'Future<List<GalleryPictureInfo>>?'.
Is this Dart Analysis or me? The project still compiles.
Upd. Added code example
FutureBuilder<List<GalleryPictureInfo>>(
future: derpiService.getListOfImages(),
//other code
);
#override
Future<List<GalleryPictureInfo>> getListOfImages(arguments) async {
List<GalleryPictureInfo> listOfImages = [];
var searchImages = await getSearchImages(tags: tags, page: page);
//adding images to List
return listOfImages;
}
It's something with FutureBuilder actually. I should've mention this.
Upd. "Fixed" with // ignore: argument_type_not_assignable
Looks like a problem with Dart Analysis for now
Upd. Error
It actually is an error which is pretty self explanatory.
The acutal error comes because of null safety in dart.
For ex:
void main(){
var number = getNumber(true);
int parsedNumber = int.parse(number);
print(parsedNumber);
}
String? getNumber(boolean value) {
if (value){
return null;
} else return "1";
}
So here, getNumber function either returns null or "1" depending upon the value of value variable. So, number variable's type is String?.
But the error shall arise in the next line when you try to call int.parse(). int.parse function takes an argument which should be a String but the value passed in the function is of type String?. So if we pass null in int.parse it shall throw an error.
That's why Dart analysis makes it easier to identify such cases by telling us that the value can be null and it might throw.
However the code depends upon your actual code of your project. It says that you are passing Future<List<GalleryPictureInfo>>? which is of nullable type to a function which requires Future<List<GalleryPictureInfo>>. So, before passing the value you might want to check if the value you are passing is not null.
If you are sure that the value can never be null then if for ex: if you are passing a variable called value, you might wanna try someFunctionWhereYouPassValue(value!)
That ! means that you are sure that the value will never be null.
For more details about null safety you can see:
https://dart.dev/null-safety/understanding-null-safety

How can I make null-safety assertions to avoid using null check (!) or conditional (?) operators in Flutter?

Dart compiler does not understand that the variable can not be null when I use it inside an if (x != null) statement. It still requires to use conditional ? or null check ! operators to access one of the variable's fields or methods.
Here is an example:
String? string;
void test() {
if (string != null) {
print(string.length);
}
}
This produces a compile-time error and says that
The property 'length' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?.') or adding a null check to the target ('!').
However, the receiver actually can't be null since it's wrapped with if (string != null) block. Accessing the field with string?.length or string!.length works fine but it can be confusing when I need to use different fields or methods of the variable.
String? string;
void test() {
if (string != null) {
print(string.length);
print(string.isNotEmpty);
print(string.trim());
print(string.contains('x'));
}
}
All of these statements raise the same error. I also tried putting assert(string != null); but the compiler still does not understand that the string is not null.
To give a more sophisticated example;
User? user;
#override
Widget build(BuildContext context) {
if (user == null) {
return Text('No user available');
} else {
return buildUserDetails();
}
}
Widget buildUserDetails() {
return Column(
children: [
Text(user.name),
Text(user.email),
],
);
}
This is still a problem for the compiler.
However, the receiver actually can't be null since it's wrapped
And that assumption is plain wrong.
Your variable is a global variable and any other part of your program, through multi-threading or other shenanigans can slip in between your if and the next line and change the variable.
That is why only local variables can be promoted to their non-null equivalent when the compiler proves that they cannot be null in certain code execution branches like an if.
The following will work perfectly fine, because you are operating on a local variable that the compiler can be sure won't be changed by outside operations:
String? string;
void test() {
final local = string;
if (local != null) {
// here, local was promoted from "string?" to "string"
// since the "if" makes sure it is not null AND
// the variable is not accessible to anything but this
// function, so it cannot be changed from the outside
// and is contrained to the sequential flow of this method.
print(local.length);
}
}
These are for sound null safety. Thats why whenever you start calling a functions / accessing it makes sure that the variable is not null by using ! or provide other case for null using ?.
Suppose for following case :
if (string != null) {
string=null; // Or through other function xyx() {string=null;} string becomes null then your if condition is void
print(string.length);
print(string.isNotEmpty);
print(string.trim());
print(string.contains('x'));
}
// Still sound null safety that's why above is not allowed
if (string != null) {
string=null; // Or through other function xyx() {string=null;} string becomes null then your if condition is void
print(string!.length);
print(string!.isNotEmpty);
print(string!.trim());
print(string!.contains('x'));
}
So for sound null safety it is required to be checked if string is not null before accessing it.
As per your comments you need to assign this nullable string to a non nullable string (~isdatablank~ means String was null) and proceed
String? string;
String s=string??"~isdatablank~";
if (s != "~isdatablank~") {
print(s.length);
print(s.isNotEmpty);
print(s.trim());
print(s.contains('x'));
}

How to deal with information that arrives null? - NoSuchMethodError

I'm getting null information from a web api. If a single information is null, the error will occur:
Error: Exception: NoSuchMethodError: '[]'
Dynamic call of null.
Receiver: null
Arguments: ["address"]
I declared this information in the model like this:
final String? address;
..
address: json['data1']['data2'][0]['data3']['address'][0]
I tried to do something like:
address: json['data1']['data2'][0]['data3']['address'][0].isEmpty
? ''
: json['data1']['data2'][0]['data3']['address'][0],
But it does not work.
I appreciate if anyone can help me analyze it!
The only thing you can do is to anticipate the null values and handle each case as needed.
For instance, if a null value is not accepted at all, you could wrap the code in throw ... catch statement then throw an error -- e.g.Missing Data and handle that error.
If having a null value is fine, you can use the null aware operator ? (or a nested if-statements if you prefer that). For example, assuming the value is a String, you could do something like this:
final String? myValue = json['data1']?['data2']?[0]?['data3']?['address']?[0];
Though, keep in mind if you're accessing a list by index, you still can get a RangeError if the index is out of range or if the list is empty. In such case you may need to split the process in a separate method and inspect each part separately such as:
String? extractValue(Map<String, dynamic> json) {
final firstList = json['data1']?['data2'];
if (firstList is List && firstList.isNotEmpty) {
final innerList = firstList[0]['data3']?['address'];
if (innerList is List && innerList.isNotEmpty) {
return innerList[0];
}
}
return null; // or return a default value or throw an error
}
You can handle such arguments ( arguments that give you null value) like this.
Let's say there's a variable a and there's a possibility that it'll give a null value, you can give it a default value.
For example:
There is a variable 'a', which is your data source.
String name = a ?? "This is not a null value";
The ?? would check if the value is null or not. If it's null, it would assign the value that you provided, otherwise it would keep the existing one.

Dart, Identifier with exclamation mark in the back

Recently I have been developing mobile aplication with flutter, when I looking at the source code for TickerProvider I see these lines:
mixin SingleTickerProviderStateMixin<T extends StatefulWidget> on State<T> implements TickerProvider {
Ticker? _ticker;
#override
Ticker createTicker(TickerCallback onTick) {
...
_ticker = Ticker(onTick, debugLabel: kDebugMode ? 'created by $this' : null);
return _ticker!;
}
...
}
I'm interested with this line:
return _ticker!;
I have seen boolean identifier with exclamation mark in the front meaning that it will return the opposite value of it, but I never see this one. Can someone tell me what this does?
It's part of the null safety that Dart have.
You can read about it here
If you’re sure that an expression with a nullable type isn’t null, you can add ! to make Dart treat it as non-nullable
Example:
int? aNullableInt = 2;
int value = aNullableInt!; // `aNullableInt!` is an int.
// This throws if aNullableInt is null.
For betrer undestanding (by analogy with the action of the algorithm itself).
This operator acts as the following inline internal function (at least similarly):
T cast<T>(T? value) {
if (value == null) {
throw _CastError('Null check operator used on a null value');
} else {
return value;
}
}
P.S.
Forgot to add.
Based on the error messages that are generated at runtime, we can conclude that this operator is called the Null check operator, which may mean that it checks the value for null and throws an exception if the value is null.
No magic!