Return null value between two dates in sqflite and flutter - flutter

i have spent three days for find solution but nothing , always have a same value NULL!
I create database and the function to calculate total in chossing period here :
1/ class Database
class DatabaseHelper {
static DatabaseHelper _databaseHelper; // Singleton DatabaseHelper
static Database _database; // Singleton Database
String clientTable = 'client_table';
String colId = 'id';
String colNumerotelephone = 'numerotelephone';
String colCode = 'code';
String colPrix = 'prix';
String colPriority = 'priority';
String colColor = 'color';
String colDate = 'date';
DatabaseHelper._createInstance(); // Named constructor to create instance of DatabaseHelper
factory DatabaseHelper() {
if (_databaseHelper == null) {
_databaseHelper = DatabaseHelper
._createInstance(); // This is executed only once, singleton object
}
return _databaseHelper;
}
Future<Database> get database async {
if (_database == null) {
_database = await initializeDatabase();
}
return _database;
}
Future<Database> initializeDatabase() async {
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + 'clients.db';
var clientsDatabase =
await openDatabase(path, version: 1, onCreate: _createDb);
return clientsDatabase;
}
void _createDb(Database db, int newVersion) async {
await db.execute(
'CREATE TABLE $clientTable($colId INTEGER PRIMARY KEY AUTOINCREMENT, $colNumerotelephone TEXT,$colCode TEXT, '
'$colPrix REAL, $colPriority INTEGER, $colColor INTEGER,$colDate TEXT)');
}
.......
// code where i get the null value
Future claculTotalPeriod (String startDate, String endDate) async {
var totalClientperiod = await database;
var resulttotalperiod = await totalClientperiod.rawQuery("SELECT SUM($colPrix) AS TOTAL from $clientTable WHERE $colDate BETWEEN '$startDate' AND '$endDate'");
return resulttotalperiod.toList();
}
}
2/and this class for displaying database data
class ClientList extends StatefulWidget {
const ClientList({Key key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return ClientListState();
}
}
class ClientListState extends State<ClientList> {
DatabaseHelper databaseHelper = DatabaseHelper();
List<Client> clientList;
double somme_period = 00;
String somme_total_period = "00.00";
String startDate='';
String endDate='';
TextEditingController startdate = TextEditingController();
TextEditingController finishdate = TextEditingController();
void calcul_total_period() async {
var totalSumPeriod = (await databaseHelper.claculTotalPeriod(startDate, endDate))[0]['TOTAL']; //['$startDate''$endDate'];
setState(() {
somme_period = totalSumPeriod ?? 00;
somme_total_period = somme.toStringAsFixed(2);
});
}
#override
Widget build(BuildContext context) {
if (clientList == null) {
clientList = [];
updateListView();
}
return Scaffold(
appBar: myAppBar(),
body: clientList.isEmpty
? Container(
color: Colors.white,
child: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text('ADD Client',
style: Theme.of(context).textTheme.bodyText2),
),
),
)
: Container(
color: Colors.white,
child: getClientsList(),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
navigateToDetail(Client('', '', '', 3, 0, 0.0), 'new');
},
tooltip: 'Add',
shape: const CircleBorder(
side: BorderSide(color: Colors.black, width: 2.0)),
child: const Icon(Icons.add, color: Colors.black),
backgroundColor: Colors.white,
),
bottomNavigationBar: OutlinedButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return Container(
margin: const EdgeInsets.all(20),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
color: Colors.white,
clipBehavior: Clip.antiAliasWithSaveLayer,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const SizedBox(height: 20,),
TextField(
controller: startdate,
//editing controller of this TextField
decoration: const InputDecoration(
icon: Icon(Icons.calendar_today), //icon of text field
labelText: "start date" //label text of field
),
readOnly: true,
//set it true, so that user will not able to edit text
onTap: () async {
DateTime pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2022,12),
lastDate: DateTime(2026,12));
if (pickedDate != null) {
print(
pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000
String formattedDate =
DateFormat('yyyy-MM-dd').format(pickedDate);
print(
formattedDate); //formatted date output using intl package => 2021-03-16
setState(() {
startdate.text =
formattedDate;
startDate = startdate.text.toString(); //set output date to TextField value.
});
} else {}
},
),
const SizedBox(height: 20,),
TextField(
controller: finishdate,
//editing controller of this TextField
decoration: const InputDecoration(
icon: Icon(Icons.calendar_today), //icon of text field
labelText: "end date" //label text of field
),
readOnly: true,
//set it true, so that user will not able to edit text
onTap: () async {
DateTime pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2022,12),
lastDate: DateTime(2026,12));
if (pickedDate != null) {
print(
pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000
String formattedDate =
DateFormat('yyyy-MM-dd').format(pickedDate);
print(
formattedDate); //formatted date output using intl package => 2021-03-16
setState(() {
finishdate.text =
formattedDate; //set output date to TextField value.
endDate = finishdate.text.toString();
});
} else {}
},
),
const SizedBox(height: 20,),
OutlinedButton(
onPressed: () {
calcul_total_period();
},
child: const Text(' period total')),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
somme_total_period,
style: Theme.of(context).textTheme.headline5,
textAlign: TextAlign.center,
),
),
],
),
),
);
});
},
child: const Text('totalinperiod')),
);
}
void updateListView() {
final Future<Database> dbFuture = databaseHelper.initializeDatabase();
dbFuture.then((database) {
Future<List<Client>> clientListFuture = databaseHelper.getClientList();
clientListFuture.then((clientList) {
setState(() {
this.clientList = clientList;
count = clientList.length;
});
});
});
}
}
when i execute the code always i get the null value for the resulttotalperiod
can same one help me please.

Related

How to Fetching data from sql database in flutter between two date?

in flutter and sqflite i created this function to calculate the total of price in colPrix.
I want to calculate total prices between two dates (period time) by pick and choose the date of start and the end date every time want to calculate the total .
What shoud i do ?
1/function calculate Total in database (where i create database).
class DatabaseHelper {
static DatabaseHelper _databaseHelper; // Singleton DatabaseHelper
static Database _database; // Singleton Database
String clientTable = 'client_table';
String colId = 'id';
String colNumerotelephone = 'numerotelephone';
String colCode = 'code';
String colPrix = 'prix';
String colPriority = 'priority';
String colColor = 'color';
String colDate = 'date';
DatabaseHelper._createInstance();
factory DatabaseHelper() {
if (_databaseHelper == null) {_databaseHelper = DatabaseHelper._createInstance(); // This is executed only once, singleton object}
return _databaseHelper;
}
Future<Database> get database async {
if (_database == null) { _database = await initializeDatabase();}
return _database;
}
.....
.....
Future claculTotalPeriod (String startDate, String endDate) async {
var totalClientperiod = await database;
var result = await totalClientperiod.rawQuery("SELECT SUM($colPrix) AS TOTAL from $clientTable WHERE $colDate BETWEEN '$startDate' AND '$endDate'");
return result.toList();
}
}
2/display the result
class ClientList extends StatefulWidget {
const ClientList({Key key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return ClientListState();
}
}
class ClientListState extends State<ClientList> {
DatabaseHelper databaseHelper = DatabaseHelper();
List<Client> clientList;
int count = 0;
int axisCount = 2;
double somme_period = 00;
String somme_total_period = "00.00";
String startDate='';
String endDate='';
TextEditingController startdate = TextEditingController();
TextEditingController finishdate = TextEditingController();
void calcul_total_period() async {
var total_sum_period = (await databaseHelper.claculTotalPeriod(startDate, endDate))[0]['$startDate''$endDate'];
setState(() {
somme_period = total_sum_period ?? 00;
somme_total_period = somme.toStringAsFixed(2);
});
}
#override
Widget build(BuildContext context) {
if (clientList == null) {
clientList = [];
updateListView();
}
return Scaffold(
appBar: myAppBar(),
body: clientList.isEmpty
? Container(
color: Colors.white,
child: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text('add+',
style: Theme.of(context).textTheme.bodyText2),
),
),
)
: Container(
color: Colors.white,
child: getClientsList(),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
navigateToDetail(Client('', '', '', 3, 0, 0.0), 'new');
},
tooltip: 'add',
shape: const CircleBorder(
side: BorderSide(color: Colors.black, width: 2.0)),
child: const Icon(Icons.add, color: Colors.black),
backgroundColor: Colors.white,
),
bottomNavigationBar: OutlinedButton(
onPressed: () {
showDialog(
...
child: Column(
TextField(
controller: startdate,
decoration: const InputDecoration(
icon: Icon(Icons.calendar_today
),
onTap: () async {
DateTime pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2022,12),
lastDate: DateTime(2026,12));
if (pickedDate != null) {
print(
pickedDate);
String formattedDate =
DateFormat('yyyy-MM-dd').format(pickedDate);
print(
formattedDate); //formatted date output using intl package => 2021-03-16
setState(() {
startdate.text =
formattedDate;
startDate = startdate.text.toString();
});
} else {}
},
),
const SizedBox(height: 20,),
TextField(
controller: finishdate,
decoration: const InputDecoration(
icon: Icon(Icons.calendar_today), //icon of text field
),
onTap: () async {
DateTime pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2022,12),
lastDate: DateTime(2026,12));
if (pickedDate != null) {
print(
pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000
String formattedDate =
DateFormat('yyyy-MM-dd').format(pickedDate);
print(
formattedDate); //formatted date output using intl package => 2021-03-16
setState(() {
finishdate.text =
formattedDate; //set output date to TextField value.
endDate = finishdate.text.toString();
});
} else {}
},
),
const SizedBox(height: 20,),
OutlinedButton(
onPressed: () {
calcul_total_period();
},
child: const Text(' total in period')),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
somme_total_period,
style: Theme.of(context).textTheme.headline5,
textAlign: TextAlign.center,
),
),
],
),
),
);
});
},
child: const Text('total')),
);
}
Widget getClientsList() {
return StaggeredGridView.countBuilder(
physics: const BouncingScrollPhysics(),
crossAxisCount: 4,
itemCount: count,
itemBuilder: (BuildContext context, int index) => GestureDetector(
onTap: () {
navigateToDetail(clientList[index], 'edit');
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: colors[clientList[index].color],
border: Border.all(width: 2, color: Colors.black),
borderRadius: BorderRadius.circular(8.0)),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
clientList[index].numerotelephone,
style: Theme.of(context).textTheme.bodyText2,
),
),
),
Text(
getPriorityText(clientList[index].priority),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
clientList[index].code,
style: Theme.of(context).textTheme.bodyText2,
),
),
),
],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Text(clientList[index].prix.toString() ?? 0,
style: Theme.of(context).textTheme.bodyText1),
)
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(clientList[index].date,
style: Theme.of(context).textTheme.subtitle2),
])
],
),
),
),
),
staggeredTileBuilder: (int index) => StaggeredTile.fit(axisCount),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
);
}
void navigateToDetail(Client client, String title) async {
bool result = await Navigator.push(context,
MaterialPageRoute(builder: (context) => ClientDetail(client, title)));
if (result == true) {
updateListView();
}
}
void updateListView() {
final Future<Database> dbFuture = databaseHelper.initializeDatabase();
dbFuture.then((database) {
Future<List<Client>> clientListFuture = databaseHelper.getClientList();
clientListFuture.then((clientList) {
setState(() {
this.clientList = clientList;
count = clientList.length;
});
});
});
}
}
You can do like this
List<Map> results = await dbClient.rawQuery(
"SELECT SUM(col) as TOTAL "
"FROM MyTable "
"AND dateTimeStamp >= ? "
"AND dateTimeStamp <= ? "
"ORDER BY dateTimeStamp ASC ",
[fromTimestamp,toTimeStamp]);

Put request in flutter ,does not update the object when I change only one field on edit screen

When making a put request and I edit all the field the object is updated. But if I only update one field on the edit screen than the object is not update. I think this is because the unchanged controllers do not keep the value that is already given to them in the Set state method.
Can anyone give me some hints how to solve this ?
import 'package:fin_app/apiservice/variables.dart';
import 'package:fin_app/screens/reminder/reminder_screen.dart';
import 'package:fin_app/screens/login_screen/login_screen.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../../models/user.dart';
import '../monthly_expense/expense_app_theme.dart';
const String myhomepageRoute = '/';
const String myprofileRoute = 'profile';
class ReminderEdit extends StatefulWidget {
final String id;
final String title;
final String date;
final int amount;
const ReminderEdit({Key? key, required this.id, required this.title,required this.date,required this.amount}) : super(key: key);
#override
_ReminderEditState createState() => _ReminderEditState();
}
class _ReminderEditState extends State<ReminderEdit> {
final GlobalKey<FormState> _formKey = GlobalKey();
String id="";
final TextEditingController _titleInput = TextEditingController();
final TextEditingController _dateInput = TextEditingController();
final TextEditingController _amountInput = TextEditingController();
Future<Reminder>? _futureReminder;
Future<void> edit(String id,String title,String date,int amount) async {
Map<String, String> requestHeaders = {
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token'
};
final editReminder = jsonEncode({
'title': title,
'date': date,
'amount': amount
});
if (_titleInput.text.isNotEmpty &&
_dateInput.text.isNotEmpty ) {
var response = await http.put(
Uri.parse("$baseUrl/reminder/me/$id/details"),
body: editReminder,
headers: requestHeaders);
if (response.statusCode == 200) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Profile edited succesfully.")));
} else {
print(response.statusCode);
print(id);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Could not edit the reminder.")));
}
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Please fill out the field.")));
}
}
#override
void initState() {
_dateInput.text = ""; //set the initial value of text field
super.initState();
setState(() {
id = widget.id;
_titleInput.text = widget.title;
_dateInput.text = widget.date;
_amountInput.text=widget.amount.toString();
});
}
void navigate() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AlarmPage()),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ExpenseAppTheme.background,
body: Padding(
padding: const EdgeInsets.all(16.0),
child: ListView(
children: <Widget>[
const Align(
alignment: Alignment.topLeft,
child: Text("Edit reminder",
style: TextStyle(
fontSize: 24,
)),
),
const SizedBox(
height: 20,
),
Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
TextFormField(
controller: _titleInput,
decoration: const InputDecoration(
labelText: 'Title',
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
borderSide:
BorderSide(color: Colors.grey, width: 0.0),
),
border: OutlineInputBorder()),
keyboardType: TextInputType.number,
validator: (value) {
if (value == null ||
value.isEmpty ||
value.contains(RegExp(r'^[a-zA-Z\-]'))) {
return 'Use only text!';
}
},
),
const SizedBox(
height: 20,
),
TextFormField(
controller:_dateInput, //editing controller of this TextField
decoration: InputDecoration(
icon: Icon(Icons.calendar_today), //icon of text field
labelText: "Enter Date" //label text of field
),
readOnly:
true, //set it true, so that user will not able to edit text
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(
2000), //DateTime.now() - not to allow to choose before today.
lastDate: DateTime(2101));
if (pickedDate != null) {
print(
pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000
String formattedDate =
DateFormat('yyyy-MM-dd').format(pickedDate);
print(
formattedDate); //formatted date output using intl package => 2021-03-16
//you can implement different kind of Date Format here according to your requirement
setState(() {
_dateInput.text =
formattedDate; //set output date to TextField value.
});
} else {
print("Date is not selected");
}
},
),
const SizedBox(
height: 35,
),
TextFormField(
controller: _amountInput,
decoration: const InputDecoration(
labelText: 'Amount',
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
borderSide:
BorderSide(color: Colors.grey, width: 0.0),
),
border: OutlineInputBorder()),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Amount must not be empty';
} else if (value.contains(RegExp(r'^[0-9]*$'))) {
return 'Amount must only contain numbers';
}
},
), const SizedBox(
height: 20,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: const Size.fromHeight(60)),
onPressed: () {
edit(widget.id,_titleInput.text,_dateInput.text,int.parse(_amountInput.text));
navigate();
},
child: const Text("Submit"),
),
],
),
),
],
),
),
);
}
FutureBuilder<Reminder> buildFutureBuilder() {
return FutureBuilder<Reminder>(
future: _futureReminder,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text('Expense added');
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
);
}
}

How to configure the eventloader with data from sqlite?

Hi I'm beginner of flutter
I want to make marker on my calendar with eventloader
I try to take the data from SQLite and deliver it to the eventloader, but I saw the log that it failed because it was a Future type.
Sqlite has data List of "Challenge"
event loader need Map<DateTime, List> selectedEvents
When I exit and run the application again, the events stored in the currently selected event disappear.
import 'package:firebase_database/firebase_database.dart';
import 'package:firebase_auth/firebase_auth.dart';
import ...
// //
main(){
WidgetsFlutterBinding.ensureInitialized();
runApp(HomePage());
}
// //
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
late Map<DateTime, List<Event>> selectedEvents;
CalendarFormat format = CalendarFormat.month;
DateTime selectedDay = DateTime.now();
DateTime focusedDay = DateTime.now();
DatabaseReference ref = FirebaseDatabase.instance.ref("performance");
List<Challenge> makeList = [];
Map<DateTime, List<dynamic>> _events = {};
TextEditingController _eventController = TextEditingController(); // 텍스트 필드에서 text 가져오기
String name = "";
#override
void initState() {
selectedEvents = {};
super.initState();
}
List<Event> _getEventsfromDay(DateTime date) {
return selectedEvents[date] ?? [];
}
#override
void dispose() {
_eventController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: const Color(0xfff2a900),
title: Text("Challenge"),
centerTitle: true,
),
body: Column(
children: [
TableCalendar(
focusedDay: selectedDay,
firstDay: DateTime(1990),
lastDay: DateTime(2050),
calendarFormat: format,
onFormatChanged: (CalendarFormat _format) {
setState(() {
format = _format;
});
},
startingDayOfWeek: StartingDayOfWeek.sunday,
daysOfWeekVisible: true,
//Day Changed
onDaySelected: (DateTime selectDay, DateTime focusDay) {
setState(() {
selectedDay = selectDay;
focusedDay = focusDay;
});
// print(focusedDay);
},
selectedDayPredicate: (DateTime date) {
return isSameDay(selectedDay, date);
},
eventLoader: _getEventsfromDay,
//To style the Calendar
calendarStyle: CalendarStyle(
isTodayHighlighted: true,
selectedDecoration: BoxDecoration(
color: Color(0xff60584C),
// color: (255, 188, 80),
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(10.0),
),
selectedTextStyle: TextStyle(color: Colors.white),
todayDecoration: BoxDecoration(
color: const Color(0xfff2a900),
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(10.0),
),
defaultDecoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(10.0),
),
weekendDecoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(10.0),
),
),
headerStyle: HeaderStyle(
formatButtonVisible: true,
titleCentered: true,
formatButtonShowsNext: false,
formatButtonDecoration: BoxDecoration(
color: Color(0xff60584C),
borderRadius: BorderRadius.circular(10.0),
),
formatButtonTextStyle: TextStyle(
color: Colors.white,
),
),
),
/// 새로추가
Expanded(
child:FutureBuilder<List<Challenge>>(
future: DatabaseHelper.instance.getChallenge(),
builder: (BuildContext context,
AsyncSnapshot<List<Challenge>> snapshot){
if(!snapshot.hasData){
return Center(child:Text('Loading'));
}
return snapshot.data!.isEmpty
? Center(child:Text('챌린지에 참여해보세요!'))
: ListView( // 챌린지 리스트
children: snapshot.data!.map((challenge){
DateTime sqlDate = DateTime.parse(challenge.date);
return Card(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(10),
child: Row(
children: [
SizedBox(
width: 200,
height: 50,
child: Center(
child: Text(challenge.challenge,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
color: const Color(0xff60584C),
),
),
)
),
],
)
),
Container(
// width: MediaQuery.of(context).size.width * 0.7,
child: Align(
alignment: Alignment.bottomRight,
child: Text(
challenge.date,
style: TextStyle(
fontSize: 15,
color: Colors.grey),
),
),
)
],
)
);
return Center(
child:ListTile(
title:Text(challenge.challenge),
),
);
}).toList(),
);
}),
),
],
),
floatingActionButton: FloatingActionButton.extended(
backgroundColor: Color(0xfff2a900),
onPressed: () => showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text("Today's Challenge"),
content: TextFormField(
controller: _eventController,
),
actions: [
TextButton(
child: Text("Cancel"),
onPressed: () => Navigator.pop(context),
),
TextButton(
child: Text("Ok"),
onPressed: () async {
// 텍스트 필드가 비었을 때
if (_eventController.text.isEmpty) {
} else { // challenge 입력
/// 마커만들 때 쓰일 Map<DateTime, List<Event>> 원소 추가 코드
if (selectedEvents[selectedDay] != null) {
selectedEvents[selectedDay]?.add(
Event(title: _eventController.text),
);
} else {
selectedEvents[selectedDay] = [
Event(title: _eventController.text)
];
}
///
// 로그인한 사용자정보
User? user = FirebaseAuth.instance.currentUser;
for(final providerProfile in user!.providerData){
final emailAddress = providerProfile.email;
List<String>? currentUser = emailAddress?.split('#');
name = currentUser![0];
}
// 현재 날짜
final dateStr = DateFormat('yyyy-MM-dd').format(selectedDay);
// realtime firebase
await ref
.child(name)
.set(_eventController.text)
.asStream();
// sqlite
await DatabaseHelper.instance.add(
Challenge(date:dateStr, challenge: _eventController.text),
);
// _fetchEvents();
}
Navigator.pop(context);
_eventController.clear();
setState((){
///
///
});
return;
},
),
],
),
),
label: Text("🌱"),
icon: Icon(Icons.add),
),
);
}
}
class Challenge{
final int? id;
final String date;
final String challenge;
Challenge({this.id, required this.date, required this.challenge});
factory Challenge.fromMap(Map<String, dynamic> json) => new Challenge(
id : json['id'],
date : json['date'],
challenge: json['challenge']);
Map<String, dynamic> toMap(){
return {
'id' : id,
'date' : date,
'challenge' : challenge,
};
}
}
class DatabaseHelper{
DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
static Database? _database;
Future<Database> get database async => _database ??=await _initDatabase();
Future<Database> _initDatabase() async{
String path = join(await getDatabasesPath(), 'my_challenge.db');
return await openDatabase(
path,
version: 1,
onCreate: _onCreate,
);
}
Future _onCreate(Database db, int version) async{
await db.execute('''
CREATE TABLE my_challenge(
id INTEGER PRIMARY_KEY,
date TEXT,
challenge TEXT
)
''');
}
Future<List<Challenge>> getChallenge() async {
Database db = await instance.database;
var challenges = await db.query('my_challenge', orderBy: 'date');
List<Challenge> challengeList = challenges.isNotEmpty
? challenges.map((c)=>Challenge.fromMap(c)).toList()
:[];
/// selectedEvents : Map<Datetime, List<Event>>
///
return challengeList;
}
Future<int> add(Challenge challenge) async{
Database db = await instance.database;
return await db.insert('my_challenge', challenge.toMap());
}
}
class Event
class Event {
final String title;
Event({required this.title});
String toString() => this.title;
}

The method 'changeeventdescription' was called on null

I have looked at many answers to other questions but I think I am missing something still. I am developing a flutter app and the page that I am having trouble with is a page where I create meetings for a calendar.
When I look at the debug log I see that the eventProvider is null. I copied the structure from another screen in my app and everything works fine there. What have I missed?
Here is the code from the screen:
final eventRef = FirebaseFirestore.instance.collection(('events'));
class AddEventScreen extends StatefulWidget {
static const String id = 'add_event_screen';
final Event event;
AddEventScreen([this.event]);
#override
_AddEventScreenState createState() => _AddEventScreenState();
}
class _AddEventScreenState extends State<AddEventScreen> {
final _db = FirebaseFirestore.instance;
final eventNameController = TextEditingController();
final eventStartTimeController = TextEditingController();
final eventDurationController = TextEditingController();
final eventDateController = TextEditingController();
final eventDescriptionController = TextEditingController();
#override
void dispose() {
eventNameController.dispose();
eventStartTimeController.dispose();
eventDurationController.dispose();
eventDateController.dispose();
eventDescriptionController.dispose();
super.dispose();
}
bool showSpinner = false;
String eventName;
String eventStartTime;
String eventDuration;
String eventData;
String eventDescription;
getCurentAgencyEvents() async {
if (globals.agencyId == null) {
eventNameController.text = "";
eventStartTimeController.text = "";
eventDurationController.text = "";
eventDateController.text = "";
eventDescriptionController.text = "";
} else {
final DocumentSnapshot currentEvent =
await eventRef.doc(globals.agencyId).get();
// existing record
// Updates Controllers
eventNameController.text = currentEvent.data()["name"];
eventStartTimeController.text = currentEvent.data()['address1'];
eventDurationController.text = currentEvent.data()['address2'];
eventDateController.text = currentEvent.data()['city'];
eventDescriptionController.text = currentEvent.data()['state'];
// Updates State
new Future.delayed(Duration.zero, () {
final eventProvider =
Provider.of<EventProvider>(context, listen: false);
eventProvider.loadValues(widget.event);
});
}
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
final eventProvider = Provider.of<EventProvider>(context);
final _firestoreService = FirestoreService();
DateTime _date = new DateTime.now();
TimeOfDay _time = new TimeOfDay.now();
Duration initialtimer = new Duration();
DateTime _selectedDate = DateTime.now();
TimeOfDay _timePicked = TimeOfDay.now();
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset('assets/images/Appbar_logo.png',
fit: BoxFit.cover, height: 56),
],
),
),
backgroundColor: Colors.white,
body: SafeArea(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
Text(
'Event Editor',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.w800,
),
),
SizedBox(
height: 30.0,
),
TextField(
controller: eventNameController,
keyboardType: TextInputType.text,
textAlign: TextAlign.center,
onChanged: (value) {
eventProvider.changeeventname(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Event Name', labelText: 'Event Name'),
),
SizedBox(
height: 8.0,
),
TextField(
controller: eventDurationController,
textAlign: TextAlign.center,
onChanged: (value) {
eventProvider.changeeventduration(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Duration', labelText: 'Duration'),
),
SizedBox(
height: 8.0,
),
TextField(
controller: eventDateController,
keyboardType: TextInputType.datetime,
textAlign: TextAlign.center,
onTap: () async {
DateTime _datePicked = await showDatePicker(
context: context,
initialDate: _selectedDate,
//firstDate: new DateTime.now().add(Duration(days: -365)),
firstDate: new DateTime(2020),
lastDate: new DateTime(2022));
if (_date != null && _date != _datePicked) {
setState(() {
eventDateController.text =
DateFormat("MM/dd/yyyy").format(_datePicked);
eventProvider.changeeventdate(_datePicked);
_selectedDate = _datePicked;
//DateFormat("MM/dd/yyyy").format(_date));
});
}
},
onChanged: (value) {
eventProvider.changeeventdate(_date);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Date',
labelText: 'Date',
),
),
SizedBox(
height: 8.0,
),
TextField(
controller: eventStartTimeController,
keyboardType: TextInputType.text,
textAlign: TextAlign.center,
onTap: () async {
TimeOfDay _timePicked = await showTimePicker(
context: context,
initialTime: new TimeOfDay.now());
//if (_timePicked != null) {
setState(() {
eventStartTimeController.text = _timePicked.format(context);
});
//}
},
onChanged: (value) {
eventProvider.changeeventstarttime(_timePicked);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Start Time',
labelText: 'Start Time',
),
),
SizedBox(
height: 8.0,
),
TextField(
controller: eventDescriptionController,
keyboardType: TextInputType.text,
textAlign: TextAlign.center,
onChanged: (value) {
eventProvider.changeeventdescription(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Description', labelText: 'Description'),
),
SizedBox(
height: 8.0,
),
RoundedButton(
title: 'Save Event',
colour: Colors.blueAccent,
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
globals.newEvent = true;
eventProvider.saveEvent();
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => AppointmentCalendarScreen()));
setState(() {
showSpinner = false;
});
} catch (e) {
// todo: add better error handling
print(e);
}
},
),
SizedBox(
height: 8.0,
),
(widget != null)
? RoundedButton(
title: 'Delete',
colour: Colors.red,
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
//agencyProvider.deleteAgency(globals.currentUid);
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => AppointmentCalendarScreen()));
setState(() {
showSpinner = false;
});
} catch (e) {
// todo: add better error handling
print(e);
}
},
)
: Container()
],
),
),
),
),
);
}
}
Here is the debug log and I get the same message for each input control:
======== Exception caught by widgets ===============================================================
The following NoSuchMethodError was thrown while calling onChanged:
The method 'changeeventname' was called on null.
Receiver: null
Tried calling: changeeventname("Test event")
Here is the code for the EventProvider:
class EventProvider with ChangeNotifier {
final firestoreService = FirestoreService();
FirebaseFirestore _db = FirebaseFirestore.instance;
final eventRef = FirebaseFirestore.instance.collection(('events'));
String _eventName;
TimeOfDay _eventStartTime;
String _eventDuration;
DateTime _eventDate;
String _eventDescription;
//Getters
String get eventName => _eventName;
TimeOfDay get eventStartTime => _eventStartTime;
String get eventDuration => _eventDuration;
DateTime get eventDate => _eventDate;
String get eventDescription => _eventDescription;
final EventProvider eventProvider = new EventProvider();
//Setters
changeeventname(String value) {
_eventName = value;
notifyListeners();
}
changeeventstarttime(TimeOfDay value) {
_eventStartTime = value;
notifyListeners();
}
changeeventduration(String value) {
_eventDuration = value;
notifyListeners();
}
changeeventdate(DateTime value) {
_eventDate = value;
notifyListeners();
}
changeeventdescription(String value) {
_eventDescription = value;
notifyListeners();
}
loadValues(Event event) {
_eventName = event.eventName;
_eventStartTime = event.eventStartTime;
_eventDuration = event.eventDuration;
_eventDate = event.eventDate;
_eventDescription = event.eventDescription;
}
saveEvent() {
var newEvent = Event(
eventName: _eventName,
eventStartTime: _eventStartTime,
eventDuration: _eventDuration,
eventDate: _eventDate,
eventDescription: _eventDescription);
// If the agency is a new agency retrieve the agency
// document ID and save it to a new agent document
if (globals.newEvent == true) {
String id = _db.collection('event').doc().id;
globals.agencyId = id;
//firestoreService.saveNewEvent(newEvent);
eventProvider.saveEvent();
globals.newEvent = false;
} else {
firestoreService.saveEvent(newEvent);
}
}
}
I found the issue. I just needed to clean up the code.

Flutter: How to assign other value (object) as Text Editing Controller in Another Field?

I'm building a form that has contact name and phone number fields. User will be able to choose (tap) contact from previously saved contact list, and this should display name and phone numbers at their respective fields.
To achieve that I'm using TypeAheadFormField from Flutter_Form_Builder Package version: 3.14.0 to build my form.
I successfully assign _nameController from local database in the default TypeAheadFormField controller.
But I can't assign _mobileController from the same choice I tapped to FormBuilderTextField.
I managed to get "name'-value with TypeAheadFormField, but everytime I switch the choices from suggestions,
the _mobileController.text didn't update on FormBuilderTextField
My code as follow:
import 'package:myApp/customer.dart';
import 'package:myApp/db_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
class MyForm extends StatefulWidget {
#override
_MyFormState createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
DatabaseHelper _dbHelper;
Customer _customer = Customer();
List<Customer> _customerList = [];
final _formKey = GlobalKey<FormBuilderState>();
final _cfKey = GlobalKey<FormBuilderState>();
final _nameController = TextEditingController();
final _inputContactNameController = TextEditingController();
final _inputContactPhoneController = TextEditingController();
var _mobileController = TextEditingController();
#override
void initState() {
super.initState();
_refreshBikeSellerList();
setState(() {
_dbHelper = DatabaseHelper.instance;
});
_mobileController = TextEditingController();
_mobileController.addListener(() {
setState(() {});
});
}
#override
void dispose() {
_mobileController.dispose();
_nameController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
child: FormBuilder(
key: _formKey,
child: Column(
children: [
FormBuilderTypeAhead(
attribute: 'contact_person',
initialValue: _customer,
controller: _nameController,
onChanged: (val) {},
itemBuilder: (context, Customer _customer) {
return ListTile(
title: Text(_customer.name),
subtitle: Text(_customer.mobile),
);
},
selectionToTextTransformer: (Customer c) => c.name,
suggestionsCallback: (query) {
if (query.isNotEmpty) {
var lowercaseQuery = query.toLowerCase();
return _customerList.where((_customer) {
return _customer.name
.toLowerCase()
.contains(lowercaseQuery);
}).toList(growable: false)
..sort((a, b) => a.name
.toLowerCase()
.indexOf(lowercaseQuery)
.compareTo(
b.name.toLowerCase().indexOf(lowercaseQuery)));
} else {
return _customerList;
}
},
textFieldConfiguration: TextFieldConfiguration(
autofocus: true,
style: DefaultTextStyle.of(context).style.copyWith(
fontSize: 17,
letterSpacing: 1.2,
color: Colors.black,
fontWeight: FontWeight.w300,
),
// controller: guessMotor1,
),
onSuggestionSelected: (val) {
if (val != null) {
return _customerList.map((_customer) {
setState(() {
_mobileController.text = _customer.mobile;
});
}).toList();
} else {
return _customerList;
}
},
),
FormBuilderTextField(
controller: _mobileController,
attribute: 'mobile',
readOnly: true,
style: TextStyle(fontSize: 17),
decoration: InputDecoration(
hintText: 'mobile',
),
),
SizedBox(height: 40),
Container(
child: RaisedButton(
onPressed: () async {
await manageContact(context);
},
child: Text('Manage Contact'),
),
),
],
),
),
);
}
manageContact(BuildContext context) async {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(
'Manage Contact',
textAlign: TextAlign.center,
),
titleTextStyle: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 17,
color: Colors.black45,
letterSpacing: 0.8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12))),
content: FormBuilder(
key: _cfKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// SizedBox(height: 10),
InkResponse(
onTap: () {},
child: CircleAvatar(
radius: 30,
child: Icon(
Icons.person_add,
color: Colors.grey[100],
),
backgroundColor: Colors.grey[500],
),
),
SizedBox(height: 10),
Container(
width: MediaQuery.of(context).size.width * 0.5,
margin: EdgeInsets.symmetric(horizontal: 15),
child: FormBuilderTextField(
maxLength: 20,
controller: _inputContactNameController,
textAlign: TextAlign.start,
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.words,
attribute: 'contact_person',
decoration: InputDecoration(
prefixIcon: Icon(
Icons.person_outline,
size: 22,
)),
onChanged: (val) {
setState(() {
_customer.name = val;
_formKey
.currentState.fields['contact_person'].currentState
.validate();
});
},
autovalidateMode: AutovalidateMode.always,
validators: [
FormBuilderValidators.required(),
FormBuilderValidators.maxLength(20),
FormBuilderValidators.minLength(2),
],
),
),
Container(
width: MediaQuery.of(context).size.width * 0.5,
margin: EdgeInsets.symmetric(horizontal: 15),
child: FormBuilderTextField(
attribute: 'phone_number',
controller: _inputContactPhoneController,
textAlign: TextAlign.start,
keyboardType: TextInputType.number,
decoration: InputDecoration(
prefixIcon: Icon(
Icons.phone_android,
size: 22,
)),
onChanged: (val) {
setState(() {
_customer.mobile = val;
_formKey.currentState.fields['phone_number'].currentState
.validate();
});
},
validators: [
FormBuilderValidators.required(),
FormBuilderValidators.numeric(),
],
valueTransformer: (text) {
return text == null ? null : num.tryParse(text);
},
),
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
RaisedButton(
color: Colors.white,
child: Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
}),
RaisedButton(
color: Colors.grey[400],
child: Text(
'Save',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
try {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
if (_customer.id == null)
await _dbHelper.insertBikeContact(_customer);
else
await _dbHelper.updateCustomer(_customer);
_refreshBikeSellerList();
_formKey.currentState.reset();
_inputContactNameController.clear();
_inputContactPhoneController.clear();
Navigator.of(context).pop();
}
} catch (e) {
print(e);
}
},
)
],
),
],
),
),
),
);
}
_refreshBikeSellerList() async {
List<Customer> x = await _dbHelper.getCustomer();
setState(() {
_customerList = x;
});
}
}
Is there any possible way to update _mobileController as I tap?
Any help would be much appreciated.
Thank you in advance.
EDITED:
class where I save the customer data:
class Customer {
int id;
String name;
String mobile;
static const tblCustomer = 'Customer';
static const colId = 'id';
static const colName = 'name';
static const colMobile = 'mobile';
Customer({
this.id,
this.name,
this.mobile,
});
Map<String, dynamic> toMap() {
var map = <String, dynamic>{colName: name, colMobile: mobile};
if (id != null) map[colId] = id;
return map;
}
Customer.fromMap(Map<String, dynamic> map) {
id = map[colId];
name = map[colName];
mobile = map[colMobile];
}
#override
bool operator ==(Object other) =>
identical(this, other) ||
other is Customer &&
runtimeType == other.runtimeType &&
name == other.name;
#override
int get hashCode => name.hashCode;
#override
String toString() {
return name;
}
}
Here is my database:
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
import 'customer.dart';
class DatabaseHelper {
static const _databaseVersion = 1;
static const _databaseName = 'Kiloin.db';
DatabaseHelper._();
static final DatabaseHelper instance = DatabaseHelper._();
Database _database;
Future<Database> get database async {
if (_database != null) return _database;
_database = await _initDatabase();
return _database;
}
_initDatabase() async {
Directory dataDirectory = await getApplicationDocumentsDirectory();
String dbPath = join(dataDirectory.path, _databaseName);
return await openDatabase(
dbPath,
version: _databaseVersion,
onCreate: _onCreateDB,
);
}
_onCreateDB(Database db, int version) async {
await db.execute('''
CREATE TABLE ${Customer.tblCustomer}(
${Customer.colId} INTEGER PRIMARY KEY AUTOINCREMENT,
${Customer.colName} TEXT NOT NULL,
${Customer.colMobile} TEXT NOT NULL
)
''');
}
Future<int> insertBikeContact(Customer customer) async {
Database db = await database;
return await db.insert(Customer.tblCustomer, customer.toMap());
}
Future<List<Customer>> getCustomer() async {
Database db = await database;
List<Map> contact = await db.query(Customer.tblCustomer);
return contact.length == 0
? []
: contact.map((e) => Customer.fromMap(e)).toList();
}
Future<int> updateCustomer(Customer customer) async {
Database db = await database;
return await db.update(Customer.tblCustomer, customer.toMap(),
where: '${Customer.colId}=?', whereArgs: [customer.id]);
}
Future<int> deleteContact(int id) async {
Database db = await database;
return await db.delete(Customer.tblCustomer,
where: '${Customer.colId}=?', whereArgs: [id]);
}
}
The value that you get from onSuggestionSelected is the customer. Use that value to update _mobileController.text.
onSuggestionSelected: (customer) {
if (customer != null) {
setState(() {
_mobileController.text = customer.mobile;
});
}
}