Flutter Firestore NoSuchMethodError
I'm developing app with flutter and trying to get data from firestore by using streambuilder method like so.
body: new StreamBuilder<DocumentSnapshot>(
stream: Firestore.instance.collection('user').document(uid).collection('userInfo').document(uid).snapshots(),
builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) return new Center(child: new CircularProgressIndicator());
if (snapshot.hasData) {
return new Center(
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.only(left: 24.0, right: 24.0),
children: <Widget>[
new Column(
children: <Widget>[
new CircleAvatar(
backgroundColor: Colors.transparent,
radius: 48.0,
child: Image.asset('assets/logo.png'),
),
new Padding(padding: const EdgeInsets.only(bottom: 20.0)),
new Text(snapshot.data['name'],
style: new TextStyle(fontSize: 28.0)),
new Padding(padding: const EdgeInsets.only(bottom: 35.0)),
],
),
new Column(
children: <Widget>[
new Row(
children: <Widget>[
new Column(
children: <Widget>[
new Icon(
Icons.accessibility,
size: 18.0,
),
new Text('Age',
style: new TextStyle(
fontSize: 12.0, color: Colors.blue)),
],
),
new Padding(
padding: const EdgeInsets.only(right: 16.0)),
new Text(snapshot.data['age'].toString(), style: new TextStyle(fontSize: 25.0)),
],
),
new Padding(padding: const EdgeInsets.only(top: 3.0)),
new Divider(color: Colors.grey, height: 1.0),
new Padding(padding: const EdgeInsets.only(bottom: 25.0)),
new Row(
children: <Widget>[
new Column(
children: <Widget>[
new Icon(
Icons.place,
size: 18.0,
),
new Text('State',
style: new TextStyle(
fontSize: 11.0, color: Colors.blue)),
],
),
new Padding(
padding: const EdgeInsets.only(right: 16.0)),
new Text(snapshot.data['state'], style: new TextStyle(fontSize: 25.0)),
],
),
new Padding(padding: const EdgeInsets.only(top: 3.0)),
new Divider(color: Colors.grey, height: 1.0),
new Padding(padding: const EdgeInsets.only(bottom: 25.0)),
new Row(
children: <Widget>[
new Column(
children: <Widget>[
new Icon(
Icons.audiotrack,
size: 18.0,
),
new Text('Hobby',
style: new TextStyle( fontSize: 11.0, color: Colors.blue)),
],
),
new Padding(
padding: const EdgeInsets.only(right: 16.0)),
new Text(snapshot.data['hobby'], style: new TextStyle(fontSize: 26.0)),
],
),
new Padding(padding: const EdgeInsets.only(top: 3.0)),
new Divider(color: Colors.grey, height: 1.0),
],
),
new SizedBox(height: 45.0),
new RaisedButton(
child: new Text('New Request',
style:
new TextStyle(color: Colors.white, fontSize: 20.0)),
color: Colors.blueAccent,
splashColor: Colors.blueGrey,
onPressed: () {
_toNewRequest();
},
),
],
),
);
} else {
return new Center(
child: new Text('You havent set profile'),
);
}
},
),
but error says this
flutter: The following NoSuchMethodError was thrown building
StreamBuilder(dirty, state: flutter:
_StreamBuilderBaseState>#f91a2) The method '[]' was
called on null. Receiver: null Tried calling:[]
("name")
but if I refresh(restart maybe) the app, click the green arrow,
then it shows data correctly.
why is this not working when app launches?
Thank you in advance!
Answering with example code because of multiple questions on the same.
This can be used as a reference to using streamBuilder with Firestore.
Stream Builder Example :
SingleChildScrollView(
child: StreamBuilder(
stream: getClientProfile().snapshots(),
builder: (context, snapshots) {
if (snapshots.connectionState == ConnectionState.active) {
Client client = Client.from(snapshots.data);
return Column(
children: [
HeaderDetails(client.productCategories, client.businessName,
client.coverPhoto, client.avatarPhoto),
SizedBox(
height: 20.0,
),
_displayInformationCard(
client.businessCategory, client.businessDescription),
_locationInformationCard(client.address.getFullAddress()),
_contactInformation(client),
],
);
} else if (snapshots.connectionState == ConnectionState.waiting) {
return Container(child: Center(child: CircularProgressIndicator()));
} else {
return Container(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.warning),
),
Text('Error in loadind data')
],
),
);
}
},
),
);
firestore call example :
DocumentReference getClientProfile() {
return _fireStore.collection(SELLERS_COLLECTION).document(docId);
}
and the model class, to structure your document in dart :
import 'package:cloud_firestore/cloud_firestore.dart';
class Client {
final DocumentReference documentReference;
String sellerId;
String businessName, businessDescription, businessCategory;
List productCategories;
String coverPhoto, avatarPhoto;
Representative representative;
Address address;
Client.data(this.documentReference,
[this.sellerId,
this.businessName,
this.businessDescription,
this.businessCategory,
this.productCategories,
this.coverPhoto,
this.avatarPhoto,
this.representative,
this.address]) {
this.sellerId ??= '';
this.businessName ??= '';
this.businessDescription ??= '';
this.businessCategory ??= '';
this.productCategories ??= [];
this.coverPhoto ??= '';
this.avatarPhoto ??=
'';
}
factory Client.from(DocumentSnapshot document) => Client.data(
document != null ? document.reference : null,
document.data['sellerId'],
document.data['businessName'],
document.data['businessDescription'],
document.data['businessCategory'],
document.data['productCategories'],
document.data['coverPhoto'],
document.data['avatarPhoto'],
Representative.from(document.data['representative']),
Address.from(document.data['pickupAddress']),
);
Map<String, dynamic> toMap() {
return {
'sellerId': sellerId,
'businessName': businessName,
'businessDescription': businessDescription,
'businessCategory': businessCategory,
'productCategories': productCategories,
'coverPhoto': coverPhoto,
'avatarPhoto': avatarPhoto,
'representative': representative.toMap(),
'pickupAddress': address.toMap(),
};
}
}
class Address {
String building;
String street;
String location;
double lat;
double lng;
Address.data(this.building, this.street, this.location, this.lat, this.lng) {
this.building ??= '';
this.street ??= '';
this.location ??= '';
this.lat ??= 0.0;
this.lng ??= 0.0;
}
factory Address.from(address) => Address.data(address['building'],
address['street'], address['location'], address['lat'], address['lng']);
getFullAddress() {
return building + ', ' + street + '\n' + location;
}
Map<String, dynamic> toMap() {
return {
'building': building,
'street': street,
'location': location,
'lat': lat,
'lng': lng,
};
}
}
class Representative {
String representativeName;
String contactNumber;
String email;
Representative.data(this.representativeName, this.contactNumber, this.email) {
this.representativeName ??= '';
this.contactNumber ??= '';
this.email ??= '';
}
factory Representative.from(representative) => Representative.data(
representative['representativeName'],
representative['contactNumber'],
representative['email']);
Map<String, dynamic> toMap() {
return {
'representativeName': representativeName,
'contactNumber': contactNumber,
'email': email,
};
}
}
The code was built using this as the reference.
body: new StreamBuilder<DocumentSnapshot>(
stream: Firestore.instance.collection('user').document(uid).collection('userInfo').document(uid).snapshots(),
builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) return new Center(child: new CircularProgressIndicator());
if (snapshot.hasData) {
return new Center(
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.only(left: 24.0, right: 24.0),
children: <Widget>[
new Column(
children: <Widget>[
new CircleAvatar(
backgroundColor: Colors.transparent,
radius: 48.0,
child: Image.asset('assets/logo.png'),
),
new Padding(padding: const EdgeInsets.only(bottom: 20.0)),
new Text(snapshot.data['name'],
style: new TextStyle(fontSize: 28.0)),
new Padding(padding: const EdgeInsets.only(bottom: 35.0)),
],
),
new Column(
children: <Widget>[
new Row(
children: <Widget>[
new Column(
children: <Widget>[
new Icon(
Icons.accessibility,
size: 18.0,
),
new Text('Age',
style: new TextStyle(
fontSize: 12.0, color: Colors.blue)),
],
),
new Padding(
padding: const EdgeInsets.only(right: 16.0)),
new Text(snapshot.data['age'].toString(), style: new TextStyle(fontSize: 25.0)),
],
),
new Padding(padding: const EdgeInsets.only(top: 3.0)),
new Divider(color: Colors.grey, height: 1.0),
new Padding(padding: const EdgeInsets.only(bottom: 25.0)),
new Row(
children: <Widget>[
new Column(
children: <Widget>[
new Icon(
Icons.place,
size: 18.0,
),
new Text('State',
style: new TextStyle(
fontSize: 11.0, color: Colors.blue)),
],
),
new Padding(
padding: const EdgeInsets.only(right: 16.0)),
new Text(snapshot.data['state'], style: new TextStyle(fontSize: 25.0)),
],
),
new Padding(padding: const EdgeInsets.only(top: 3.0)),
new Divider(color: Colors.grey, height: 1.0),
new Padding(padding: const EdgeInsets.only(bottom: 25.0)),
new Row(
children: <Widget>[
new Column(
children: <Widget>[
new Icon(
Icons.audiotrack,
size: 18.0,
),
new Text('Hobby',
style: new TextStyle( fontSize: 11.0, color: Colors.blue)),
],
),
new Padding(
padding: const EdgeInsets.only(right: 16.0)),
new Text(snapshot.data['hobby'], style: new TextStyle(fontSize: 26.0)),
],
),
new Padding(padding: const EdgeInsets.only(top: 3.0)),
new Divider(color: Colors.grey, height: 1.0),
],
),
new SizedBox(height: 45.0),
new RaisedButton(
child: new Text('New Request',
style:
new TextStyle(color: Colors.white, fontSize: 20.0)),
color: Colors.blueAccent,
splashColor: Colors.blueGrey,
onPressed: () {
_toNewRequest();
},
),
],
),
);
} else {
return new Center(
child: new Text('You havent set profile'),
);
}
},
),
but error says this
flutter: The following NoSuchMethodError was thrown building
StreamBuilder(dirty, state: flutter:
_StreamBuilderBaseState>#f91a2) The method '[]' was
called on null. Receiver: null Tried calling:[]
("name")
but if I refresh(restart maybe) the app, click the green arrow,
then it shows data correctly.
why is this not working when app launches?
Thank you in advance!
Answering with example code because of multiple questions on the same.
This can be used as a reference to using streamBuilder with Firestore.
Stream Builder Example :
SingleChildScrollView(
child: StreamBuilder(
stream: getClientProfile().snapshots(),
builder: (context, snapshots) {
if (snapshots.connectionState == ConnectionState.active) {
Client client = Client.from(snapshots.data);
return Column(
children: [
HeaderDetails(client.productCategories, client.businessName,
client.coverPhoto, client.avatarPhoto),
SizedBox(
height: 20.0,
),
_displayInformationCard(
client.businessCategory, client.businessDescription),
_locationInformationCard(client.address.getFullAddress()),
_contactInformation(client),
],
);
} else if (snapshots.connectionState == ConnectionState.waiting) {
return Container(child: Center(child: CircularProgressIndicator()));
} else {
return Container(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.warning),
),
Text('Error in loadind data')
],
),
);
}
},
),
);
firestore call example :
DocumentReference getClientProfile() {
return _fireStore.collection(SELLERS_COLLECTION).document(docId);
}
and the model class, to structure your document in dart :
import 'package:cloud_firestore/cloud_firestore.dart';
class Client {
final DocumentReference documentReference;
String sellerId;
String businessName, businessDescription, businessCategory;
List productCategories;
String coverPhoto, avatarPhoto;
Representative representative;
Address address;
Client.data(this.documentReference,
[this.sellerId,
this.businessName,
this.businessDescription,
this.businessCategory,
this.productCategories,
this.coverPhoto,
this.avatarPhoto,
this.representative,
this.address]) {
this.sellerId ??= '';
this.businessName ??= '';
this.businessDescription ??= '';
this.businessCategory ??= '';
this.productCategories ??= [];
this.coverPhoto ??= '';
this.avatarPhoto ??=
'';
}
factory Client.from(DocumentSnapshot document) => Client.data(
document != null ? document.reference : null,
document.data['sellerId'],
document.data['businessName'],
document.data['businessDescription'],
document.data['businessCategory'],
document.data['productCategories'],
document.data['coverPhoto'],
document.data['avatarPhoto'],
Representative.from(document.data['representative']),
Address.from(document.data['pickupAddress']),
);
Map<String, dynamic> toMap() {
return {
'sellerId': sellerId,
'businessName': businessName,
'businessDescription': businessDescription,
'businessCategory': businessCategory,
'productCategories': productCategories,
'coverPhoto': coverPhoto,
'avatarPhoto': avatarPhoto,
'representative': representative.toMap(),
'pickupAddress': address.toMap(),
};
}
}
class Address {
String building;
String street;
String location;
double lat;
double lng;
Address.data(this.building, this.street, this.location, this.lat, this.lng) {
this.building ??= '';
this.street ??= '';
this.location ??= '';
this.lat ??= 0.0;
this.lng ??= 0.0;
}
factory Address.from(address) => Address.data(address['building'],
address['street'], address['location'], address['lat'], address['lng']);
getFullAddress() {
return building + ', ' + street + '\n' + location;
}
Map<String, dynamic> toMap() {
return {
'building': building,
'street': street,
'location': location,
'lat': lat,
'lng': lng,
};
}
}
class Representative {
String representativeName;
String contactNumber;
String email;
Representative.data(this.representativeName, this.contactNumber, this.email) {
this.representativeName ??= '';
this.contactNumber ??= '';
this.email ??= '';
}
factory Representative.from(representative) => Representative.data(
representative['representativeName'],
representative['contactNumber'],
representative['email']);
Map<String, dynamic> toMap() {
return {
'representativeName': representativeName,
'contactNumber': contactNumber,
'email': email,
};
}
}
The code was built using this as the reference.
Comments
Post a Comment