Flutter passing data between screens showing null data after passing - flutter

Hi i was experienced ionic developer but i am new to flutter i was trying to pass data between screens in flutter but when it navigates it shows null value , in debug mode before navigate there is values after navigate it shows null , here is my code please correct my code thanks.
Screen 1
import 'package:flutter/material.dart';
import 'package:date_field/date_field.dart';
import 'package:headletter/screens/Add_horoscope/marriage_info.dart';
class AddBasicInfo extends StatefulWidget {
const AddBasicInfo({Key? key}) : super(key: key);
#override
_AddBasicInfoState createState() => _AddBasicInfoState();
}
class _AddBasicInfoState extends State<AddBasicInfo>{
#override
void initState() {
super.initState();
}
Widget build(BuildContext context) {
return MaterialApp()....
bottomNavigationBar: BottomAppBar(
child: GestureDetector(
onTap: (){
final data1 = [
{
"Name": inputName.text,
"Gender": _selectedGender,
"DOB":dobDate,
"DobTime":dobTime,
"Place": birthPlace.text,
"Landmark": landmark.text,
"birthNo": _selectedChild
}
];
final String passingValue = "checking for passing";
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
MarriageInfo(passingValue: passingValue)),
);
}
}
},
Screen 2
class MarriageInfo extends StatefulWidget {
final String passingValue;
const MarriageInfo({Key? key, required this.passingValue}) : super(key: key);
#override
_MarriageInfoState createState() => _MarriageInfoState();
}

Far now this is correct but while using passingValue on Screen2 you have to use widget.passingValue
e.g. print(widget.passingValue);

you are using statefulwidget
You can describe constructor of statefullwidget like that
final String passingValue;
const MarriageInfo(this.number);
and than you can excess this value by
widget.passingValue

You should use widget.passingValue instead of just that variable name.
The property is assigned to that widget, not to that state class.

Related

create: (_) => AboutBloc(widget.seed)..add(CallforAbout()) not Working in flutter

I want to fire Bloc Event when Screen loads but ..add is not working , also tried using initState() still State is intial.
Also used MultiblocProvider it works but in multiBlocProvider cant pass aurgumnets Required to call API.
class AboutThisProfile extends StatefulWidget {
String seed;
AboutThisProfile({
Key? key,
required this.seed,
}) : super(key: key);
#override
_AboutThisProfileState createState() => _AboutThisProfileState();
}
class _AboutThisProfileState extends State<AboutThisProfile> {
Widget build(BuildContext context) {
return BlocProvider<AboutBloc>(
create: (_) => AboutBloc(widget.seed)..add(CallforAbout()),
child: AboutScafold(
seed: widget.seed,
),
);
}
}

how can i call setState from difference class

FLUTER DART
I have two files like this
one is stful class like this
class Test extends StatefulWidget {
const Test({Key? key}) : super(key: key);
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
#override
Widget build(BuildContext context) {
return TextButton(
onPressed: () {
updateField() // here i call function from other page
},
child: null,
);
}
}
and one is function into other file or page like this
updateField()async{
FirebaseFirestore.instance.collection("users").doc(currentUser.uid).update({
"faceType" : currentUser.faceType ,
});
setState(() {
currentUser.faceType= faceType;
});
}
but once i use setstate it says setstate is not defined , how can i use it please
thanks
Make sure you're calling setState within the stateful widget.
The setState is a method available within only Stateful widgets.
Anyone outside the stateful widget is just a custom method you wrote.
That being said you can use a state management library of your choice and you'll be able to easily change different states within your stateful widget.
The best part is that the logic code would not have to be within the UI.
You should have a function in the Statefull widget that handles SetState Cases.
and within this function you call whatever functions in other files of your project.
So, in your case you can have a function in the Statfull widget as follows:
class Test extends StatefulWidget {
const Test({Key? key}) : super(key: key);
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
_updateScreen() async {
try{
await updateField();
setState(() {
// handle the new state with Provider or whatever you prefer
});
}catch(error){
// handle errors
}
}
#override
Widget build(BuildContext context) {
return TextButton(
onPressed: () {
_updateScreen()
},
child: null,
);
}
}
and the other file could has the function as follows:
updateField()async{
FirebaseFirestore.instance.collection("users").doc(currentUser.uid).update({
"faceType" : currentUser.faceType ,
});
}

keeping repository instance "alive" with bloc

I am still with my first bloc based app, adding features. While previously, I stored some of my page specific data with the bloc class, for the last feature, I now moved most variables into its repository. I already feared that the instance of calling the repository gets lost, afterwards, which now proved true.
Is there a proper, easy way to make the instance persistent?
I know of inherited widgets, however, I have not yet figured out how to implement this and my question around this unfortunately remained unanswered. It would be great, if someone could point me to some direction!
In general, my idea was to have the api dealing with local files and online data, the repository with frequently re-used data (session data, presented data etc) and helper variables within the bloc. So when the UI requests data, the bloc asks the repository which will either return a value stored in a variable or request a value from the api.
This is, how the strucuture basically looks like (hope I have not missed anything significant)
void main() async {
final UserRepository userRepository = UserRepository(); // <===== userRepository initialized
runApp(MyApp(userRepository: UserRepository()));
}
class MyApp extends StatelessWidget {
MyApp({Key key, this.userRepository}) : assert(userRepository != null), super(key: key);
final UserRepository userRepository;
#override
Widget build(BuildContext context) {
return BlocProvider<UserBloc>( <====== userBloc injection to top of widget tree
create: (_) => UserBloc(userRepository: userRepository)..add(AppStarted()),
child: App(),
);
}
}
// =================================================== APP WITH ROUTES
class App extends StatelessWidget {
App({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return CupertinoApp(
routes: {
'/': (_) => HomePage(),
'feature 1': (_) => HomePage(),
},
);
}
}
// =================================================== LANDING PAGE WITH MAIN MENU
class HomePage extends StatefulWidget {
HomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('MathUup'),
),
child: SafeArea(
child: CupertinoButton(
child: Text('Feature 1',
onPressed: () => Navigator.pushNamed(context, 'feature 1'),
),)));
}}
// =================================================== BLOC
class UserBloc extends Bloc<UserEvent, UserState> {
UserBloc({this.userRepository}) : super(AppInitial());
final UserRepository userRepository;
...
final user = await userRepository.getActiveUserData(userId);
final lastSessionData = await userRepository.getLastSession(userId);
...
}
// =================================================== REPOSITORY
class UserRepository {
UserRepository();
final UserApiClient achievementsApiClient = UserApiClient();
final SessionsApiClient sessionsApiClient = SessionsApiClient();
UserSession activeUserSession;
User activeUserData;
Future<String> getLastUserId() async {
final lastUserId = await sessionsApiClient.getLastUserId();
return lastUserId;
}
Future<UserSession> getActiveUser() async {
if (activeUserSession == null) {
activeUserSession = await sessionsApiClient.getLastUser();
}
return activeUserSession;
}
}
This line is creating and initializing your user repository:
final UserRepository userRepository = UserRepository(); // <===== userRepository initialized
However, this line is not passing that repository, it's creating a new repository, ignoring the one you just initialized:
runApp(MyApp(userRepository: UserRepository()));
I think you meant to use the variable you already have:
runApp(MyApp(userRepository: userRepository));

use passed data before build method flutter

I'm trying to access the information I've passed over from a previous class before the build method begins. But it's saying only static members can be accessed in initializers. I don't really want to use the static property, partially because I wouldn't know how to use it, but also because I think it seems unnecessary. In previous pages I've been able to access the data but only after the build method, does anyone know how I can access it before? Thanks all
class FirstPage extends StatefulWidget {
#override
_FirstPageState createState() => _FirstPageState();
}
class _FirstPageState extends State<FirstPage> {
List<MyProvider> myList;
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: myList.length,
itemBuilder: (context, index) {
String imgPath = myList[index].image;
String myTextPath = myList[index].name;
String locationNamePath = myList[index].location;
double distancePath = myList[index].distance;
String myName = '${myTextPath} ''${locationNamePath}';
return MyCard(
locationText: locationNamePath,
myText: myTextPath,
assetImage: Image.network(imgPath),
function: (){
Provider.of<Data>(context, listen: false).addLogo(Image.network(imgPath));
Navigator.push(context, MaterialPageRoute(builder: (context) => SecondPage(myName: myName,)));
},
);
}),
);
}
}
My next page accesses the data using a key but it seems not to be able to use it before the build method, and that's what I need to get around!
class SecondPage extends StatefulWidget {
final String myName;
const SecondPage({Key key, this.myName})
: super(key: key);
#override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> with TickerProviderStateMixin {
final CollectionReference myItemsReference = Firestore.instance.collection('${widget.myName}');
// This is where the error is
#override
Widget build(BuildContext context) {
return Scaffold();
}
}
Use the initState method for anything related to initialization of State. See this for more on initState.
Example:
CollectionReference myItemsReference;
#override
void initState() {
myItemsReference = Firestore.instance.collection('${widget.myName}');
}

Passing data to StatefulWidget and accessing it in it's state in Flutter

I have 2 screens in my Flutter app: a list of records and a screen for creating and editing records.
If I pass an object to the second screen that means I am going to edit this and if I pass null it means that I am creating a new item. The editing screen is a Stateful widget and I am not sure how to use this approach https://flutter.io/cookbook/navigation/passing-data/ for my case.
class RecordPage extends StatefulWidget {
final Record recordObject;
RecordPage({Key key, #required this.recordObject}) : super(key: key);
#override
_RecordPageState createState() => new _RecordPageState();
}
class _RecordPageState extends State<RecordPage> {
#override
Widget build(BuildContext context) {
//.....
}
}
How can I access recordObject inside _RecordPageState?
To use recordObject in _RecordPageState, you have to just write widget.objectname like below
class _RecordPageState extends State<RecordPage> {
#override
Widget build(BuildContext context) {
.....
widget.recordObject
.....
}
}
Full Example
You don't need to pass parameters to State using it's constructor.
You can easily access these using widget.myField.
class MyRecord extends StatefulWidget {
final String recordName;
const MyRecord(this.recordName);
#override
MyRecordState createState() => MyRecordState();
}
class MyRecordState extends State<MyRecord> {
#override
Widget build(BuildContext context) {
return Text(widget.recordName); // Here you direct access using widget
}
}
Pass your data when you Navigate screen :
Navigator.of(context).push(MaterialPageRoute(builder: (context) => MyRecord("WonderWorld")));
class RecordPage extends StatefulWidget {
final Record recordObject;
RecordPage({Key key, #required this.recordObject}) : super(key: key);
#override
_RecordPageState createState() => new _RecordPageState(recordObject);
}
class _RecordPageState extends State<RecordPage> {
Record recordObject
_RecordPageState(this. recordObject); //constructor
#override
Widget build(BuildContext context) {. //closure has access
//.....
}
}
example as below:
class nhaphangle extends StatefulWidget {
final String username;
final List<String> dshangle;// = ["1","2"];
const nhaphangle({ Key key, #required this.username,#required this.dshangle }) : super(key: key);
#override
_nhaphangleState createState() => _nhaphangleState();
}
class _nhaphangleState extends State<nhaphangle> {
TextEditingController mspController = TextEditingController();
TextEditingController soluongController = TextEditingController();
final scrollDirection = Axis.vertical;
DateTime Ngaysx = DateTime.now();
ScrollController _scrollController = new ScrollController();
ApiService _apiService;
List<String> titles = [];
#override
void initState() {
super.initState();
_apiService = ApiService();
titles = widget.dshangle; //here var is call and set to
}
I have to Navigate back to any one of the screens in the list pages but when I did that my onTap function stops working and navigation stops.
class MyBar extends StatefulWidget {
MyBar({this.pageNumber});
final pageNumber;
static const String id = 'mybar_screen';
#override
_MyBarState createState() => _MyBarState();
}
class _MyBarState extends State<MyBar> {
final List pages = [
NotificationScreen(),
AppointmentScreen(),
RequestBloodScreen(),
ProfileScreen(),
];
#override
Widget build(BuildContext context) {
var _selectedItemIndex = widget.pageNumber;
return Scaffold(
bottomNavigationBar: BottomNavigationBar(
elevation: 0,
backgroundColor: Colors.white,
unselectedItemColor: Colors.grey.shade700,
selectedItemColor: Color(kAppColor),
selectedIconTheme: IconThemeData(color: Color(kAppColor)),
currentIndex: _selectedItemIndex,
type: BottomNavigationBarType.fixed,
onTap: (int index) {
setState(() {
_selectedItemIndex = index;
});
},
You should use a Pub/Sub mechanism.
I prefer to use Rx in many situations and languages. For Dart/Flutter this is the package: https://pub.dev/packages/rxdart
For example, you can use a BehaviorSubject to emit data from widget A, pass the stream to widget B which listens for changes and applies them inside the setState.
Widget A:
// initialize subject and put it into the Widget B
BehaviorSubject<LiveOutput> subject = BehaviorSubject();
late WidgetB widgetB = WidgetB(deviceOutput: subject);
// when you have to emit new data
subject.add(deviceOutput);
Widget B:
// add stream at class level
class WidgetB extends StatefulWidget {
final ValueStream<LiveOutput> deviceOutput;
const WidgetB({Key? key, required this.deviceOutput}) : super(key: key);
#override
State<WidgetB> createState() => _WidgetBState();
}
// listen for changes
#override
void initState() {
super.initState();
widget.deviceOutput.listen((event) {
print("new live output");
setState(() {
// do whatever you want
});
});
}
In my app, often instead of using stateful widgets, I use mainly ChangeNotifierProvider<T> in main.dart, some model class
class FooModel extends ChangeNotifier {
var _foo = false;
void changeFooState() {
_foo = true;
notifyListeners();
}
bool getFoo () => _foo;
}
and
var foo = context.read<FooModel>();
# or
var foo = context.watch<FooModel>();
in my stateless widgets. IMO this gives me more precise control over the rebuilding upon runtime state change, compared to stateful widgets.
The recipe can be found in the official docs, the concept is called "lifting state up".