The method 'jumpToDay' was called on null. [Flutter] - flutter

In this application, the user will be able to add tasks and display it in a PageView.builder. The user will also be able to scroll through the PageView.builder by swiping left or right. The pageview is mapped to dates (ex: current page maps to today's date, next page maps to tomorrow's date, etc.). I also wanted to implement a jump feature which lets the user move to a new page by specifying a date on a showDatepicker widget.
The PageView.builder was implemented by using this project. this project also has the jump to page feature : https://github.com/ZedTheLed/calendar_views
the showDatepicker is implemented in the method below. it is called by clicking on a Raisedbutton:
_selectDate() async {
final DateTime picker =await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2010),
lastDate: DateTime(2040)
);
if (picker != null) {
print(picker);
return _daysPageController.jumpToDay(picker); // this method jumps the user to a selected date
// Navigator.pop(context);
// print(selectedDate);
// await runJump(selectedDate);
// return selectedDate;
}
}
when the user clicks on a date, the variable DateTime picker successfully returns the user-selected date in the print statement. But when i pass this value to the jumptopage method, it gives his error : The method 'jumpToDay' was called on null.
The PageView.builder is implemented in the code below :
final List<DateTime> days;
Scaffold(
floatingActionButton: new RaisedButton(
child: new Text("Jump To Today"),
onPressed: () {
_selectDate();
},
),
body: new Column(
children: widget.days.map(((day) => Container(
constraints: new BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 1.00,
maxWidth: MediaQuery.of(context).size.width * 1.00
),
child: Starting_screen(_makeTextString(day)), //this screen displays the tasks added by the user
)
),
).toList()
),
);
the method _makeTextString just modifies a DateTime value and returns it in a desirable format.
Could i get a suggestion on how to handle this error?
full project is available here : https://bitbucket.org/NotAnurag/todolist_restarted/src/master/

When the user clicks on a date, the variable DateTime picker successfully returns the user-selected date in the print statement. But when I pass this value to the jumptopage method, it gives his error: "The method jumpToDay was called on null"
The problem that I see in the code is that _daysPageController is not initialized. IDE helpfully suggests various methods that you can call on DaysPageController, but the fact remains that it is declared, but no value is assigned to it (meaning that it is null):
DaysPageController _daysPageController; // remains null unless assigned a value
Therefore, what the error is attempting to tell is that jumpToDay(DateTime) is called on null (which obviously does not have such a method). If you look at the stack trace a bit more explicit hint is buried in there:
[ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: NoSuchMethodError: The method 'jumpToDay' was called on null.
Try to initialize the controller and see if it helps to resolve the issue.

Related

How do i modify the data of an existing variable in flutter?

I want to make an editable TextWidget in flutter but I don't really know how to go around it, I did some research, but still can't find a good solution.
Here's my sample code below.
I have a variable called
int qty = 1;
and so I called the variable in TextWidget
Column(
children: [
Text(
"${qty}",
style: TextStyle(),
)
],
),
I want to have these features that make user tab on the value to change it if they want, upon tap, a pop-up dialog will show to give the user the ability to change the existing value to whatever the user wants.
Please if anyone knows how, please help.
You will need a statfull widget to call setState and make the UI update with the new value stored in your qty variable. (I'am assuming that you are not using any state managment).
I wrote a possible solution for what you need.
Let look into some considerations:
Text will show whatever is in the qty as long we call setState after (or do it inside) we change the value of qty.
You need some widget to detect your tap. If you want to the text be 'clicable' then it should be wraped inside that widget.
The onTap/onPress call back of that widget should show a new widget. For this you can use the already made showDialog() and pass it a Dialog Widget. in here you will put your ui for that.
In some point of that UI you need to introduce the new value. So you can use a simple TextField that will save the introduced value, where you can assign it to qty, without forgetting to call setState! Note that it deal with strings, so you neet to do an int.parse() ou double.parse accordingly to you qty var type.
And I think that's it.
The could be other ways of doing it. This is a good and simple approach for your need.
I wrote a piece of code to help or somelse how is trying to do it:
InkWell(
// can be gesture detector, button, etc
onTap: () => showDialog(
context: context,
builder: (context) => Dialog(
child: Container(
color:
Colors.white60, // change it accordingly to you
height: 80, // change it accordingly to you
width: 200, // change it accordingly to you
child: Column(
children: [
const Text('Change your value here'),
TextField(
decoration:
InputDecoration(hintText: qty.toString()),
onChanged: (insertValue) => setState(() {
qty = int.parse(insertValue);
}),
// you can use other callBack function (like onComplete,
// onSaved), wich is more eficient than calling setState eveytime,
// but you have to do the needed adtaptions. Like onSave
// needs a key to call the save function. is easy just google it.
),
],
)),
)),
child: Text(
"${qty}",
),
),
What you are probably looking is a DropdownButton.
You would have something like this:
int qty = 1;
List<int> listOfValues = [1,2,3,4];
and then in your column you would have
DropdownButton<int>(
// This are the list of items that will appear in your dropdown menu.
// items is all the options you want your users to be able to select from,
// and it take a list of `DropdownMenuItem`. So instead of creating a `DropdownMenuItem`
// for each of the items in `listOfValues`, we iterate through it and return
// a `DropdownMenuItem`
items: listOfValues
.map((item) => DropdownMenuItem<int>(
value: item,
child: Text('$item'),
))
.toList(),
value: qty,
onChanged: (value) {
if (value != null) {
setState(() {
qty = value;
});
}
},
),
For more information on DropDownButton, check the following links:
https://api.flutter.dev/flutter/material/DropdownButton-class.html
https://www.youtube.com/watch?v=K8Y7sWZ7Q3s
Note: In a scenario where you want to increase the quantity of an item, like in a shopping cart, maybe having a button increment qty by 1 would be better.

Flutter Listview - Subtitle and DateDiff problem

i need your help :)
I think this is not working... but i mean i can do it with an extra page like a "detailpage" and show the data. Well here is my issue
i have the main screen with a listview.Builder for all my entries.
it just shows an icon, the title(name) and a Date (the Date is in the future that i can define in the add screen)
ok now my problem. i need a Datediff. i dont want to show the future Date (endTime), i want the differnce days between today and the future Date
child: ListTile(
leading: CircleAvatar(
backgroundImage:
AssetImage('asset/veggi.png'), ),
title: Text(vegetableEntry.items[index].title),
onTap: () => Navigator.of(context).pushNamed(vegetableDetailScreen.routeName,
arguments: vegetableEntry.items[index].id),
subtitle: Text(vegetableEntry.items[index].endTime.difference(dateNow2).inDays),
somtehing like:
that i get on my subtitle smth like: Icon/ Title(name) /DaysLeft: 29 (checks everytime on open?)
i'm getting the error:
The method 'difference' isn't defined for the type 'String'.
Try correcting the name to the name of an existing method, or defining a method named 'difference'.
i know i can fix it in the DetailScreen with
DateTime startDate = _pickedStartDate;
DateTime endDate = _pickedEndDate;
final daysLeft = endDate.difference(startDate).inDays;
print(daysLeft);
but i dont think this is possible in the Listview.builder ?
i hope this is understandable and someone can help me
best regards,
and a happy day :)
This actually is possible in ListView.builder. Just do the work in the builder function before you return the ListTile. You can't use (context, index) =>. You'll have to use (context, index) {}.
You can also convert the Timestamp String into a DateTime inline like so
subtitle: Text(DateTime.parse(vegetableEntry.items[index].endTime).difference(dateNow2).inDays.toString(),

Refreshing Dialog In Flutter with Bloc

So I'm trying to pick a date with a DatePicker package from inside a showDialog using Bloc.
Here's the code that shows the Dialog:
onPressed: () {
showDialog(
context: context,
barrierDismissible: true,
child: _buildEditDialog(context, arguments),
);
},
And here's the Dialog's content:
void _openCalendarPicker(BuildContext context, SearchHotelArguments arguments) async {
final DateTime dateTimeNow = DateTime.now();
final List<DateTime> picked = await DateRagePicker.showDatePicker(
context: context,
initialFirstDate: arguments.checkInDate ?? dateTimeNow,
initialLastDate: arguments.checkOutDate ?? dateTimeNow.add(Duration(days: 1)),
firstDate: dateTimeNow,
lastDate: dateTimeNow.add(Duration(days: 365 * 10)));
if (picked != null && picked.length == 2) {
context.read<HotelChangeParamsBloc>().setCheckInDate(picked[0]);
context.read<HotelChangeParamsBloc>().setCheckOutDate(picked[1]);
}
}
Now, the issue here is that from a Dialog I open a popup with the DateRangePicker, pick the Date and submit it but on the Dialog the date stays the same as it was previously. And if I close and re-open the Dialog I can see that there was a change in the date. So the Dialog is not refreshing the data by itself(unless I re-open it).
Does anyone know how I can refresh the Dialog with the new Date from the DateRangePicker?
Edit:
If you're interested in adhering to the intended Bloc pattern, you wouldn't be firing a regular function from your dialog. That's why I said 'assuming you're emitting a new state'.
Ideally it would be
context.read<HotelChangeParamsBloc>().add(UserSelectedDateEvent(setCheckInDate(picked[0])));
In that example UserSelectedDateEvent is an event that passes in a DateTime object that gets emitted to an updated state.
That event would hit the mapEventToState method in your Bloc, emit a new state, and if you wrap your first dialog in a BlocBuilder as mentioned below, it will show the updated date
Original answer:
Assuming that your setCheckInDate() method is emitting a new state in your HotelChangeParamsBloc, you just need to wrap your first dialog in
BlocBuilder<HotelChangeParamsBloc, HotelChangeParamsBlocState>
Then within that, display the updated date with state.yourBlocVariable.toString()
Without the BlocBuilder theres nothing telling it to rebuild so it won't show the updated state until you close and rebuild it.

how to update the FutureBuilder text every time the shared-preference is updated

I wanted to keep the time data stored in the mobile localcaly so when ever the app is closed and open backed i want it to be shown. that part works but when ever the button is pressed to set new time it wont update to the newly set sharedprefence to show instead of the load or the new time.
This is the function that runs every time the button is being pressed
void timeInPush()async{
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
String now =await new DateFormat.yMd().add_Hm().format(new DateTime.now());
String day =await new DateFormat.d().add_Hm().format(new DateTime.now());
sharedPreferences.setString("timeIn", now);
sharedPreferences.setString("timeOut",null);
sharedPreferences.reload();
}
This is the function for the Future builder
Future <String> timeShowtimein()async{
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
return Future.delayed(Duration(seconds: 1),()async{
return await sharedPreferences.getString("timeIn");
});
}
And here is the UI builder
Container timeText(){
return Container(
child:Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FutureBuilder(
future:timeShowtimein() ,
builder: (context, snapshot){
if(snapshot.hasData){
return Text("${snapshot.data}");
}else{
return Text("Loading");
}
}),
SizedBox(
width:20,
),
Text("$Timeout",style:TextStyle(
color: Colors.redAccent,
fontSize: 15.0))
],
)
);
}
Calling timeInPush() sets the values in the Shared Preferences. The problem is that it does not let the FutureBuilder know that changes have occurred.
sharedPreferences.reload() re-syncs the preferences with the native application to make sure that there are no pending changes in the dart side of things (It is stated in the documentation)
Try converting your widget to stateful and call setState(() { }) in the timeInPush() method after setting the values. This might force a rebuild and fire up the future builder again.
The problem is that it might show loading for a frame or two every time the widget rebuilds. You can fix this using initialData property = an additional variable that you might need to update manually every time you set the values in shared prefs but that will just make the code more complex. Moreover, every time you update the sharedPrefs, you will need to call setState to force the rebuild.
I will recommend rx_shared_preferences package. It's built on top of shared_preferences package and has the ability to work with streams. With StreamBuilder, you only need to update the SharedPreferences and the rebuilds inside the stream builder will be made automatically.

How to change displayed data the best way in Flutter

i want to change displayed data in Flutter? I wrote a function changeDataForTest (only a function for testing the event), which should change the data displayed in Text.
But if I click on this, it isn't changed. The value of the displayed string only changes, if i add (context as Element).reassemble(); after calling the method. Is this the normal way to go, or is there a smoother way to solve my problem?
dynamic changeDataForTest(neuerWert) {
this.data = neuerWert;
}
Column(
children: [
Center(
child: Text(
this.data + this.wiegehts,
),
),
FlatButton(
textColor: Color(0xFF6200EE),
onPressed: () {
changeDataForTest('neuerWert');
(context as Element).reassemble();
},
)
],
)
Thanks
Lukas
If you're using only a small widget, you could use a StatefulWidget using the method:
setState(() {
// change your variable
})
If your widget is complex and has lots of different possible variables, I'll not recommend using setState as this method calls the build method every time is being used.
One simple and fast option, is to use ValueNotifier:
final myVariable = ValueNotifier(false); // where you can replace 'false' with any Object
and then, using it this way:
ValueListenableBuilder(
valueListenable: myVariable,
builder: (context, value, child) {
return Text(value); // or any other use of Widgets
},
);
myVariable.value = true; // if you're looking for to change the current value
finally, if you logic is truly complex and you need to scale, I'll recommend to use a StateManagement library like:
Provider
Riverpod
BloC
Others
You can find those libraries and examples over: https://pub.dev