Flutter - InputDatePickerFormField - flutter

I'm trying to add a text field that will get the date in the input field. I'm using InputDatePickerFormField widget. The issue I'm finding that it does not show error when the date is incorrect.
Here is my code:
class _BirthDay extends StatefulWidget {
#override
__BirthDayState createState() => __BirthDayState();
}
class __BirthDayState extends State<_BirthDay> {
DateTime? selectedDate;
#override
Widget build(BuildContext context) {
final firstDate = DateTime(DateTime.now().year - 120);
final lastDate = DateTime.now();
return InputDatePickerFormField(
firstDate: firstDate,
lastDate: lastDate,
fieldLabelText: '${AppLocalizations.of(context)!.dateOfBirth}',
errorFormatText: '${AppLocalizations.of(context)!.dateOfBirthInvalid}',
errorInvalidText: '${AppLocalizations.of(context)!.dateOfBirthInvalid}',
onDateSubmitted: (date) {
print(date);
setState(() {
selectedDate = date;
});
},
onDateSaved: (date) {
print(date);
setState(() {
selectedDate = date;
});
},
);
}
}

One way that you can add a checker on your Text fields is by setting the fields as children of a Form. Using this, you'll be able to validate the values on your fields once submitted.
final _formKey = GlobalKey<FormState>();
...
Form(
key: _formKey,
child: InputDatePickerFormField(...),
)
Then you can run a check using _formKey.currentState!.validate()). Trigger this validation on any onClick or onPressed event.

You need to save the form to see the validations errors
_formKey2.currentState.save();
You can call it on the submit button

Related

Assigning a field value from firestore to variable in flutter

I am trying to get four text field values from a specific firestore document, assign them to four different variables and use them in the build context.
This is what I have been trying to do for just one field value:
class PackageScanPage extends StatefulWidget {
#override
State<PackageScanPage> createState() => _PackageScanPageState();
}
class _PackageScanPageState extends State<PackageScanPage> {
#override
Widget build(BuildContext context) {
final _firestore = FirebaseFirestore.instance;
final textFieldValue = ModalRoute.of(context)!.settings.arguments;
var _message;
_fetchData() async{
_firestore.collection("groceries").document('$textFieldValue').get().then((value) {
setState(() {
_message = value.data['name'];
});
});
}
return Container(
child: Text(_message.toString())
),
}
Thanks in advance.
What do you mean by 'get four text field values from a specific firestore document, assign them to four different variables'
if you are trying to pass the text field value from the app to firebase then I got you
TextField(
onSubmitted: (value) async {
FirebaseFirestore.instance.runTransaction(
(Transaction myTransaction) async {
FirebaseFirestore.instance
.collection('example')
.doc('example')
.update({'something': value});
}

Initial date range not set on DateRangePicker

I'm working on application where I need to persist the selected date range with shared preferences. For date picker I'm using an external package, for state handling I work with provider.
At the beginning in provider model I'm reading the value from shared preferences :
class DateRangeFilterModel extends ChangeNotifier {
PickerDateRange? _dateRange;
DateRangeFilterModel() {
loadDateRange();
}
PickerDateRange? get dateRange => _dateRange;
Future<void> loadDateRange() async {
_dateRange = await SharedPreferencesManager.getFilterDateRange();
notifyListeners();
}
Future<PickerDateRange?> getDateRange() async {
return await SharedPreferencesManager.getFilterDateRange();
}
Future<void> setDateRange(PickerDateRange? dateRange) async {
_dateRange = dateRange;
await SharedPreferencesManager.saveFilterDateRange(
dateRange?.startDate, dateRange?.endDate);
notifyListeners();
}
}
With Consumer widget I try to set up the initial value, for an example I also show the result on Text widget. On Text widget saved date range appears but on SfDateRangePicker not.
Consumer<DateRangeFilterModel>(
builder: (context, model, child) => Column(
children: [
Text(model.dateRange.toString()),
SfDateRangePicker(
initialSelectedRange: model.dateRange,
showTodayButton: false,
enablePastDates: false,
selectionMode: DateRangePickerSelectionMode.range,
minDate: DateTime.now(),
onSelectionChanged: (DateRangePickerSelectionChangedArgs args) {
if (args.value is PickerDateRange) {
final DateTime? startDate = args.value.startDate;
final DateTime? endDate = args.value.endDate;
if (startDate != null && endDate != null) {
context
.read<DateRangeFilterModel>()
.setDateRange(PickerDateRange(startDate, endDate));
}
}
},
),
],
),
),
My ChangeNotifierProvider
ChangeNotifierProvider(
create: (context) => DateRangeFilterModel(),
child: const DateRangePicker()
),
I think there is some concurrency problems. Where I made mistake?
Thanks for any advice.
My solution is was to set initial range through controller.
final DateRangePickerController _controller = DateRangePickerController();
.....
SfDateRangePicker(
initialSelectedRange: _controller.selectedRange = model.dateRange,
controller: _controller,
...
)

Error : LateInitializationError: Field '_startDate#934496985' has not been initialized and Set State

I am building a calendar through syncfusion calendar on a flutter app and I have been getting an error that tells me "Field '' has not been initialized". I know that I need to initialize _startDate and _endDate but I am not sure what value it should be given.
Code :
class EventCalendar extends StatefulWidget {
const EventCalendar({Key? key}) : super(key: key);
#override
EventCalendarState createState() => EventCalendarState();
}
List<Color> _colorCollection = <Color>[];
List<String> _colorNames = <String>[];
int _selectedColorIndex = 0;
late DataSource _events;
Meeting? _selectedAppointment;
late DateTime _startDate;
late TimeOfDay _startTime;
late DateTime _endDate;
late TimeOfDay _endTime;
bool _isAllDay = false;
String _subject = '';
String _notes = '';
class EventCalendarState extends State<EventCalendar> {
EventCalendarState();
CalendarView _calendarView = CalendarView.month;
late List<String> eventNameCollection;
late List<Meeting> appointments;
#override
void initState() {
_calendarView = CalendarView.month;
appointments = getMeetingDetails();
_events = DataSource(appointments);
// initialize _startDate and _endDate here?
_selectedAppointment = null;
_selectedColorIndex = 0;
_subject = '';
_notes = '';
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: UserDrawer(),
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.black),
backgroundColor: Colors.transparent,
elevation: 0,
centerTitle: true,
title: const Text('Itinerary',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color: Colors.black)),
),
resizeToAvoidBottomInset: false,
body: Padding(
padding: const EdgeInsets.fromLTRB(5, 0, 5, 5),
child: getEventCalendar(_calendarView, _events, onCalendarTapped)),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add, color: Colors.white),
backgroundColor: Color(0xFF003893),
onPressed: () => Navigator.push<Widget>(
context,
MaterialPageRoute(
builder: (BuildContext context) => EventEditor()),
)));
}
SfCalendar getEventCalendar(
CalendarView _calendarView,
CalendarDataSource _calendarDataSource,
CalendarTapCallback calendarTapCallback) {
return SfCalendar(
view: _calendarView,
backgroundColor: Colors.transparent,
initialSelectedDate: DateTime.now(),
todayHighlightColor: Color(0xFF003893),
selectionDecoration: BoxDecoration(color: Colors.white60),
showNavigationArrow: true,
cellBorderColor: Colors.transparent,
firstDayOfWeek: 1,
onTap: calendarTapCallback,
allowedViews: [
CalendarView.day,
CalendarView.week,
CalendarView.month,
CalendarView.timelineWeek
],
monthViewSettings: MonthViewSettings(
showAgenda: true,
agendaViewHeight: 250,
appointmentDisplayMode: MonthAppointmentDisplayMode.appointment),
dataSource: _calendarDataSource,
initialDisplayDate: DateTime(DateTime.now().year, DateTime.now().month,
DateTime.now().day, 0, 0, 0),
timeSlotViewSettings: TimeSlotViewSettings(
minimumAppointmentDuration: const Duration(minutes: 60)),
);
}
void onCalendarViewChange(String value) {
if (value == 'Day') {
_calendarView = CalendarView.day;
} else if (value == 'Week') {
_calendarView = CalendarView.week;
} else if (value == 'Month') {
_calendarView = CalendarView.month;
} else if (value == 'Timeline week') {
_calendarView = CalendarView.timelineWeek;
}
setState(() {});
}
void onCalendarTapped(CalendarTapDetails calendarTapDetails) {
if (calendarTapDetails.targetElement != CalendarElement.appointment) {
return;
}
setState(() {
_selectedAppointment = null;
_isAllDay = false;
_selectedColorIndex = 0;
_subject = '';
_notes = '';
if (_calendarView == CalendarView.month) {
_calendarView = CalendarView.day;
} else {
if (calendarTapDetails.appointments != null &&
calendarTapDetails.appointments!.length == 1) {
final Meeting meetingDetails = calendarTapDetails.appointments![0];
_startDate = meetingDetails.from;
_endDate = meetingDetails.to;
_isAllDay = meetingDetails.isAllDay;
_selectedColorIndex =
_colorCollection.indexOf(meetingDetails.background);
_subject = meetingDetails.eventName == '(No title)'
? ''
: meetingDetails.eventName;
_notes = meetingDetails.description;
_selectedAppointment = meetingDetails;
} else {
final DateTime date = calendarTapDetails.date!;
_startDate = date;
_endDate = date.add(const Duration(hours: 1));
}
_startTime =
TimeOfDay(hour: _startDate.hour, minute: _startDate.minute);
_endTime = TimeOfDay(hour: _endDate.hour, minute: _endDate.minute);
Navigator.push<Widget>(
context,
MaterialPageRoute(builder: (BuildContext context) => EventEditor()),
);
}
});
}
List<Meeting> getMeetingDetails() {
final List<Meeting> meetingCollection = <Meeting>[];
eventNameCollection = <String>[];
eventNameCollection.add('');
_colorCollection = <Color>[];
_colorCollection.add(const Color(0xFF3D4FB5));
_colorCollection.add(const Color(0xFF0F8644));
_colorCollection.add(const Color(0xFF8B1FA9));
_colorCollection.add(const Color(0xFFD20100));
_colorCollection.add(const Color(0xFFFC571D));
_colorCollection.add(const Color(0xFF85461E));
_colorCollection.add(const Color(0xFFFF00FF));
_colorCollection.add(const Color(0xFFE47C73));
_colorCollection.add(const Color(0xFF636363));
_colorNames = <String>[];
_colorNames.add('Blue');
_colorNames.add('Green');
_colorNames.add('Purple');
_colorNames.add('Red');
_colorNames.add('Orange');
_colorNames.add('Caramel');
_colorNames.add('Magenta');
_colorNames.add('Peach');
_colorNames.add('Gray');
return meetingCollection;
}
}
class DataSource extends CalendarDataSource {
DataSource(List<Meeting> source) {
appointments = source;
}
#override
bool isAllDay(int index) => appointments![index].isAllDay;
#override
String getSubject(int index) => appointments![index].eventName;
#override
String getNotes(int index) => appointments![index].description;
#override
Color getColor(int index) => appointments![index].background;
#override
DateTime getStartTime(int index) => appointments![index].from;
#override
DateTime getEndTime(int index) => appointments![index].to;
}
class Meeting {
Meeting(
{required this.from,
required this.to,
this.background = Colors.green,
this.isAllDay = false,
this.eventName = '',
this.description = ''});
final String eventName;
final DateTime from;
final DateTime to;
final Color background;
final bool isAllDay;
final String description;
}
On top of the error, when I go to another page and return back to this calendar page, whatever events that was saved on it earlier on disappears already.
What value should I be giving to initialize _startDate and _endDate and how do I save the state of the page?
All state properties must be declared inside State class. late means that such variable will be initialized later (for example in initState method). If initialization time is not known make variable nullable, I.e. use question mark for type (e.g. DateTime?.
You don't initialize start and end dates, to be able to accept null use ?
like that
DateTime? _startDate;
DateTime? _endDate;
You can make them nullable, with DateTime? and before using them, where you got an error like when you want to access the hour property from them, you can check them if they are null, like this:
if([_startTime, _endTime].contains(null)) return;
Also, since you don't use the data outside of the handler and it is used after you change the value, you can initialize them with DateTime.now(), like this:
DateTime _startDate = DateTime.now();
And you can do this:
if (_calendarView == CalendarView.month) {
_calendarView = CalendarView.day;
return;
}
To remove the else that's coming after.
While specifying the variable as nullable we need to set the values before use them, in this case the AppointmentEditor class used the _startDate and _endDate values before initializing them, hence to use the values we must ensure that the values were set with values, hence before navigate to the editor page we must set values for the startDate and endDate variable with the required values, in this case you can use the selected date value from CalendarController or current date time value, or the date time value which you want to add the event in calendar.
In this shared code snippet, we have used current time value for the both variables as a default value, kindly set the _startDate and _endDate in the onPressed callback of the FloatingActionButton. Please find the attached code snippet for the same.
Code snippet:
onPressed: () {
_startDate??=DateTime.now();
_endDate??=DateTime.now();
Navigator.push<Widget>(
context,
MaterialPageRoute(
builder: (BuildContext context) => AppointmentEditor()),
)
}

Get data from future func and change the object

Good day!
I have a class ToDoItem
class ToDoItem with ChangeNotifier {
final String id;
final DateTime creationDate;
final DateTime doingDate;
final String text;
final Color color;
ToDoItem({this.id, this.creationDate, this.doingDate, this.text, this.color});
}
Then I have a DatePicker
class _TopWithDateAndOptionState extends State<TopWithDateAndOption> {
var finaldate;
void callDatePicker() async {
var order = await getDate().then(
(value) => print("VAL = ${value}"),
);
// setState(() {
// finaldate = order;
// print("pickeddate = ${finaldate}");
// });
}
Future<DateTime> getDate() {
// Imagine that this function is
// more complex and slow.
return showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2018),
lastDate: DateTime(2030),
builder: (BuildContext context, Widget child) {
return Theme(
data: ThemeData.light(),
child: child,
);
},
);
}
And at the end I get object of ToDoItem class by Provider.
#override
Widget build(BuildContext context) {
final todoItem = Provider.of<ToDoItem>(context);
So the question is how to change the doingDate in object ToDoItem with new value of finaldate?
How to check out if this variable was already changed by new data from DataPicker? Should I use any listener or something simpler?
My problem was the stateful widget. I've changed it to stateless and it worked/

Is there any way to print all selected dates in date-range-picker instead of it first and last dates in flutter?

I'm trying to print all selected dates in date range picker, is there anyway to do it?
here is my code
import 'package:flutter/material.dart';
import 'package:date_range_picker/date_range_picker.dart' as DateRagePicker;
class TryCalendar extends StatefulWidget {
#override
_TryCalendarState createState() => _TryCalendarState();
}
class _TryCalendarState extends State<TryCalendar> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
),
body: new MaterialButton(
color: Color(0xFFED7D31),
onPressed: () async {
final List<DateTime> picked = await DateRagePicker.showDatePicker(
context: context,
initialFirstDate: new DateTime.now(),
initialLastDate: (new DateTime.now()).add(new Duration(days: 7)),
firstDate: new DateTime(2015),
lastDate: new DateTime(2020)
);
if (picked != null && picked.length == 2) {
print(picked);
}
},
child: new Text("Pick date range")
)
);
}
}
I need to print all selected dates instead of first and last selected dates. Thank you!
List<DateTime> getDaysInBeteween(DateTime startDate, DateTime endDate) {
List<DateTime> days = [];
for (int i = 0; i <= endDate.difference(startDate).inDays; i++) {
days.add(startDate.add(Duration(days: i)));
}
return days;
}
picked is list of DateTime , so you should iterate every date in list then print
if (picked != null && picked.length >= 2) {
picked.forEach((date) {
print(date.toString());
});
}