i have an Json File as assets. parsing works perfect, but when i use the list from my json, an error is thrown. "the getter was called on null"
Here my JsonCode:
class Biersorten{
final List<Bier> biersorten;
Biersorten({
this.biersorten
});
factory Biersorten.fromJson(List<dynamic> parsedJson){
List<Bier> listBiersorten = new List<Bier>();
listBiersorten = parsedJson.map((i)=>Bier.fromJson(i)).toList();
return new Biersorten(
biersorten: listBiersorten,
);
}
}
class Bier{
int id;
String name;
String firmenname;
String alkoholgehalt;
Bier({this.id, this.name, this.firmenname, this.alkoholgehalt});
factory Bier.fromJson(Map<String, dynamic> parsedJson){
return Bier(
id: parsedJson["id"],
name : parsedJson["name"],
firmenname : parsedJson ["firmenname"],
alkoholgehalt: parsedJson["alkoholgehalt"]
);
}
}
Here my HomePageCode:
class MyHomePage extends StatelessWidget {
final String title;
Biersorten biersorten;
MyHomePage({this.title}){
loadBier();
}
Future<String> _loadBierAsset() async {
return await rootBundle.loadString("assets/JSON/Beer.json");
}
Future loadBier() async {
String jsonString = await _loadBierAsset();
final jsonResponse = json.decode(jsonString);
biersorten = new Biersorten.fromJson(jsonResponse);
print(biersorten.biersorten[0].alkoholgehalt);
}
Widget getCard(String title){
return Card(
child: Container(
height: 50,
child: Center(
child: Text(title),
),
)
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Column(
children: <Widget>[
ListView.builder(
itemCount: biersorten.biersorten.length,
itemBuilder: (context, i){
return getCard(biersorten.biersorten[i].name);
},
)
],
),
);
}
}
In the Function _loadBierAsset() i can use the List, but in the ListView.builder it throw an error.
How can i solve this problem?
Thanks for help:)
It is because your function is async and it doesn't return before the list is built. Till that time the list hasn't been initialized.First change your widget from Stateless to Stateful. Then Do this:
body: biersorten!=null ?
Column(
children: <Widget>[
ListView.builder(
itemCount: biersorten.biersorten.length,
itemBuilder: (context, i){
return getCard(biersorten.biersorten[i].name);
},
)
],
): Center(child: CircularProgressIndicator()),
And change your loadBier function to
Future loadBier() async {
String jsonString = await _loadBierAsset();
final jsonResponse = json.decode(jsonString);
setState((){
biersorten = new Biersorten.fromJson(jsonResponse);
});
print(biersorten.biersorten[0].alkoholgehalt);
}
And in your initState() add
loadBier();
Related
I am currently displaying my icons like this:
Widget _buildPopupDialog(BuildContext context) {
List<IconData> _iconsTable = [
Icons.feedback,
Icons.eco,
Icons.support,
Icons.call,
Icons.nature_people,
Icons.directions_bike,
];
return new AlertDialog(
content: SingleChildScrollView(
child: new Container(
child: GridView.count(
children: new List.generate(6, (int index) {
return new Positioned(
child: new DailyButton(iconData: _iconsTable[index]),
);
}),
),
),
),
However, I am wanting to get the icon data from cloud firestore. I am very new to using both flutter and firebase so I am very unsure how I would be able to do this. So far, I have tried this but iconData: Icons.iconsData obviously doesnt work:
class MyApp3 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage3(),
);
}
}
class MyHomePage3 extends StatefulWidget {
#override
_MyHomePageState3 createState() {
return _MyHomePageState3();
}
}
class _MyHomePageState3 extends State<MyHomePage3> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: _buildBody(context),
);
}
Widget _buildBody(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('icons').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return LinearProgressIndicator();
return _buildList(context, snapshot.data.docs);
},
);
}
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
return ListView(
children: snapshot.map((data) => _buildListItem(context, data)).toList(),
);
}
Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
final record3 = Record3.fromSnapshot(data);
var _iconsData = record3.name;
return Padding(
key: ValueKey(record3.name),
child: Container(
child: Card(
child: new MoodButton(
onTap: () => print("Mood"),
iconData: Icons.iconsData,
),
// trailing: Text(record3.votes.toString()),
// onTap: () => record3.reference.update({'votes': record3.votes+1})
),
),
);
}
}
class Record3 {
final String name;
final int votes;
final DocumentReference reference;
Record3.fromMap(Map<String, dynamic> map, {this.reference})
: assert(map['name'] != null),
assert(map['votes'] != null),
name = map['name'],
votes = map['votes'];
Record3.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data(), reference: snapshot.reference);
#override
String toString() => "Record<$name:$votes>";
}
Any help would be greatly appreciated!
If anyone is interested, I was able to figure it out:
Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
final record3 = Record3.fromSnapshot(data);
int iconCode = record3.votes;
return Padding(
key: ValueKey(record3.name),
child: Container(
child: new Container(
child: new ListView(
scrollDirection: Axis.horizontal,
children: new List.generate(1, (int index) {
return new Positioned(
child: new MoodButton(
onTap: () => print("Mood"),
iconData: (IconData(iconCode, fontFamily: 'MaterialIcons')),
),
);
})),
),
),
);
I'm trying to catch the error when my device has no internet connection. I've built out 2 future methods, 1 to import a json and 1 to look into the database. I have a future builder that's suppose to wait for both futures to finish before building out the grid view but it seems like the offlineFlashCardList is being prematurely called due to the connection error. Any idea how to make it wait for both futures to finish before the snapshot error gets called?
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:baby_sound/strings.dart';
import 'package:baby_sound/objects/flashCardList.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'dart:async' show Future;
import 'dart:convert';
import 'package:baby_sound/database/database.dart';
import 'package:baby_sound/objects/network.dart';
import 'package:http/http.dart' as http;
class GridViewWidget extends StatefulWidget{
#override
createState() => new GridViewState();
}
class GridViewState extends State<GridViewWidget>{
List<FlashCardList> flashCardList;
List<FlashCardList> offlineFlashCardList;
Future<List<FlashCardList>> fetchFlashCardList() async{
debugPrint("before response");
List<FlashCardList> tempFlashCardList;
final response = await http.get('some json url');
//checkConnection(url).then((response){
debugPrint ("after database load, response code: ${response.statusCode}");
if (response.statusCode == 200) {
var data = json.decode(response.body);
var flashCardListData = data["FlashCardList"] as List;
tempFlashCardList = flashCardListData.map<FlashCardList>((json) => FlashCardList.fromJson(json)).toList();
for (int i = 0; i < tempFlashCardList.length; i++){
debugPrint("DBProvider listID: ${await DBProvider.db.getFlashCardList(tempFlashCardList[i].flashCardListID)}, flashCardID: ${tempFlashCardList[i].flashCardListID}");
if (await DBProvider.db.getFlashCardList(tempFlashCardList[i].flashCardListID) == null){
DBProvider.db.newFlashCardList(tempFlashCardList[i]);
debugPrint("Adding ${tempFlashCardList[i].name}}}");
} else {
DBProvider.db.updateFlashCardList(tempFlashCardList[i]);
debugPrint("Updating ${tempFlashCardList[i].name}, getFlashCardList: ${DBProvider.db.getFlashCardList(tempFlashCardList[i].flashCardListID)}");
}
}
flashCardList = tempFlashCardList;
debugPrint("Standard flashCardList Size: ${flashCardList.length}");
}
debugPrint("flashCardList Size Before Return: ${flashCardList.length}");
return flashCardList;
}
Future<List<FlashCardList>> fetchFlashCardListFromDB() async{
offlineFlashCardList = await DBProvider.db.getAllFlashCardListFromDB();
debugPrint("fetchFromDB size: ${offlineFlashCardList.length}");
return offlineFlashCardList;
}
#override
void initState(){
debugPrint ('debug main.dart');
super.initState();
}
#override
Widget build(BuildContext context){
return new Scaffold(
appBar: new AppBar(
centerTitle: true,
title: new Text(Strings.pageTitle),
),
body: FutureBuilder<List<FlashCardList>>(
future: new Future(() async{
await fetchFlashCardList();
await fetchFlashCardListFromDB();
}),
builder: (BuildContext context, AsyncSnapshot<List<FlashCardList>> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
debugPrint("Snapshot has error: ${snapshot.error}");
return new GridView.builder(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
childAspectRatio: 0.5),
itemCount: offlineFlashCardList.length,
itemBuilder: (BuildContext context, int index) {
return _getGridItemUI(context, offlineFlashCardList[index]);
});
// return new Center(child: new CircularProgressIndicator());
} else {
debugPrint("Grid ViewBuilder");
return new GridView.builder(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
childAspectRatio:0.5),
itemCount: flashCardList.length,
itemBuilder: (BuildContext context, int index) {
return _getGridItemUI(context, flashCardList[index]);
});
}
}else {
debugPrint("CircularProgress");
return new Center(child: new CircularProgressIndicator());
}
})
);
}
_getGridItemUI(BuildContext context, FlashCardList item){
return new InkWell(
onTap: () {
_showSnackBar(context, item);
},
child: new Card(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Image(image: new CachedNetworkImageProvider("https://babymozart.org/babymozartq92C9TLa9UMkulL2m81xHdn9u2R92e1e/image/" + item.image)),
/*new Expanded(
child:new Center(
child: new Column(
children: <Widget>[
new SizedBox(height: 8.0),
new Expanded(
child: AutoSizeText(
item.name, maxLines: 1,
)
)
],
),
)
)*/
],
),
elevation: 2.0,
margin: EdgeInsets.all(5.0),
)
);
}
_showSnackBar(BuildContext context, FlashCardList item){
}
}
You can use Future.wait to wait for several Future to be completed.
body: FutureBuilder<List<FlashCardList>>(
future: Future.wait([
fetchFlashCardList(),
fetchFlashCardListFromDB(),
]),
Here's an example based on Alexandre's answer (As I found myself looking for how to handle results):
FutureBuilder(
future: Future.wait([
firstFuture(), // Future<bool> firstFuture() async {...}
secondFuture(),// Future<bool> secondFuture() async {...}
//... More futures
]),
builder: (
context,
// List of booleans(results of all futures above)
AsyncSnapshot<List<bool>> snapshot,
){
// Check hasData once for all futures.
if (!snapshot.hasData) {
return CircularProgressIndicator();
}
// Access first Future's data:
// snapshot.data[0]
// Access second Future's data:
// snapshot.data[1]
return Container();
}
);
So let's say I'm fetching different List from Different Url's
so The Future function will look like this
Future<List<City>> getCityDetails(Region selectedRegion) async {}
Future<List<Region>> getregionDetails() async {}
thus the Widget Builder will look like this
FutureBuilder<List<Region>>(
future: getregionDetails(),
builder: (context, snapshot) {}
is there a way or work around in this one? I'm trying to find an answer how to implement this one or is there another way?
i think you are looking for something like this
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(MaterialApp(
home: MyApp(),
));
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Widget createRegionsListView(BuildContext context, AsyncSnapshot snapshot) {
var values = snapshot.data;
return ListView.builder(
itemCount: values.length,
itemBuilder: (BuildContext context, int index) {
return values.isNotEmpty
? Column(
children: <Widget>[
ListTile(
title: Text(values[index].region),
),
Divider(
height: 2.0,
),
],
)
: CircularProgressIndicator();
},
);
}
Widget createCountriesListView(BuildContext context, AsyncSnapshot snapshot) {
var values = snapshot.data;
return ListView.builder(
itemCount: values == null ? 0 : values.length,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
setState(() {
selectedCountry = values[index].code;
});
print(values[index].code);
print(selectedCountry);
},
child: Column(
children: <Widget>[
new ListTile(
title: Text(values[index].name),
selected: values[index].code == selectedCountry,
),
Divider(
height: 2.0,
),
],
),
);
},
);
}
final String API_KEY = "03f6c3123ea549f334f2f67c61980983";
Future<List<Country>> getCountries() async {
final response = await http
.get('http://battuta.medunes.net/api/country/all/?key=$API_KEY');
if (response.statusCode == 200) {
var parsedCountryList = json.decode(response.body);
List<Country> countries = List<Country>();
parsedCountryList.forEach((country) {
countries.add(Country.fromJSON(country));
});
return countries;
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load ');
}
}
Future<List<Region>> getRegions(String sl) async {
final response = await http
.get('http://battuta.medunes.net/api/region/$sl/all/?key=$API_KEY');
if (response.statusCode == 200) {
var parsedCountryList = json.decode(response.body);
List<Region> regions = List<Region>();
parsedCountryList.forEach((region) {
regions.add(Region.fromJSON(region));
});
return regions;
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load ');
}
}
String selectedCountry = "AF";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Row(children: [
Expanded(
child: FutureBuilder(
future: getCountries(),
initialData: [],
builder: (context, snapshot) {
return createCountriesListView(context, snapshot);
}),
),
Expanded(
child: FutureBuilder(
future: getRegions(selectedCountry),
initialData: [],
builder: (context, snapshot) {
return createRegionsListView(context, snapshot);
}),
),
]),
);
}
}
class Country {
String name;
String code;
Country({this.name, this.code});
factory Country.fromJSON(Map<String, dynamic> json) {
return Country(
name: json['name'],
code: json['code'],
);
}
}
class Region {
String country;
String region;
Region({this.country, this.region});
factory Region.fromJSON(Map<String, dynamic> json) {
return Region(
region: json["region"],
country: json["country"],
);
}
}
I have a ListView and I want to navigate to the next page on the item click.
I need an index of the clicked item of my ListView.
I know this can be done using Controller. But I couldn't find any example.
When adding the onTap for your GestureRecognizer, (or button), your closure can capture the index passed through in the itemBuilder.
E.g.
body: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
child: Text(index.toString()),
onTap: () => Scaffold
.of(context)
.showSnackBar(SnackBar(content: Text(index.toString()))),
);
},
itemCount: 10));
This code will display a snack bar containing the index of the ListItem that you have tapped.
Once you have the index of the item, you can navigate to a new page using code provided by other answers to this question.
If you're using a ListView.builder, you can use a ListTile to add an onTap. This will make sure you have the material ripple effect.
ListView.builder(
itemBuilder: (_, i) {
return ListTile(
title: Text('$i'),
onTap: () {}, // Handle your onTap here.
);
},
)
There's an example in the Flutter documentation that's actually this very situation (navigation to next page on item click).
As others have said, use the onTap on the item in a ListView.builder. Just thought I'd post the link to the example in case someone else needed a more full explanation.
Send data to a new screen - flutter.io
...
final List<Todo> todos;
...
ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(todos[index].title),
onTap: () {
//Go to the next screen with Navigator.push
},
);
},
);
Another alternative is to use InkWell. InkWell includes a nice ripple effect on tap, which GestureDetector does not have.
https://api.flutter.dev/flutter/material/InkWell-class.html
Use like this:
return Scaffold(
appBar: AppBar(title: Text("Hello World")),
body: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return InkWell(
child: Text(index.toString()),
onTap: () => Scaffold.of(context)
.showSnackBar(SnackBar(content: Text(index.toString()))),
);
},
itemCount: 10)
);
You should use the onPressed method in the item(s) you have in your ListView (or add a GestureDetector) then use Navigator, similar to the snippet below where AboutScreen is the next page you want to go to.
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AboutScreen()),
);
}
With listview in you can useing GestureDetetor();
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return new GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RoomDetail()));
},
child: Container(child:(Text("This is content you want")));
ListViewpage.dart
class sta extends StatefulWidget {
const sta({Key? key}) : super(key: key);
#override
State<sta> createState() => _staState();
}
var isShow = false;
var getdata = Diohelper.getdata();
class _staState extends State<sta> {
#override
Widget build(BuildContext context) {
List mwidge = [];
int index = 0;
getdata.forEach((element) {
element.index = index;
mwidge.add(ListTile(
onTap: () {
// on click listner for move to another widget or activity (android native)
Navigator.push(context,
MaterialPageRoute(builder: (context) =>
// here element passing to the detail page element contain index other details
DetailPage(element)));
},
hoverColor: Colors.amber,
title: Text(element.name.toString()),
trailing: element.isShow
? SizedBox(
width: 100,
height: 50,
child: OutlinedButton(
onPressed: () {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text(element.name.toString())));
},
child: Text("Show")),
)
: Container(
width: 100,
),
));
index++;
});
return GestureDetector(
child: Center(
child: ListView(
children: [...mwidge],
),
),
);
}
}
DetailPage.dart
class DetailPage extends StatefulWidget {
productModel model;
DetailPage(this.model, {Key? key}) : super(key: key);
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
child: ListView(
children: [
Text("Name:" + widget.model.name.toString()),
Text("Category:" + widget.model.category.toString()),
Text("price:" + widget.model.price.toString())
],
),
));
}
}
FullCode:
import 'package:flutter/material.dart';
void main() =>
runApp(MaterialApp(home: Scaffold(appBar: AppBar(), body: sta())));
class sta extends StatefulWidget {
const sta({Key? key}) : super(key: key);
#override
State<sta> createState() => _staState();
}
var isShow = false;
var getdata = Diohelper.getdata();
class _staState extends State<sta> {
#override
Widget build(BuildContext context) {
List mwidge = [];
int index = 0;
getdata.forEach((element) {
element.index = index;
mwidge.add(ListTile(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => DetailPage(element)));
},
hoverColor: Colors.amber,
title: Text(element.name.toString()),
trailing: element.isShow
? SizedBox(
width: 100,
height: 50,
child: OutlinedButton(
onPressed: () {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text(element.name.toString())));
},
child: Text("Show")),
)
: Container(
width: 100,
),
));
index++;
});
return GestureDetector(
child: Center(
child: ListView(
children: [...mwidge],
),
),
);
}
}
class DetailPage extends StatefulWidget {
productModel model;
DetailPage(this.model, {Key? key}) : super(key: key);
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
child: ListView(
children: [
Text("Name:" + widget.model.name.toString()),
Text("Category:" + widget.model.category.toString()),
Text("price:" + widget.model.price.toString())
],
),
));
}
}
class productModel {
String? name;
String? price;
String? category;
bool isShow = false;
int index = 0;
productModel({this.name, this.price, this.category, this.isShow = false});
productModel.fromJson(Map<String, dynamic> json) {
name = json['name'];
price = json['price'];
category = json['category'];
isShow = json['isShow'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['price'] = this.price;
data['category'] = this.category;
data['isShow'] = this.isShow;
return data;
}
}
class Diohelper {
static List<productModel> getdata() {
List<productModel> list = [];
list.add(productModel(name: "broast", price: "100", category: "chicken"));
list.add(productModel(name: "mandi", price: "100", category: "chicken"));
list.add(productModel(name: "mandi", price: "100", category: "veg"));
return list;
}
}
Dartpad or Live Code
I am trying to pass data from one screen to another, but I keep getting a null exception. Whenever I fill in the form on the first screen and proceed to next screen, I get a `
NoSuchMethodError: The getter 'storeNumber' was called on null
`
My variables class is ==> This entity class has variables that I populate using a form in the following class:
class StoreData {
String _storeNumber;
String _repName;
String _repCell;
DateTime _transactionDate = new DateTime.now();
StoreData(
this._storeNumber, this._repName, this._repCell, this._transactionDate);
String get storeNumber => _storeNumber;
set storeNumber(String value) {
_storeNumber = value;
}
String get repName => _repName;
DateTime get transactionDate => _transactionDate;
set transactionDate(DateTime value) {
_transactionDate = value;
}
String get repCell => _repCell;
set repCell(String value) {
_repCell = value;
}
set repName(String value) {
_repName = value;
}
}
The main class (in this case this is the first screen that sends data to second screen) includes the following code:
This class has a form that takes in 3 inputs and send them to second screen.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'FeedBack.dart';
import 'StoreData.dart';
void main() {
runApp(MaterialApp(
title: 'Navigation Basics',
home: FirstScreen(),
));
}
//get our entity class
StoreData storeDate;
// get variables from entity class
String storeNumber = storeDate.storeNumber;
String repName = storeDate.repName;
String repCell = storeDate.repCell;
DateTime transactionDate = storeDate.transactionDate;
class FirstScreen extends StatefulWidget {
#override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
GlobalKey<FormState> _key = GlobalKey();
bool _validate = false;
_sendData() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FeedBack(
storeData: new StoreData(
storeNumber, repName, repCell, transactionDate))),
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('Test App'),
),
body: new SingleChildScrollView(
child: new Container(
margin: new EdgeInsets.all(15.0),
child: new Form(
key: _key,
autovalidate: _validate,
child: formUI(),
),
),
),
),
);
}
Widget formUI() {
return new Column(
children: <Widget>[
new TextFormField(
decoration: new InputDecoration(hintText: 'Store Number'),
keyboardType: TextInputType.number,
validator: validateRepCell,
onSaved: (String val) {
storeNumber = val;
}),
new TextFormField(
decoration: new InputDecoration(hintText: 'Rep Full Name'),
validator: validateRepName,
onSaved: (String val) {
repName = val;
}),
new TextFormField(
decoration: new InputDecoration(hintText: 'Rep Phone Number'),
keyboardType: TextInputType.number,
validator: validateRepCell,
onSaved: (String val) {
repCell = val;
}),
new SizedBox(height: 15.0),
new RaisedButton(
onPressed: _sendData,
child: new Text('Proceed'),
)
],
);
}
// Validate Fields
String validateRepCell(String value) {
// String patttern = r'(^[a-zA-Z ]*$)';
RegExp regExp = new RegExp(r'^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$');
if (value.length == 0) {
return "Store Number is Required";
} else if (!regExp.hasMatch(value)) {
return "Store Number must be only have numbers";
}
return null;
}
String validateRepName(String value) {
String patttern = r'(^[a-zA-Z ]*$)';
RegExp regExp = new RegExp(patttern);
if (value.length == 0) {
return "Rep Name is Required";
} else if (!regExp.hasMatch(value)) {
return "Name must be a-z and A-Z";
}
return null;
}
}
The second screen's code is here:
class FeedBack extends StatelessWidget {
final StoreData storeData;
FeedBack({Key key, #required this.storeData}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("FeedBack Screen"),
),
body: new Container(
child: new Column(
children: <Widget>[
new RaisedButton(
onPressed: _sendToDatabase,
child: new Text('Press Me'),
),
new Text("${storeData.storeNumber}"),
],
),
),
);
}
_sendToDatabase() {
Firestore.instance.runTransaction((Transaction transaction) async {
CollectionReference reference = Firestore.instance.collection('Stores');
await reference.add({"test": "test", "testII": "test"});
});
}
}
I have been trying to solve this problem for a week now, but given my new experience with Dart and Flutter framework, it has been tough !
Any help would be appreciated,
You can use the following approach.
Remove the following lines from your code:
//get our entity class
StoreData storeDate;
As initially there will be no instance of StoreData available right now.
Now, declare new variables like the following:
String storeNumber;
String repName;
String repCell;
DateTime transactionDate;
And then assign the form values to them in onSaved method.
So when your form will be submitted, these values will be used for creating new StoreData and it will be passed to the Second page.
Here is the code for your main.dart file:
import 'package:flutter/material.dart';
import 'FeedBack.dart';
import 'StoreData.dart';
void main() {
runApp(MaterialApp(
title: 'Navigation Basics',
home: FirstScreen(),
));
}
// get variables from entity class
String storeNumber;
String repName;
String repCell;
DateTime transactionDate = DateTime.now();
class FirstScreen extends StatefulWidget {
#override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
GlobalKey<FormState> _key = GlobalKey();
bool _validate = false;
_sendData() {
_key.currentState.save();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FeedBack(
storeData: StoreData(
storeNumber, repName, repCell, transactionDate))),
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('Test App'),
),
body: new SingleChildScrollView(
child: new Container(
margin: new EdgeInsets.all(15.0),
child: new Form(
key: _key,
autovalidate: _validate,
child: formUI(),
),
),
),
),
);
}
Widget formUI() {
return new Column(
children: <Widget>[
new TextFormField(
decoration: new InputDecoration(hintText: 'Store Number'),
keyboardType: TextInputType.number,
validator: validateRepCell,
onSaved: (String val) {
storeNumber = val;
}),
new TextFormField(
decoration: new InputDecoration(hintText: 'Rep Full Name'),
validator: validateRepName,
onSaved: (String val) {
repName = val;
}),
new TextFormField(
decoration: new InputDecoration(hintText: 'Rep Phone Number'),
keyboardType: TextInputType.number,
validator: validateRepCell,
onSaved: (String val) {
repCell = val;
}),
new SizedBox(height: 15.0),
new RaisedButton(
onPressed: _sendData,
child: new Text('Proceed'),
)
],
);
}
// Validate Fields
String validateRepCell(String value) {
// String patttern = r'(^[a-zA-Z ]*$)';
RegExp regExp = new RegExp(r'^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$');
if (value.length == 0) {
return "Store Number is Required";
} else if (!regExp.hasMatch(value)) {
return "Store Number must be only have numbers";
}
return null;
}
String validateRepName(String value) {
String patttern = r'(^[a-zA-Z ]*$)';
RegExp regExp = new RegExp(patttern);
if (value.length == 0) {
return "Rep Name is Required";
} else if (!regExp.hasMatch(value)) {
return "Name must be a-z and A-Z";
}
return null;
}
}