I am pulling data from Firestore and Editing, and when I click on the data to edit, I don't see it showing anything, however when I write the information and Save. Instead of changing the Edited Field, I get a new document with the edited field.
For example in the code, I edit the name => I will have a new document with the email reused and name changed.
And here is my code:
class EditHouse extends StatefulWidget {
final House house;
EditHouse(this.house);
class _EditHouseState extends State<EditHouse> {
final nameController = TextEditingController();
final emailController = TextEditingController();
#override
void dispose() {
nameController.dispose();
emailController.dispose();
super.dispose();
}
#override
void initState() {
if (widget.house == null) {
nameController.text == "";
emailController.text == "";
new Future.delayed(Duration.zero, () {
final houseProvider =
Provider.of<HouseProvider>(context, listen: false);
houseProvider.loadValues(House(
name: '',
email: ''));
});
} else {
nameController.text = widget.house.name;
emailController.text = widget.house.email;
new Future.delayed(Duration.zero, () {
final houseProvider =
Provider.of<HouseProvider>(context, listen: false);
houseProvider.loadValues(widget.house);
});
}
super.initState();
}}
I don't know if the problem lies here or not EditHouse(this.house);
when I can't use it EditHouse([required this.house]); I will get an error message Can't have modifier 'required' here
Related
I have two files, in the first are a few TextformFields and in the second are buttons. I wanna disable the button when one of the TextformFields is empty.
File 1:
class FormTextState extends State<FormText>{
final TextEditingController inputController1 = TextEditingController();
final TextEditingController inputController2 = TextEditingController();
final TextEditingController inputController3 = TextEditingController();
bool submit1 = false;
bool submit2 = false;
bool submit3 = false;
#override
void initState(){
super.initState();
inputController1.addListener(() { setState(() {
submit1 = inputController1.text.isNotEmpty;
});
});
inputController2.addListener(() { setState(() {
submit2 = inputController2.text.isNotEmpty;
});
});
inputController3.addListener(() { setState(() {
submit3 = inputController3.text.isNotEmpty;
});
});
}
#override
void dispose(){
inputController1.dispose();
inputController2.dispose();
inputController3.dispose();
super.dispose();
[...]
}
For each TextFormField the controller is defined as following:
TextFormField(
controller: inputController1,
If I would create the button directly in this file, everything works fine like that:
ElevatedButton(
onPressed: submit1 && submit2 && submit3 ? () => doSomething() : null,
How can I reach this result from the other file with the buttons? The submit values are not reachable. I imported the file at the beginning, of course.
You could add a function to your class like:
class FormTextState extends State<FormText>{
final Function(String str) stringHandler;
...
and when creating the class
FormTextState(stringHandler: _handler);
Future<void> _handler(String str) async {
print(str);
}
you nee to use the following porperties
autovalidateMode: AutovalidateMode.onUserInteraction
onChanged: (val) {
if (formKey.currentState?.validate() == true) {
BlocProvider.of<MyDataBloc>(context)
.add(ActivateButtonEvent());
} else {
BlocProvider.of<MyDataBloc>(context)
.add(DeActivateButtonEvent());
}
},
this will work for formtextfield in case that you are using bloc
Can someone explain to me where I am wrong? I am programming this application and, working with sqflite, I have had this kind of problem several times when I use the readPlayer() function.
class matchesRow extends StatefulWidget {
final List matches;
final List results;
final int index;
matchesRow({
Key? key,
required this.index,
required this.matches,
required this.results,
}) : super(key: key);
#override
State<matchesRow> createState() => _matchesRowState();
}
class _matchesRowState extends State<matchesRow> {
late Player gP1;
late Player gP2;
bool ripescato = false;
PlayersDatabase pb = PlayersDatabase.instance;
#override
void initState() {
super.initState();
getPlayers();
}
#override
void dispose() {
PlayersDatabase.instance.close();
super.dispose();
}
Future getPlayers() async {
List<dynamic> duel = widget.matches[widget.index];
gP1 = await pb.readPlayer(duel[0]);
print(gP1);
gP2 = await pb.readPlayer(duel[0]);
if (duel[1] == "R") {
ripescato = true;
} else {
gP2 = await pb.readPlayer(duel[1]);
}
}
#override
Container build(BuildContext context) {
var icon = Icons.code_sharp;
return Container(child: Text(gP1.name));
}}
This is the function ReadPlayer()
Future<Player> readPlayer(int id) async {
final db = await instance.database;
final maps = await db.query(
tablePlayers,
columns: PlayerFields.values,
where: '${PlayerFields.id} = ?',
whereArgs: [id],
);
if (maps.isNotEmpty) {
return Player.fromJson(maps.first);
} else {
throw Exception('ID $id not found');
}
I don't understand why even if I declare the value of gP1 and gP2 in getPlayers() the error still pop up.
gP1 and gP2 getting from future method. It will take some time to fetch data from future method getPlayers. Use FutureBuilder or make it nullable
For nullable case it will be
Player? gP1;
Player? gP2;
#override
void initState() {
super.initState();
getPlayers().then((value) {
//update Ui after getting data
setState(() {});
});
}
And use case with default value on null case
Text(gP1?.name??"didnt get yet")
I wanna ask how to save state from textfield? cause i can't saving this state, after hot restart my value always reset, i just want to save state after hot restart, can i know my problem where it's wrong?
it's my code:
class HomePage extends StatefulWidget {
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
TextEditingController nameController = TextEditingController();
var nama = 'nama';
void setPref() async {
var prefs = await SharedPreferences.getInstance();
prefs.setString(nama, nameController.text);
}
void load() async {
var prefs = await SharedPreferences.getInstance();
setState(() {
nama = prefs.getString(nameController.text) ?? '';
nameController.text = nama;
});
}
#override
void initState() {
// TODO: implement initState
super.initState();
load();
}
#override
Widget build(BuildContext context) {
.....
}
}
There is a problem in your code:
In shared Prefrences you have to use key to store and get value.
But you are using it in wrong way:
Here is correct code:
void load() async {
var prefs = await SharedPreferences.getInstance();
String value = '';
setState(() {
value= prefs.getString(nama) ?? '';
nameController.text = value;
});
}
The nama is a key name and you are also using it to receive value. And the key you are using is nameController.text is also wrong.
Bonus
The convection of writing keys in Flutter is Following:
String nameKey = 'NAMEKEY';
I pass the value of both userProfileID And ,userstype to Profilepage() as shown below but when i go to profile page and I try to print the value of both this variable I will get Null value, I think they Actually not passed from this _HomePageState, anyone help?
Here is Where I pass the Value of both
userProfileID as a UserID and userstype as UserTypes inside initState() below,
and both UserID and UserTypes are Obtained from SharedPrefrence
(I call GetData to obtain the value of UserID and UserTypes from SharedPreference )
class _HomePageState extends State<HomePage> {
String UserID;
String UserTypes;
List<Widget>_children;
bool isSignedIn= false;
int _CurrentIndex=0;
void initState(){
super.initState();
GetData();
_children=[
TimeLinePage(UsersIdTimeline:UserID,UsersTypeTimeline:UserTypes),
SearchPage(searchUserSID: UserID,searchUsertype:UserTypes), //search(),
UploadPage(uploadUserSID:UserID,uploadUsertype: UserTypes),
NotificationsPage(NotifyUserSID: UserID,NotifyUsertype:UserTypes),
ProfilePage(userProfileID:UserID,userstype:UserTypes),
];
if(FirebaseAuth.instance.currentUser!=null){
setState(() {
isSignedIn= true;
});
}else{
setState(() {
isSignedIn= false;
});
}
}
#override
Widget build(BuildContext context) {
if(isSignedIn){
return buildHomeScreen();
} else{
return buildSignedInScreen();
}
}
void GetData()async {
SharedPreferences preferences= await SharedPreferences.getInstance();
setState(() {
UserID=preferences.get('UserId');
UserTypes=preferences.get('UserType');
});
}
}
here is buildHomeScreen
class _HomePageState extends State<HomePage> {
// ignore: non_constant_identifier_names
String UserID;
String UserTypes;
List<Widget>_children;
List<Widget>_agentchildren;
bool isSignedIn= false;
// ignore: non_constant_identifier_names
int _CurrentIndex=0;
int _agentCurrentIndex=0;
void initState(){
super.initState();
GetData();
_children=[
TimeLinePage(UsersIdTimeline:UserID,UsersTypeTimeline:UserTypes),
SearchPage(searchUserSID: UserID,searchUsertype:UserTypes),
UploadPage(uploadUserSID:UserID,uploadUsertype:UserTypes),
NotificationsPage(NotifyUserSID: UserID,NotifyUsertype:UserTypes),
ProfilePage(userProfileID:UserID,userstype:UserTypes),
];
if(FirebaseAuth.instance.currentUser!=null){
setState(() {
isSignedIn= true;
});
}else{
setState(() {
isSignedIn= false;
});
}
}
#override
Widget build(BuildContext context) {
if(isSignedIn){
if(UserTypes=='agent'){
return buildagentScreen();
} else if(UserTypes== 'Signupuser'||
UserTypes== 'owner'||
UserTypes== 'seller'
){
return buildHomeScreen();
}else{
return buildSignedInScreen();
}
}
}
Here is My ProfilePage(), if I try to get the value of both
( String userstype; String userProfileID;) in this page
i get Null value but I alredy pass the value of them from the above _HomePageState()
class ProfilePage extends StatefulWidget {
String userstype;
String userProfileID;
ProfilePage({this.userProfileID, this.userstype});
#override
_ProfilePageState createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
final String CurrentOnlineUserID=curentuser?.uid;
bool loading =false;
int countPost=0;
String postOrientation="grid";
List<Post> PostList=[];
void initState(){
getAllProfilePost();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar:header(context,strTitle:"profile"),
body:ListView(
children:<Widget>[
TopView(),
]
),
);
}
Use shared preferences globally for your application.
import 'dart:async' show Future;
import 'package:shared_preferences/shared_preferences.dart';
class PreferenceUtils {
static Future<SharedPreferences> get _instance async => _prefsInstance ??= await SharedPreferences.getInstance();
static SharedPreferences _prefsInstance;
// call this method from iniState() function of mainApp().
static Future<SharedPreferences> init() async {
_prefsInstance = await _instance;
return _prefsInstance;
}
static String getString(String key, [String defValue]) {
return _prefsInstance.getString(key) ?? defValue ?? "";
}
static Future<bool> setString(String key, String value) async {
var prefs = await _instance;
return prefs?.setString(key, value) ?? Future.value(false);
}
}
Please follow this link
https://stackoverflow.com/a/61046061/8218866
When the _HomePageState is created, the initState is called, and so this line:
_children=[
[...],
ProfilePage(userProfileID:UserID,userstype:UserTypes),
];
This line is creating the object of a ProfilePage with the desired UserID's and UserTypes. This ProfilePage object will be put inside the _children list.
When you do this:
setState(() {
UserID=preferences.get('UserId');
UserTypes=preferences.get('UserType');
});
You are 1) calling the build method again, and 2) updating the value of UserID and UserTypes. You did not change the value of any itens inside the _childrens list. Or the list itself. Hence the misbehavior you noticed.
There are many ways to solve this, but the essence would be to move this list declaration inside the build method. An example:
#override
Widget build(BuildContext context) {
_children = [.....]
if(isSignedIn){
[...]
Doing this way would not be a pretty way to do it, because you are creating lots of new (and useless) objets every time the build method is called. Maybe in a small application this wouldn't be a problem, and for didactic reasons I chose to show this way in this answer.
The more correct way would be to :
Switch and instantiate inside buildHomeScreen the body object:
Scaffold buildHomeScreen(){
Widget body;
switch (_currentIndex) {
case 0:
body =
TimeLinePage(UsersIdTimeline:UserID,UsersTypeTimeline:UserTypes);
break;
case 1:
body = ...;
break;
}
return Scaffold(
...
body: body,
...
)
}
Which should give you the same result.
Recently I am developing first ever app in Flutter and I know the basics only.
So here's the problem which I am facing currently.
I have to Navigate One of the two screens, either Register or Home page according to old/new user, So what I did is here.
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'Register.dart';
import 'HomePage.dart';
class Authenticate extends StatefulWidget {
#override
_AuthenticateState createState() => _AuthenticateState();
}
class _AuthenticateState extends State<Authenticate> {
String _userName = "";
#override
void initState() {
super.initState();
_getUserName();
}
_getUserName() async {
SharedPreferences pref = await SharedPreferences.getInstance();
setState(() {
_userName = pref.getString('userName') ?? "";
});
}
Widget build(BuildContext context) {
if (_userName == "") {
print('name : $_userName , NEW user'); // ERROR - why it's printing on console for old User ?
return Register();
} else {
return HomePage(_userName);
}
}
}
So the problem is, even if I am opening app through old user, it is printing the debug code written for new user and there's around 0.3 sec screen visibility of Register screen.
So what should I do to fix this?
The print is happening because this line of code:
SharedPreferences pref = await SharedPreferences.getInstance();
is asynchronous, which means that it might invoke in some later point in time. Because of that the build method is called first, then your _getUserName method finished, which causes a setState and invokes a build method again.
You might want to show some kind of loader screen until sharedPrefernces is initialized and then decide wheter to show Register or Home page.
Example code:
class _AuthenticateState extends State<Authenticate> {
String _userName = "";
bool _isLoading = true;
#override
void initState() {
super.initState();
_getUserName();
}
_getUserName() async {
SharedPreferences pref = await SharedPreferences.getInstance();
setState(() {
_userName = pref.getString('userName') ?? "";
_isLoading = false;
});
}
Widget build(BuildContext context) {
if (_isLoading) {
return Center(child: CupertinoActivityIndicator());
} else if (_userName == "") {
print('name : $_userName , NEW user'); // ERROR - why it's printing on console for old User ?
return Register();
} else {
return HomePage(_userName);
}
}
}
Try this:
class _AuthenticateState extends State<Authenticate> {
String _userName;
#override
void initState() {
super.initState();
_getUserName();
}
_getUserName() async {
SharedPreferences pref = await SharedPreferences.getInstance();
setState(() {
_userName = pref.getString('userName') ?? '';
});
}
Widget build(BuildContext context) {
if (_userName == null) {
return Center(child: CircularProgressIndicator());
} else if (_userName == '') {
print('name : $_userName , NEW user');
return Register();
} else {
return HomePage(_userName);
}
}
}
In this case, _userName is null initially and will only be assigned a value after the _getUserName() returns either an empty String or an old userName. When null, the widget will build a progress indicator instead. If you don't want that, just return a Container().