I get an error with snapshot.data()["~~~"] flutter - flutter

I'm trying to get the value from Firestore with the following code. But I'm sorry I got this error. Help me
DocumentSnapshot snapshot = await FirebaseFirestore.instance.collection("users").doc(user.uid).get();
print(snapshot.data()["location"] as String);
Details of the error
The method '[]' can't be unconditionally invoked because the receiver can be 'null'. Try making the call conditional (using '?.') or adding a null check to the target ('!').
I tried various things, for example print(snapshot.data()!['location'] as String);
error code
The operator '[]' isn't defined for the type 'Object'. Try defining the operator '[]'.```

The method '[]' can't be unconditionally invoked because the receiver can be 'null'. Try making the call conditional (using '?.') or adding a null check to the target ('!').
As you might be able to guess, you are getting an error because if the snapshot has no data, it will return null, which will error. Here are some ways of fixing it:
adding a bang operator (!) (But you say this did not fix the issue?)
print(snapshot.data()!['location'] as String);
note the ! after data(), the bang operator tells dart to ignore a nullable value, this code will work as long as snapshot.data() is not null, of course, this is not safe, because snapshot.data() could be null, so here is an obvious solution:
var data = snapshot.data();
if (data != null) {
print(data!['location'] as String);
}
this should work, because now if data is null, the print statement will simply not run.
adding a ? operator
print(snapshot?['location']);
note the ? after data(), the ? operator will escalate a null value, so if snapshot.data() is not null, snapshot.data()?['location'] will be equal to snapshot.data()['location'], but if snapshot.data() is null, snapshot.data()?['location'] will be equal to null instead of throwing an error.
Adding a ?? operator
print(snapshot.data()?['location'] ?? 'the value was null');
Here, it is necessary to use both the ? operator to escalate the null value and the ?? operator.
The ?? operator will output the value on the left if the value is not null and will output the value on the right if the value on the left is null, so in this case, if snapshot.data() is null, that will escalate the null value, meaning snapshot.data()?['location'] will be null, which in turn means that instead of printing 'null', the ?? operator will print 'the value was null'
So to conclude, if you are sure the value is not null, you can use the bang operator !, if you are not sure, then you can use a combination of ? and ?? to your advantage.
Edit
It looks like adding one of the above solutions still won't fix the issue, here is an updated version that will hopefully fix the new issues?
print((snapshot.data()! as Map<String, dynamic>)['location'] as String);

you need to add null check operator to make sure that receiver is not null.
print(snapshot.data()!["location"] as String);

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

What does the '!' at the end of my code do?

Text(locations[index].location!)
without the '!' I get the next error:
The argument type 'String?' can't be assigned to the parameter type 'String'
Thanks in advance!
locations[index].location can return null, using ! we are saying, the value of it won't be null. Text widget doesn't accept null value.
It is better to do a null check 1st on nullable data like
if (locations[index].location != null) Text(locations[index].location)
or you can provide default value
Text(locations[index].location ?? "got null")
You can also do
Text("${locations[index].location}");
The exclamation mark (!) in Dart tells the code that you are sure this variable can never be null. It is an unsafe way of dealing with variables that may be null.
In your case, the type of the variable is String?, which means that it may be null or a String.
To safely unwrap a nullable variable, it is advised to do the following:
if (locations[index].location != null) {
//Do your logic here
}
Null Safety Documentation
It means it is a nullable type, which means it can be initialized without any value.

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.

Warning implementing list filtering in Flutter

I have the following code to filter a list from data to be shown in a listView:
child: FutureBuilder(
future: fetchPacientes('todo'),
builder: (context, snapshot) {
if (snapshot.hasData) {
var filteredList = snapshot.data;
print("a minusculas:" +
_controller.text.toLowerCase());
filteredList = filteredList
.where((element) => (element.nombre
.toLowerCase()
.contains(
_controller.text.toLowerCase()) ||
element.NHC.toLowerCase().contains(
_controller.text.toLowerCase()) ||
element.apellidos.toLowerCase().contains(
_controller.text.toLowerCase())))
.toList();
But I am getting an error at point:
.where(...
This is the error output:
The method 'where' can't be unconditionally invoked because the receiver can be 'null'.
I am trying to migrate an old app to Null Safety, but I am not able to solve this issue. The proposed solution is to add a null check at filteredList! but the error is not removed when doing that way
That error means that the object on which the . is applied (in this case, the filteredList) can be null, so it would throw an exception if filteredList will be actually null.
So, to avoid the error, you have these options:
Add a ! after filteredList: in this case, you're assuring the compiler that filteredList will never ever be null, and the error will disappear. Note that this doesn't actually prevent it from being null: you're just reassuring the compiler about it, and filteredList could still be null. In that case, the app will throw a dedicated exception telling you that it found a 'null' object when you declared in the code that this should not have happened
Check if filteredList is null: add a few lines of code testing if it is really null, and then handle the case, even something basic like returning a Text('filteredList is empty'). After this, you can safely write filteredList! because you are sure that it will never be null, since you actually tested id.
Set a default value for filteredList in case it's null: Dart has this operator that assigns a value to an object if it is null: filteredList ??= []. Again, after using this, you can safely write filteredList! because it will never be null.
PS sorry, didn't notice the last sentence. Since adding ! and a null check isn't working, I'd try setting a default value for filteredList. Or maybe checking for null on snapshot.data, and then set an explicit non-nullable type for filteredList, like List<Object> filteredList.
The error is becausesnapshot.data can be null. Try adding a ? before your .where like so :
filteredList = filteredList?.where(...);

Dart null safety !. vs ?-

what is the difference exactly between
String id = folderInfo!.first.id; //this works
and
String id = folderInfo?.first.id; //this is an error
I know ?. returns null when the value object is null but what does the !. return?
?. is known as Conditional member access
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)
In your case, String id means id can not have null value. But using ?. can return null that's why it is showing errors.
!. is use If you know that an expression never evaluates to null.
For example, a variable of type int? Might be an integer, or it might be null. If you know that an expression never evaluates to null but Dart disagrees, you can add ! to assert that it isn’t null (and to throw an exception if it is).
More and ref:
important-concepts of null-safety and operators.
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.
In other words !. will throw an error if the value is null and will break your function and as you know ?. will return null with no interruption.
The ! throws an error if the variable is null. You should try to avoid this if possible.
If you’re sure that an expression with a nullable type isn’t null, you can use a null assertion operator (!) to make Dart treat it as non-nullable. By adding ! just after the expression, you tell Dart that the value won’t be null, and that it’s safe to assign it to a non-nullable variable.
In your first case, you define id not nullable but when you set nullable value then throw error.
String id = folderInfo?.first.id;
In 2nd case, when you use assertion operator (!), it actually tell compiler that it must be non nullable.