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,
),
);
}
}
Related
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.
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 ,
});
}
I am using the ScopedModel pattern, but I am also interested how this same problem is addressed in the similar Provider pattern.
Currently I have a ScopedModel with a bool exposed called loggedIn. When the FirebaseonAuthStateChanged stream changes user log in state, my ScopedModel changes that bool, and calls NotifyListeners. All straight forward stuff.
Now I am confused as to the best way to push or pop routes based on this ScopedModel.
Should all my logged in screens (screens that require a user) have the following code in build method?
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!auth.hasUser)
Navigator.of(context).pushNamedAndRemoveUntil('/entry', (Route<dynamic> route) => });
});
That seems a little excessive to have this code on every single screen. Is there a way I can define this log screen change behaviour somewhere only once?
create a Widget for it ;)
class Validation extends StatefulWidget {
final Function validator;
final Widget child;
const Validation({Key key, this.validator, this.child}) : super(key: key);
#override
_ValidationState createState() => _ValidationState();
}
class _ValidationState extends State<Validation> {
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
widget.validator();
});
super.initState();
}
#override
Widget build(BuildContext context) {
return widget.child;
}
}
now use it everywhere
#override
Widget build(BuildContext context) {
return Validation(
validator: (){
if (!auth.hasUser){
Navigator.of(context).pushNamedAndRemoveUntil('/entry', (Route<dynamic> route) => false);
}
},
child: MyAwesomePage(),
);
}
you can further simplify if the validation is same everywhere or create multiple validation widget according to the validations required,
FOR YOUR CASE
class LoginValidation extends StatefulWidget {
final String routeIfNotLoggedIn;
final Widget child;
const LoginValidation({Key key, this.routeIfNotLoggedIn, this.child}) : super(key: key);
#override
_LoginValidationState createState() => _LoginValidationState();
}
class _LoginValidationState extends State<LoginValidation> {
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
if (!auth.hasUser){
Navigator.of(context).pushNamedAndRemoveUntil(widget.routeIfNotLoggedIn, (Route<dynamic> route) => false);
}
});
super.initState();
}
}
and use it
#override
Widget build(BuildContext context) {
return LoginValidation(
routeIfNotLoggedIn: "/myLoginRoute",
child: MyAwesomePage(),
);
}
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));
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}');
}