how to get data in material datatable in flutter from rest api - flutter

I want to show data in material dataTable but instead of getting data in a row it makes the table head every time with the row
My design which I Want:
The design I am getting right now:
Here is the full code of my flutter application:
UI SCREEN
________________This is Ui part of my application_
import 'package:aiims/bloc/add_relatives_bloc.dart';
import 'package:aiims/models/relative.dart';
import 'package:aiims/service/api.dart';
import 'package:aiims/widgets/side_menu_widget.dart';
import 'package:flutter/material.dart';
import 'package:outline_material_icons/outline_material_icons.dart';
import 'package:provider/provider.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
class RelativeScreen extends StatefulWidget {
#override
_RelativeScreenState createState() => _RelativeScreenState();
}
class _RelativeScreenState extends State<RelativeScreen> {
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
DataRow getDataRow(data) {
return DataRow(
cells: <DataCell>[
DataCell(Text(data["name"])),
DataCell(Text(data["age"])),
DataCell(Text(data["relation"])),
DataCell(
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(Icons.edit_outlined),
Icon(Icons.delete_outline_sharp),
],
),
),
],
);
}
#override
void initState() {
// TODO: implement initState
super.initState();
// _getDataRow(list.length);
}
// _getRelatives() {
// getRelativesList().then((Relative) {
// setState(() {
//
// });
// print("Length: ${_relative.length}");
// });
// }
// DataRow _getDataRow(list) {
// return DataRow(
// cells: <DataCell>[
// DataCell(Text(list["name"])),
// DataCell(Text(list["age"])),
// DataCell(Text(list["relation"])),
// ],
// );
// }
#override
Widget build(BuildContext context) {
final bloc = Provider.of<AddNewRelativeBloc>(context, listen: false);
return Scaffold(
drawer: NavDrawer(),
appBar: AppBar(
title: Text('Relatives'),
actions: <Widget>[
GestureDetector(
onTap: () => _add_relavitves(),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Icon(Icons.add_circle_outline_rounded),
),
),
],
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Container(
// alignment: Alignment.center,
padding: EdgeInsets.symmetric(vertical: 20),
child: SingleChildScrollView(
child: Container(
child: FutureBuilder(
future: getRelativesList(),
// initialData: new TreatmentDetail(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString()),
);
} else if (snapshot.connectionState ==
ConnectionState.done) {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: list.length,
itemBuilder: (context, index) {
return DataTable(
headingRowColor: MaterialStateColor
.resolveWith(
(states) => Color(0xffff69b4)),
// MaterialStateColor.resolveWith((states) => Colors.pink),
columns: [
DataColumn(label: Text("Name")),
DataColumn(label: Text("Age")),
DataColumn(label: Text("Relation")),
DataColumn(label: Text("Action")),
],
// rows: List.generate(
// list.length, (index) =>
// _getDataRow(list[index]),
// ));
rows: [
DataRow(
cells: [
DataCell(Text(list[index]["name"])),
DataCell(Text(list[index]["age"])),
DataCell(Text(list[index]["relation"])),
DataCell(
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Icon(Icons.edit_outlined),
Icon(Icons.delete_outline_sharp),
],
),
),
],
),
// DataRow(cells: [
// DataCell(Text('Ajay Singh')),
// DataCell(Text('25')),
// DataCell(Text('Son')),
// DataCell(
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Icon(Icons.edit_outlined),
// Icon(Icons.delete_outline_sharp),
// ],
// ),
// ),
// ]),
],
);
});
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}),
),
),
),
),
),
);
}
void _add_relavitves() {
final bloc = Provider.of<AddNewRelativeBloc>(context, listen: false);
// set up the buttons
// Widget cancelButton = FlatButton(
// child: Text("Cancel"),
// onPressed: () {
// Navigator.pop(context);
// },
// );
Widget cancelButton = MaterialButton(
child: Container(
height: 40,
width: 110,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Color(0xffff69b4),
),
child: Text(
"Discard",
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
),
),
onPressed: () {
Navigator.pop(context);
},
);
Widget continueButton = FlatButton(
child: Text("Continue"),
onPressed: () {},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Center(
child: Text(
"Add New Relative",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
content: SingleChildScrollView(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(height: 20),
StreamBuilder<Object>(
stream: bloc.name,
builder: (context, snapshot) {
return TextField(
keyboardType: TextInputType.text,
decoration: InputDecoration(
hintText: "Name",
labelText: "Name",
errorText: snapshot.error,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
// onChanged: (value) => bloc.changeName,
onChanged: bloc.changeName,
);
}),
SizedBox(height: 20),
StreamBuilder<Object>(
stream: bloc.age,
builder: (context, snapshot) {
return TextField(
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: "Age",
labelText: "Age",
errorText: snapshot.error,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
// onChanged: (value) => bloc.changeName,
onChanged: bloc.changeAge,
);
}),
SizedBox(height: 20),
StreamBuilder<Object>(
stream: bloc.relation,
builder: (context, snapshot) {
return TextField(
keyboardType: TextInputType.text,
decoration: InputDecoration(
hintText: "Relation",
labelText: "Relation",
errorText: snapshot.error,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
// onChanged: (value) => bloc.changeName,
onChanged: bloc.changeRelation,
);
}),
SizedBox(height: 20),
StreamBuilder<Object>(
stream: bloc.phoneNumber,
builder: (context, snapshot) {
return TextField(
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: "Phone Number",
labelText: "Phone Number",
errorText: snapshot.error,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
// onChanged: (value) => bloc.changeName,
onChanged: bloc.changePhoneNumber,
);
}),
],
),
),
),
actions: [
cancelButton,
_saveButton(),
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Widget _saveButton() {
final bloc = Provider.of<AddNewRelativeBloc>(context, listen: false);
return StreamBuilder<Object>(
stream: bloc.isValid,
builder: (context, snapshot) {
return GestureDetector(
onTap: snapshot.hasError || !snapshot.hasData
? null
: () {
bloc.submit();
},
child: Container(
height: 40,
width: 130,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: snapshot.hasError || !snapshot.hasData
? Color(0xffff69b4)
: Colors.green,
),
child: Text(
"Save",
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
),
),
);
});
}
}
//My Future for getting response from api
Future<List> getRelativesList() async {
final response =
await http.get("$baseUrl");
Map<String, dynamic> map = json.decode(response.body);
List<dynamic> data = map["data"];
print("first id on console" + data[0]["id"].toString());
return list = data;
}
//Here is my model
class Relative {
int _code;
String _message;
List<Data> _data;
Relative({int code, String message, List<Data> data}) {
this._code = code;
this._message = message;
this._data = data;
}
int get code => _code;
set code(int code) => _code = code;
String get message => _message;
set message(String message) => _message = message;
List<Data> get data => _data;
set data(List<Data> data) => _data = data;
Relative.fromJson(Map<String, dynamic> json) {
_code = json['code'];
_message = json['message'];
if (json['data'] != null) {
_data = new List<Data>();
json['data'].forEach((v) {
_data.add(new Data.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['code'] = this._code;
data['message'] = this._message;
if (this._data != null) {
data['data'] = this._data.map((v) => v.toJson()).toList();
}
return data;
}
}
class Data {
int _id;
int _patientId;
String _name;
String _age;
String _relation;
String _phoneNo;
Data(
{int id,
int patientId,
String name,
String age,
String relation,
String phoneNo}) {
this._id = id;
this._patientId = patientId;
this._name = name;
this._age = age;
this._relation = relation;
this._phoneNo = phoneNo;
}
enter code here
int get id => _id;
set id(int id) => _id = id;
int get patientId => _patientId;
set patientId(int patientId) => _patientId = patientId;
String get name => _name;
set name(String name) => _name = name;
String get age => _age;
set age(String age) => _age = age;
String get relation => _relation;
set relation(String relation) => _relation = relation;
String get phoneNo => _phoneNo;
set phoneNo(String phoneNo) => _phoneNo = phoneNo;
Data.fromJson(Map<String, dynamic> json) {
_id = json['id'];
_patientId = json['patient_id'];
_name = json['name'];
_age = json['age'];
_relation = json['relation'];
_phoneNo = json['phone_no'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this._id;
data['patient_id'] = this._patientId;
data['name'] = this._name;
data['age'] = this._age;
data['relation'] = this._relation;
data['phone_no'] = this._phone`enter code here`No;
return data;
}
}

You return DataTable as an item for ListView.builder, that is why you see header and row. If you want display only table then remove ListView widget and return DataTable with rows. Something like
FutureBuilder(
builder: (context, snapshot) {
return DataTable(
columns: <DataColumn>[
...
],
rows: list.map((item) {
return DataRow(
cells: <DataCell>[...]
);
}),
),
}
)

Related

Error: NoSuchMethodError: 'then' Dynamic call of null. Receiver: null

Does anyone know the cause of this error? I have tried many ways but still don't know where the problem is.
Database.dart
import 'package:fitness_app/Login/login_data.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
class DatabaseService {
static final DatabaseService _databaseService = DatabaseService._internal();
factory DatabaseService() => _databaseService;
DatabaseService._internal();
static Database? _database;
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
Future<Database> _initDatabase() async {
final databasePath = await getDatabasesPath();
final path = join(databasePath, 'conference.database');
return await openDatabase(
path,
onCreate: _onCreate,
version: 1,
onConfigure: (db) async => await db.execute('PRAGMA foreign_keys = ON'),
);
}
Future<void> _onCreate(Database db, int version) async {
await db.execute(
'CREATE TABLE login(id INTEGER PRIMARY KEY, name TEXT, username TEXT, password TEXT)',
);
}
verifyuser(String user, String pass) {}
insertLoginData(Logindata logindata) {}
}
Login.dart
import 'package:fitness_app/Login/signup.dart';
import 'package:flutter/material.dart';
import 'login_data.dart';
import 'package:fitness_app/Database/database.dart';
import 'package:fitness_app/home_page.dart';
class Login extends StatefulWidget {
const Login({Key? key, this.login}) : super(key: key);
final Logindata? login;
#override
_LoginState createState() => _LoginState();
}
class _LoginState extends State<Login> {
String email = "a";
String pass = "a";
TextEditingController emails = TextEditingController();
TextEditingController password = TextEditingController();
final _formKey = GlobalKey<FormState>();
static final List<Logindata> _login = [];
final DatabaseService _databaseService = DatabaseService();
Future<List<Logindata>> _getLogin() async {
await _databaseService.verifyuser(email, pass).then((value) {
if (value) {
AlertDialog alert = AlertDialog(
title: const Text('Login successful!'),
content: const Text('Welcome!'),
actions: <Widget>[
TextButton(
onPressed: () => (Navigator.push(
context,
MaterialPageRoute(builder: (context) => const HomePage()),
)),
child: const Text('OK'),
),
],
);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
} else {
AlertDialog alert = AlertDialog(
title: const Text('Error!'),
content: const Text('Wrong Email or Password'),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, 'OK'),
child: const Text('OK'),
),
],
);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
});
return _login;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: SingleChildScrollView(
child: Column(
children: [
Container(
padding: EdgeInsets.all(10),
child: Form(
key: _formKey,
child: Column(
children: [
Text(
'BeFit:Fitness Activity Tracker Progress\n\n',
style: TextStyle(fontSize: 24),
textAlign: TextAlign.start,
),
Text(
'Welcome',
style: TextStyle(fontSize: 40),
textAlign: TextAlign.center,
),
SizedBox(
height: 30,
),
Container(
child: TextFormField(
controller: emails,
decoration: InputDecoration(
border: UnderlineInputBorder(
borderSide:
BorderSide(width: 1, color: Colors.grey)),
labelText: 'Email'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Email is required';
}
return null;
},
),
),
SizedBox(
height: 20,
),
Container(
child: TextFormField(
controller: password,
obscureText: true,
decoration: InputDecoration(
border: UnderlineInputBorder(
borderSide:
BorderSide(width: 1, color: Colors.grey)),
labelText: 'Password'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Password is required';
}
return null;
},
),
),
SizedBox(
height: 20,
),
Container(
width: MediaQuery.of(context).size.width,
height: 50,
child: FlatButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
email = emails.text;
pass = password.text;
_getLogin();
print(email);
print(pass);
print('success');
}
},
child: Text("Login"),
textColor: Colors.white,
color: Colors.deepPurple[400],
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(10)),
),
),
SizedBox(
height: 20,
),
Container(
child: Row(
children: <Widget>[
Text('Does not have account?'),
FlatButton(
textColor: Colors.deepPurpleAccent[100],
child: Text(
'Sign up',
style: TextStyle(fontSize: 16),
),
onPressed: () {
//signup screen
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SignUp()),
);
},
)
],
mainAxisAlignment: MainAxisAlignment.center,
))
],
),
),
)
],
),
),
),
);
}
}
Here is the error
enter image description here
I'm using this flutter to complete my project but there are some errors that I can't solve it. Sorry if my coding looks not right because still lacks in coding
Your verifyuser function does not return anything so your value returns null. You either need to return something or check for null values in your then statement.
Future<String> verifyuser(String user, String pass)async {
return user + pass;
}

How to pass variable and get data from API in flutter?

This the first UI in there when user enter channel name and after click join then should it pass "loadData" method in there that channel name should pass to "API" and get channelname and appId from that url.
join button code
Future<void> onJoin() async {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => loadData(myController.text)),
);
}
loadData method
import 'dart:convert';
import 'package:http/http.dart';
import '../model/appIdModel.dart';
class ApiService {
loadData(String myController) async {
final String url ='https://jsonplaceholder.typicode.com/posts/1=$myController';
Future<List<Data>> getData() async {
Response response = await get(Uri.parse(url));
if (response.statusCode == 2000) {
Map<String, dynamic> json = jsonDecode(response.body);
List<dynamic> body = json['data'];
List<Data> datas = body.map((dynamic item) => Data.fromJson(item).toList();
return datas;
} else {
throw ('cannot fetch data');
}
}
}
}
Data model code
class Data {
String appId;
String channelName;
Data({
required this.appId,
required this.channelName,
});
factory Data.fromJson(Map<String, dynamic> json) {
return Data(
appId: json['appId'] == null ? null : json['appId'],
channelName: json['channelName'] == null ? null : json['channelName']);
}
}
then appId and channelName should fetch
FutureBuilder widget code show channelId and channelName (Home page code)
class _MyHomePageState extends State<MyHomePage> {
final myController = TextEditingController();
bool _validateError = false;
ApiService client = ApiService();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: SingleChildScrollView(
clipBehavior: Clip.antiAliasWithSaveLayer,
physics: BouncingScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(padding: EdgeInsets.only(top: 20)),
Padding(padding: EdgeInsets.symmetric(vertical: 20)),
Container(
width: MediaQuery.of(context).size.width * 0.8,
child: TextFormField(
controller: myController,
decoration: InputDecoration(
labelText: 'Channel Name',
labelStyle: TextStyle(color: Colors.blue),
hintText: 'test',
hintStyle: TextStyle(color: Colors.black45),
errorText:
_validateError ? 'Channel name is mandatory' : null,
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue),
borderRadius: BorderRadius.circular(20),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue),
borderRadius: BorderRadius.circular(20),
),
disabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue),
borderRadius: BorderRadius.circular(20),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.blue),
borderRadius: BorderRadius.circular(20),
),
),
),
),
Padding(padding: EdgeInsets.symmetric(vertical: 30)),
Container(
width: MediaQuery.of(context).size.width * 0.25,
child: MaterialButton(
onPressed: onJoin,
height: 40,
color: Colors.blueAccent,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Text(
'Join',
style: TextStyle(color: Colors.white),
),
Icon(
Icons.arrow_forward,
color: Colors.white,
),
],
),
),
),
Center(
child: FutureBuilder(
future: client.getData(),
builder: (BuildContext context,
AsyncSnapshot<List<Data>> snapshot) {
if (snapshot.hasData) {
List<Data>? data = snapshot.data;
return ListView.builder(
itemBuilder: (context, index) => Column(
children: [
Text(
data![index].channelName.toString(),
),
Text(
data[index].appId.toString(),
),
],
));
}
return const Center(
child: CircularProgressIndicator(),
);
}),
)
],
),
),
),
),
);
}
Future<void> onJoin() async {
setState(() {
myController.text.isEmpty
? _validateError = true
: _validateError = false;
});
// await _handleCameraAndMic(Permission.camera);
// await _handleCameraAndMic(Permission.microphone);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => loadData(myController.text)),
);
}
this is the my code to fetch data.when I run the url with channel name then data show nicely.
I tired to fetch "channelName" and "appId" using this url.
You are doing wrong when you call onJoin, change it to this:
Future<void> onJoin() async {
future = client.getData(myController.text);
}
then define new variable like this:
Future<List<Data>>? future;
then change ApiService to this:
class ApiService {
final String url =
'https://jsonplaceholder.typicode.com/posts/1';
Future<List<Data>> getData(String myController) async {
Response response = await get(Uri.parse(url + myController));
if (response.statusCode == 200) { // <--- change this
Map<String, dynamic> json = jsonDecode(response.body);
List<dynamic> body = json['data'];
List<Data> datas = body.map((dynamic item) => Data.fromJson(item).toList();
return datas;
} else {
throw ('cannot fetch data');
}
}
}
then change your FutureBuilder to this
future != null ? FutureBuilder(//<--- add this
future: future,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return const Center(
child: CircularProgressIndicator(),
);
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
future = null; //<--- add this
List<Data> data = snapshot.data ?? []; //<-- change this
return ListView.builder(
itemCount: data.length, //<-- add this
itemBuilder: (context, index) => Column(
children: [
Text(
data[index].channelName.toString(),
),
Text(
data[index].appId.toString(),
),
],
));
}
}
},
)
: SizedBox(),//<--- add this
also as you can see in your postman result the data contain a map, not list of map, so if you expect a list you need to contact to your backend but if not you can parse it like this:
Map<String, dynamic> body = json['data'];
List<Data> datas = [Data.fromJson(body)];
also for ui issue you can't use listview inside SingleChildScrollView, for that you need set shrinkWrap to true, also set its physics to NeverScrollableScrollPhysics too:
return ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: ...
)

flutter firestore - How to retrieve the new document id after adding to firestore

I want to retrieve the new created document id and display the document data in a new page. How can i get the document id? When onPressed() the elevated button, I want to retrieve the document data based on its id.
How can I bring the document id from addDiagnose(_type, _symptomsResult) so that I can navigate it to another page.
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DiagnosisPage(documentId: documentId),
)
);
This is my current code.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:multiselect_formfield/multiselect_formfield.dart';
import 'package:petbuddies/user/diagnosis/diagnose_history.dart';
import 'package:petbuddies/user/diagnosis/diagnosis.dart';
class CheckerPage extends StatefulWidget {
const CheckerPage({Key? key}) : super(key: key);
#override
_CheckerPageState createState() => _CheckerPageState();
}
class _CheckerPageState extends State<CheckerPage> {
//retrieve options
final _formKey = GlobalKey<FormState>();
void _petTypeDropDownItemSelected(String newValueSelected) {
setState(() {
petType = newValueSelected;
});
}
clearText(){
_symptoms?.clear();
}
#override
void initState(){
super.initState();
_symptoms = [];
_symptomsResult = [];
}
List? _symptoms;
late List<dynamic> _symptomsResult;
var petType;
var _type;
final Stream<QuerySnapshot> petTypeStream = FirebaseFirestore.instance.collection('pet type').orderBy('name').snapshots();
final Stream<QuerySnapshot> symptomsStream = FirebaseFirestore.instance.collection('symptoms').orderBy('name').snapshots();
DocumentReference diagnosis = FirebaseFirestore.instance.collection('diagnosis').doc();
//store the diagnosis result
User? user = FirebaseAuth.instance.currentUser;
Future<void> addDiagnose(_type, _symptomsResult) async {
String petChosen = this._type;
List symptomsChosen = this._symptomsResult.toList();
QuerySnapshot<Map<String, dynamic>> snapshot =
await FirebaseFirestore.instance.collection("disease")
.where('petType',isEqualTo: petChosen)
.where('symptoms',arrayContainsAny: symptomsChosen)
.get();
List<String> diseaseRef = snapshot.docs.map((e) => e.id).toList();
String createdby = user!.uid;
Timestamp date = Timestamp.now();
List possibleDisease = diseaseRef.toList();
final data = {
'created by': createdby,
'date': date,
'pet chosen': petChosen,
'symptoms chosen': symptomsChosen,
'possible disease': possibleDisease,
};
//set document data
return diagnosis
.set(data)
.then((value) => print('Diagnose Report Added'))
.catchError((error)=>print("Failed to add: $error")
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue[900],
title: const Text("Pet Symptoms Checker",
style: TextStyle(color: Colors.white),
),
),
body: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 30),
child: ListView(
children: [
Align(
alignment: Alignment.bottomRight,
child: TextButton(
child: const Text(
'History',
style: TextStyle(fontSize: 18),
),
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => const DiagnoseHistoryPage(),));
},
),
),
Container(
padding: const EdgeInsets.all(12.0),
decoration: BoxDecoration(
border: Border.all(width: 3, color: Colors.indigo,),
borderRadius: const BorderRadius.all(Radius.circular(30)),
),
child: Column(
children: [
StreamBuilder<QuerySnapshot>(
stream: petTypeStream,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Container(
padding: const EdgeInsets.only(bottom: 16.0),
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
padding: const EdgeInsets.fromLTRB(12.0, 10.0, 10.0, 10.0),
child: const Text(
"Pet Type",
style: TextStyle(fontSize: 20),
),
),
),
Expanded(
flex: 3,
child: Row(
children: [
const SizedBox(width: 30,),
DropdownButton(
value: petType,
onChanged: (valueSelectedByUser) {
_petTypeDropDownItemSelected(valueSelectedByUser.toString());
},
hint: const Text('Choose Pet Type',),
underline: Container(),
items: snapshot.data!.docs.map((DocumentSnapshot document) {
return DropdownMenuItem<String>(
value: document.get('name'),
child: Text(document.get('name')),
);
}).toList(),
),
],
),
),
],
),
);
}),
StreamBuilder(
stream: symptomsStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if(snapshot.hasError){
print('Something went wrong');
}
if(snapshot.connectionState == ConnectionState.waiting){
return const Center(
child: CircularProgressIndicator(),
);
}
final List symptomsList = [];
snapshot.data!.docs.map((DocumentSnapshot document){
Map a = document.data() as Map<String, dynamic>;
symptomsList.add(a['name']);
a['id'] = document.id;
}).toList();
return MultiSelectFormField(
autovalidate: AutovalidateMode.disabled,
chipBackGroundColor: Colors.blue[900],
chipLabelStyle: const TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
dialogTextStyle: const TextStyle(fontWeight: FontWeight.bold),
checkBoxActiveColor: Colors.blue[900],
checkBoxCheckColor: Colors.white,
dialogShapeBorder: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0))),
title: const Text(
"Symptoms",
style: TextStyle(fontSize:20),
),
validator: (value) {
if (value == null || value.length == 0) {
return 'Please select one or more symptoms';
}
return null;
},
dataSource: [
for (String i in symptomsList) {'value' : i}
],
textField: 'value',
valueField: 'value',
okButtonLabel: 'OK',
cancelButtonLabel: 'CANCEL',
hintWidget: const Text('Please choose one or more symptoms'),
initialValue: _symptoms,
onSaved: (value) {
if (value == null) return;
setState(() {
_symptoms = value;
}
);
},
);
}
),
const SizedBox(height:50,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
onPressed: () async{
if(_formKey.currentState!.validate()){
setState(() {
_type = petType.toString();
_symptomsResult = _symptoms!.toList();
addDiagnose(_type,_symptomsResult);
final documentId = diagnosis.id;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DiagnosisPage(documentId: documentId),
)
);
clearText();
}
);
}
},
child: const Text(
'Diagnose',
style: TextStyle(fontSize: 18),
),
style: ElevatedButton.styleFrom(primary: Colors.blue[900]),
),
],
),
],
),
)
],
),
),
),
);
}
}

flutter riverpod leaving screen then come back it doesn't maintain the state

So I have two screens:
-Book_screen to display all the books(click on any book to go to article_screen)
-article_screen to display articles
In article_screen, I can click on article to save it as favorites.
but when I go back to book_screen then come back to article_screen, those favorited articles doesn't show the favorited status(icon red heart).
this is my article screen code:
class ArticleENPage extends ConsumerStatefulWidget{
final String bookName;
const ArticleENPage({Key? key,#PathParam() required this.bookName,}) : super(key: key);
#override
ArticleENScreen createState()=> ArticleENScreen();
}
class ArticleENScreen extends ConsumerState<ArticleENPage> {
late Future<List<Code>> codes;
#override
void initState() {
super.initState();
codes = fetchCodes();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.bookName,style: const TextStyle(fontSize: 24,fontWeight: FontWeight.bold),),backgroundColor: Colors.white,foregroundColor: Colors.black,elevation: 0,),
body: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0),
child: Container(
margin: const EdgeInsets.only(top:10),
height: 43,
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 2),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
border: Border.all(
color: Colors.black.withOpacity(0.32),
),
),
child: Consumer(
builder: (context,ref,_) {
return TextField(
onChanged: (value) {
searchStringController controller = ref.read(searchStringProvider.notifier);
controller.setText(value.toLowerCase());
},
decoration: const InputDecoration(
border: InputBorder.none,
icon: Icon(Icons.search,size:18),
hintText: "Search Here",
hintStyle: TextStyle(color: Color.fromRGBO(128,128, 128, 1)),
),
);
}
),
),
),
const SizedBox(height: 10),
Expanded(
child: FutureBuilder(
builder: (context, AsyncSnapshot<List<Code>> snapshot) {
if (snapshot.hasData) {
return Center(
child: Consumer(
builder: (context,ref,child) {
final searchString = ref.watch(searchStringProvider);
return ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: snapshot.data!.length,
itemBuilder: (BuildContext context, int index) {
return snapshot.data![index].name
.toLowerCase()
.contains(searchString) ||
snapshot.data![index].description
.toLowerCase()
.contains(searchString)
? Consumer(
builder: (context,ref,child) {
final favlist = ref.watch(FavoriteListController.favoriteListProvider);
print(favlist);
final alreadySaved = favlist.contains(snapshot.data![index]);
return Card(
child:Padding(
padding: const EdgeInsets.all(10),
child:ExpandableNotifier(
child: ScrollOnExpand(
child: ExpandablePanel(
theme: const ExpandableThemeData(hasIcon: true),
header: RichText(text: TextSpan(children: highlight(snapshot.data![index].name, searchString,'title')),),
collapsed: RichText(text: TextSpan(children: highlight(snapshot.data![index].description, searchString,'content')), softWrap: true, maxLines: 3, overflow: TextOverflow.ellipsis,),
expanded: Column(
children: [
RichText(text: TextSpan(children: highlight(snapshot.data![index].description, searchString,'content')), softWrap: true ),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
IconButton(
icon: Icon(
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
semanticLabel: alreadySaved ? 'Remove from saved' : 'Save',
),
onPressed: () {
FavoriteListController controller = ref.read(FavoriteListController.favoriteListProvider.notifier);
if (alreadySaved) {
controller.toggle(snapshot.data![index]);
} else {
controller.toggle(snapshot.data![index]);
}
},
),
IconButton(
icon: const Icon(Icons.content_copy),
onPressed: () {
setState(() {
Clipboard.setData(ClipboardData(text: snapshot.data![index].name+"\n"+snapshot.data![index].description))
.then((value) {
ScaffoldMessenger.of(context).showSnackBar(new SnackBar(content: Text('Copied')));
},);
});
},
),],),],)),),)));})
: Container();
},
separatorBuilder: (BuildContext context, int index) {
return snapshot.data![index].name
.toLowerCase()
.contains(searchString) ||
snapshot.data![index].description
.toLowerCase()
.contains(searchString)
? Divider()
: Container();
},
);
}
),
);
} else if (snapshot.hasError) {
return const Center(child: Text('Something went wrong :('));
}
return const Align(alignment:Alignment.topCenter,child:CircularProgressIndicator());
},
future: codes,
),
),
],
),
);
}
//read from files
Future<List<Code>> fetchCodes() async {
final response =
await rootBundle.loadString('assets/articles.json');
var CodeJson = json.decode(response)[widget.bookName] as List<dynamic>;
return CodeJson.map((code) => Code.fromJson(code)).toList();
}
}
I tried using riverpod for provider and save to sharedpreference the list of code that I favorited.
final sharedPrefs =
FutureProvider<SharedPreferences>((_) async => await SharedPreferences.getInstance());
class FavoriteListController extends StateNotifier<List<Code>>{
FavoriteListController(this.pref) : super(Code.decode(pref?.getString("favcode")??""));
static final favoriteListProvider = StateNotifierProvider<FavoriteListController, List<Code>>((ref) {
final pref = ref.watch(sharedPrefs).maybeWhen(
data: (value) => value,
orElse: () => null,
);
print(pref?.getString("favcode"));
return FavoriteListController(pref);
});
final SharedPreferences? pref;
void toggle(Code code) {
if (state.contains(code)) {
state = state.where((id) => id != code).toList();
} else {
state = [...state, code];
}
final String encodedData = Code.encode(state);
pref!.setString("favcode", encodedData);
}
}
I am not sure what is the cause of this but I think it might be because of futurebuilder? I am confused to how to solve this issue...
I am stuck in a dead end so any help or advice would be really appreciated
edit 1-
this is my source code in case I have not include all the necessary codes
https://github.com/sopheareachte/LawCode
edit-2
do I need to change "late Future<List> codes;" that fetch all the codes for futurebuilder to riverpod futureprovider too for it to work?
Maybe the problem is, that you define a static provider inside of your controller class. Try this code:
final sharedPrefs = FutureProvider<SharedPreferences>((_) async => await SharedPreferences.getInstance());
final favoriteListProvider = StateNotifierProvider<FavoriteListController, List<Code>>((ref) {
final pref = ref.watch(sharedPrefs).maybeWhen(
data: (value) => value,
orElse: () => null,
);
print(pref?.getString("favcode"));
return FavoriteListController(pref);
});
class FavoriteListController extends StateNotifier<List<Code>>{
FavoriteListController(this.pref) : super(Code.decode(pref?.getString("favcode")??""));
final SharedPreferences? pref;
void toggle(Code code) {
if (state.contains(code)) {
state = state.where((id) => id != code).toList();
} else {
state = [...state, code];
}
final String encodedData = Code.encode(state);
pref!.setString("favcode", encodedData);
}
}

How to provide filled places in Flutter

First I want to introduce the pages.
Form Page
This is where I fill a form. When I click save as draft it will save the form data to the SQLite database. For now, I haven't implemented SQLite yet. Anyway, But I have a list that buffers the form input. When you click on Save as draft, I create a FormData object and add that data to a list and provide that list with Provider.
Form Page Code
class FormPage extends StatefulWidget {
FormData? formData = FormData();
FormPage({Key? key, this.formData}) : super(key: key);
#override
State<FormPage> createState() => _HomePageState();
}
class _HomePageState extends State<FormPage> {
String? isEmpty(String val) {
String? text;
setState(() {
if (val.isEmpty) {
text = 'Boş bırakılamaz';
}
});
return text;
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xffffe0b2),
appBar: AppBar(
// backgroundColor: Colors.teal.shade400,
title: const Text('Hasta Etkileşim Kaydı'),
centerTitle: true,
backgroundColor: const Color(0xffffb74d),
elevation: 0,
),
body: SafeArea(
child: FutureBuilder(
future: readJsonData(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text(snapshot.error.toString());
} else if (snapshot.hasData) {
var items = snapshot.data as List<dynamic>;
var listStajTuru = items[0].stajTuruItems;
var listCinsiyet = items[0].cinsiyetItems;
var listEtkilesim = items[0].etkilesimTuruItems;
var listKapsam = items[0].kapsamItems;
var listOrtam = items[0].ortamItems;
var listDoktor = items[0].doktorItems;
return Form(
key: _formKey,
child: ListView(
shrinkWrap: true,
children: [
myDropDownContainer(_valueStajTuru, listStajTuru,
hintTextStajTuru, onChangedStajTuru),
myDropDownContainer(_valueDoktor, listDoktor,
hintTextDoktor, onChangedDoktor),
myDropDownContainer(_valueCinsiyet, listCinsiyet,
hintTextCinsiyet, onChangedCinsiyet),
myDropDownContainer(_valueEtkilesim, listEtkilesim,
hintTextEtkilesim, onChangedEtkilesim),
myDropDownContainer(_valueKapsam, listKapsam,
hintTextKapsam, onChangedKapsam),
myDropDownContainer(_valueOrtam, listOrtam,
hintTextOrtam, onChangedOrtam),
myTextFieldRow(20, "Kayıt No: ", 10,
_formData.setKayitNo, isEmpty),
myTextFieldRow(
20, "Hastanın Yaşı:", 3, _formData.setYas, isEmpty),
myTextFieldRow(
20, "Şikayet:", 10, _formData.setSikayet, isEmpty),
myTextFieldRow(50, "Ayırıcı Tanı:", 50,
_formData.setAyiriciTani, isEmpty),
myTextFieldRow(50, "Kesin Tanı:", 50,
_formData.setKesinTani, isEmpty),
myTextFieldRow(50, "Tedavi Yöntemi:", 100,
_formData.setTedaviYontemi, isEmpty),
const SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
submitButton(context, "Sava as Draft"),
submitButton(context, "GÖNDER"),
],
),
],
),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
})),
);
}
//Kullanıcı kaydet butonuna basarsa local olarak kaydedecek
Container submitButton(BuildContext context, String title) {
return Container(
width: 120,
height: 50,
margin: const EdgeInsets.all(12),
child: TextButton(
onPressed: () {
setState(() {
if (_formKey.currentState!.validate()) {
Provider.of<FormAdd>(context, listen: false)
.addNewFormToList(_formData);
alertDialog(context).then((_) =>_formKey.currentState!.reset());
}
});
},
child: Text(
title,
style: kTextStyle.copyWith(
fontSize: 14, color: Colors.white, fontWeight: FontWeight.bold),
),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(
const Color(0xffffa726),
),
),
),
);
}
//DropDownWidget
Container myDropDownContainer(String initialVal, List<String> listItems,
String text, Function myFunc) {
return Container(
margin: const EdgeInsets.all(8),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
width: 120,
child: Text(
text,
style: kTextStyle,
),
),
const SizedBox(
width: 20,
),
Expanded(
child: Container(
height: 50,
decoration: BoxDecoration(
color: Colors.orangeAccent,
borderRadius: BorderRadius.circular(5)),
child: DropdownButtonFormField<String>(
// autovalidateMode: AutovalidateMode.always,
//menuMaxHeight: 300,
validator: (value) {
if (value!.isEmpty) {
return "485s4a8sd4as85";
}
},
decoration: const InputDecoration(border: InputBorder.none),
isExpanded: true,
//onTap: () => myFunc,
//borderRadius: BorderRadius.circular(5),
value: initialVal,
icon: const Icon(
Icons.arrow_downward,
color: Colors.black38,
),
iconSize: 24,
elevation: 16,
dropdownColor: Colors.deepOrange,
style: kTextStyle.copyWith(color: Colors.black),
onChanged: (val) => myFunc(val),
items: listItems.map<DropdownMenuItem<String>>((String? val) {
return DropdownMenuItem(
//TODO: Set default values
value: val == null ? val = initialVal : val = val,
child: Text(
val,
style: kTextStyle.copyWith(color: Colors.black),
),
);
}).toList(),
),
),
)
],
),
);
}
//TextFieldWidget
Row myTextFieldRow(double height, String text, int? maxLength,
Function function, Function regexFunction) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 80,
height: height,
child: Text(
text,
style: kTextStyle.copyWith(color: Colors.black54),
),
),
const SizedBox(
width: 10,
),
Expanded(
child: TextFormField(
validator: (value) => regexFunction(value),
// focusNode: FocusNode(),
onChanged: (input) {
function(input);
},
autofocus: false,
textAlignVertical: TextAlignVertical.bottom,
style: kTextStyle.copyWith(fontSize: 16),
maxLength: maxLength,
maxLines: null, //TODO:Arrange maxlines for the inputs
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.fromLTRB(0, 0, 0, height),
border: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.green),
borderRadius: BorderRadius.all(Radius.circular(3))),
// labelStyle:kTextStyle.copyWith(fontSize: 16, color: Colors.white54),
),
),
),
],
);
}
Future<List<FormContent>> readJsonData() async {
final jsonData =
await rootBundle.rootBundle.loadString('assets/json/formdata.json');
return [
for (final e in json.decode(jsonData)) FormContent.fromJson(e),
];
}
final _formKey = GlobalKey<FormState>();
final FormData _formData = FormData();
String _valueEtkilesim = "Gözlem";
String _valueKapsam = "Öykü";
String _valueOrtam = "Poliklinik";
String _valueDoktor = "Diğer";
String _valueStajTuru = "Ortopedi";
String _valueCinsiyet = "Erkek"; // initial value
final String hintTextCinsiyet = "Cinsiyet:";
final String hintTextStajTuru = "Staj Türü:";
final String hintTextEtkilesim = "Etkileşim Türü:";
final String hintTextKapsam = "Kapsam:";
final String hintTextOrtam = "Gerçekleştiği Ortam:";
final String hintTextDoktor = "Klinik Eğitici:";
void onChangedCinsiyet(String? newVal) {
setState(() {
_valueCinsiyet = newVal!;
_formData.setCinsiyet(_valueCinsiyet);
});
}
void onChangedStajTuru(String newVal) {
setState(() {
_valueStajTuru = newVal;
_formData.setStajTuru(newVal);
});
}
void onChangedEtkilesim(String newVal) {
setState(() {
_valueEtkilesim = newVal;
_formData.setEtkilesimTuru(newVal);
});
}
void onChangedKapsam(String newVal) {
setState(() {
_valueKapsam = newVal;
_formData.setKapsam(newVal);
});
}
void onChangedOrtam(String newVal) {
setState(() {
_valueOrtam = newVal;
_formData.setOrtam(newVal);
});
}
void onChangedDoktor(String newVal) {
setState(() {
_valueDoktor = newVal;
_formData.setDoktor(newVal);
});
}
}
Assume, we saved the form as a draft. Now, It is in the DraftsPage.
Drafts Page
Everything is alright up to now. I have a list of the saved in draft forms. When I click on any list item I could get the form information (3rd picture).
Here is the question.
When I click on the Edit button. I want to renavigate to the Form Page.However this time I want to fill the places with the relevant data. For instance, this time Kayıt No: TextField shouldn't be empty it must be filled with 555, because it was saved to draft. And unfilled places must be blank. I know I need to provide an object of the form(formData) but, I couldn't manage it. When I click on the Edit button. I should provide that object and use it in the Form Page to fill those forms. But, how?
Draft Code
class Drafts extends StatelessWidget {
#override
Widget build(BuildContext context) {
void pushToFormPage(FormData formData) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FormView(
formData: formData,
)));
}
List<FormData> _forms = Provider.of<FormAdd>(context).getForms();
return Scaffold(
backgroundColor: Colors.grey,
appBar: AppBar(
title: const Text("Taslaklar"),
centerTitle: true,
),
body: ListView.separated(
separatorBuilder: (BuildContext context, int index) => const Divider(
height: 5,
color: Colors.blueAccent,
),
itemCount: _forms.length,
itemBuilder: (BuildContext context, int index) {
return studentListViewInstanceContainer(
const Color.fromARGB(200, 200, 130, 240),
pushToFormPage,
_forms[index], context);
},
),
);
}
}
GestureDetector studentListViewInstanceContainer(
Color color, Function function, FormData formData,BuildContext context) {
return GestureDetector(
onTap: () => function(formData),
child: Container(
height: 100,
color: color,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Kayıt No: ${formData.getKayitNo()}',
style: kTextStyle,
),
Text(
'Tarih: ${formData.getKayitNo()}',
style: kTextStyle.copyWith(fontSize: 15),
) //TODO: implement DateT
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ElevatedButton(onPressed: (){
// taslağa kaydedilmiş bilgiler tekrar yüklenecek.
FormData data= Provider.of<FormData>(context,listen: false);
Navigator.push(context, MaterialPageRoute(builder: (context)=>FormPage(formData: data,)));
},
child:const Text('Edit'),
),
const SizedBox(width: 5,),
ElevatedButton(onPressed: (){
},
child: const Text('Delete'),
),
],
),
],
),
),
);
}
This is my FormData model class.
class FormData with ChangeNotifier{
String? _kayitNo;
String? _stajTuru;
String? _doktor; //TODO: Convert string to AttendingPhysician type object
// late AttendingPhysician klinikEgitici;
String? _yas; // TODO: Convert to string later
String? _cinsiyet;
String? _sikayet;
String? _ayiriciTani;
String? _kesinTani;
String? _tedaviYontemi;
String? _etkilesimTuru;
String? _kapsam;
String? _gerceklestigiOrtam;
//DateTime tarih;
String getKayitNo()=>_kayitNo!;
String getStajTuru()=>_stajTuru!;
String getDoktor()=>_doktor!;
String getYas()=>_yas!;
String getCinsiyet()=>_cinsiyet!;
String getSikayet()=>_sikayet!;
String getAyiriciTani()=>_ayiriciTani!;
String getKesinTani()=>_kesinTani!;
String getTedaviYontemi()=>_tedaviYontemi!;
String getEtkilesimTuru()=>_etkilesimTuru!;
String getKapsam()=>_kapsam!;
String getOrtam()=>_gerceklestigiOrtam!;
void setStajTuru(String stajTuru) {
_stajTuru = stajTuru;
notifyListeners();
}
void setCinsiyet(String cinsiyet) {
_cinsiyet = cinsiyet;
notifyListeners();
}
void setEtkilesimTuru(String etkilesim) {
_etkilesimTuru = etkilesim;
notifyListeners();
}
void setKapsam(String kapsam) {
_kapsam = kapsam;
notifyListeners();
}
void setOrtam(String ortam) {
_gerceklestigiOrtam = ortam;
notifyListeners();
}
void setKayitNo(String kayitNo) {
_kayitNo = kayitNo;
notifyListeners();
}
void setYas(String yas) {
_yas = yas;
notifyListeners();
}
void setSikayet(String sikayet) {
_sikayet = sikayet;
notifyListeners();
}
void setAyiriciTani(String ayiriciTani) {
_ayiriciTani = ayiriciTani;
notifyListeners();
}
void setKesinTani(String kesinTani) {
_kesinTani = kesinTani;
notifyListeners();
}
void setTedaviYontemi(String tedaviYontemi) {
_tedaviYontemi = tedaviYontemi;
notifyListeners();
}
void setDoktor(String doktor){
_doktor=doktor;
notifyListeners();
}
}
To make it easier to understand the question. This process is the same as saving mail as a draft. When you want to edit the mail, the unfinished mail will show up not an empty mail.