Edit form in flutter with getx - flutter-getx

im new for both flutter and getx and i'm trying to make edit Form with getx , but i get Null .. how to fill TextEditingController after api response
class EditMarketerController extends GetxController {
final DashboardApiProvider dashboardApiProvider;
EditMarketerController({required this.dashboardApiProvider});
MarketerToEdit marketer = MarketerToEdit();
TextEditingController usernameController =
TextEditingController();
TextEditingController emailController =
TextEditingController();
#override
void onInit() {
_getMarketer(); //----- **api call**
// Wait until the completion of the data call and then fill ↓↓↓
final usernameController = TextEditingController(text:
marketer.username);
final emailController = TextEditingController(text:
marketer.email);
super.onInit();
}

Use callBack in your _getMarketer method like this.
_getMarketer({Function? callBack}){
/// implement your api and put callBack in your api call success like this
if(callBack != null){
callBack();
}
}

Related

Flutter TextEditingController.txt not updating on first build

I am trying to clean up my code a lot. I have a form that I realise I use multiple times in my app. So I wanted to turn the form into its own stateful widget so I could easily re-use it. Unfortunately this is proving more difficult than I thought.
The form is first used in the app to add items. I then want to re-use that same form to edit items and change values in those text fields.
I call the new widget that I created:
body: const GearForm(
onSaveFunctionType: 'add',
itemID: 'none',
itemManufacturer: 'hi',
itemName: '',
itemType: 'test',
itemVolume: '',
itemWeight: '',
packCategory: '',
tempRating: '',
),
If I am passing arguments into the widget though they do not show up in the form when I am testing:
class GearForm extends StatefulWidget {
const GearForm(
{Key? key,
required this.onSaveFunctionType,
required this.itemID,
required this.itemName,
required this.itemManufacturer,
required this.itemType,
required this.packCategory,
required this.itemWeight,
required this.tempRating,
required this.itemVolume})
: super(key: key);
final String onSaveFunctionType;
final String itemID;
final String itemName;
final String itemManufacturer;
final String itemType;
final String packCategory;
final String itemWeight;
final String tempRating;
final String itemVolume;
#override
State<GearForm> createState() => _GearFormState();
}
//define category stream stream
Stream<DocumentSnapshot<Map<String, dynamic>>> streamUserCategories() {
FirebaseFirestore db = FirebaseFirestore.instance;
String userID = FirebaseAuth.instance.currentUser!.uid;
return db.collection('UserPackCategoryList').doc(userID).snapshots();
}
class _GearFormState extends State<GearForm> {
FirebaseAnalytics analytics = FirebaseAnalytics.instance;
FirebaseFirestore db = FirebaseFirestore.instance;
String userID = FirebaseAuth.instance.currentUser!.uid;
//text editing controllers
TextEditingController itemNameController = TextEditingController();
TextEditingController manufacturerController = TextEditingController();
TextEditingController itemTypeController = TextEditingController();
TextEditingController packCategoryController = TextEditingController();
TextEditingController itemWeightController = TextEditingController();
TextEditingController temperatureRatingController = TextEditingController();
TextEditingController volumeController = TextEditingController();
#override
Widget build(BuildContext context) {
//get entitlements from revenue cat
final Entitlement entitlement =
Provider.of<RevenueCatProvider>(context).entitlement;
print(widget.itemManufacturer);
//set initial controller values
itemNameController.text = widget.itemName;
manufacturerController.text = widget.itemManufacturer;
itemTypeController.text = widget.itemType;
packCategoryController.text = widget.packCategory;
itemWeightController.text = widget.itemWeight;
temperatureRatingController.text = widget.tempRating;
volumeController.text = widget.itemVolume;
The odd part is if I did a cmd+s in visual studio code then all the value would magically appear. Since the Cmd+s worked I thought it was showing the values on rebuild so I tried wrappign everythign in setState:
#override
Widget build(BuildContext context) {
//get entitlements from revenue cat
final Entitlement entitlement =
Provider.of<RevenueCatProvider>(context).entitlement;
print(widget.itemManufacturer);
setState(() {
//set initial controller values
itemNameController.text = widget.itemName;
manufacturerController.text = widget.itemManufacturer;
itemTypeController.text = widget.itemType;
packCategoryController.text = widget.packCategory;
itemWeightController.text = widget.itemWeight;
temperatureRatingController.text = widget.tempRating;
volumeController.text = widget.itemVolume;
});
but that didnt fix the issue either...
Update:
I did soem further troubleshooting and tried initState:
#override
void initState() {
super.initState();
print(widget.itemManufacturer);
itemNameController.text = widget.itemName;
manufacturerController.text = widget.itemManufacturer;
itemTypeController.text = widget.itemType;
packCategoryController.text = widget.packCategory;
itemWeightController.text = widget.itemWeight;
temperatureRatingController.text = widget.tempRating;
volumeController.text = widget.itemVolume;
//set initial controller values
}
What is super odd here is that my print(widget.itemManufacturer); works fine and I see the correct value. But it is not being assigned to the manufacturerController.text = widget.itemManufacturer; a few lines down.
Use initState or you can use late
late TextEditingController itemNameController =
TextEditingController.fromValue(TextEditingValue(text: widget.itemName));
The reason why the value were not showing in my form fields was because I am using autocomplete. Autocomplete upon further research has an initial Value field:
initialValue: TextEditingValue(text: manufacturerController.text),
Once I used that initalValue field all updated accordingly.

how to check if a variable was changed in flutter?

his is my save function
ManageFiles c = MangeFiles();
TextEditingController code = TextEditingController();
autoSave(){
c.saveTXT(code.text);
}
I wish every time a user types a word run and save, but I don't know how to implement it
To save your user's input each time he types anything just simply use onChanged method in your TextField to call your method. It will invoke it each time new value is typed
OR
You can use TextEditingController and add a listener to it. It will be invoked when its value is changed
sample:
late final TextEditingController _textEditing;
#override
void initState() {
_textEditing = TextEditingController();
_textEditing.addListener(() {
final String value = _textEditing.value.text;
// YOUR CODE
});
super.initState();
}

flutter throws null exception when setting shared preferences

hello I am currently learning about streams in flutter and I came across a timer application. that involves me storing data using shared preferences. I have a thrown exception when I try to store the default preference to the phone I traced it back to this code block:
readSettings() async {
prefs = await SharedPreferences.getInstance();
int workTime = prefs.getInt(WORKTIME);
if (workTime == null) {
await prefs.setInt(WORKTIME, int.parse('30'));
}
int shortBreak = prefs.getInt(SHORTBREAK);
if (shortBreak == null) {
await prefs.setInt(SHORTBREAK, int.parse('5'));
}
int longBreak = prefs.getInt(LONGBREAK);
if (longBreak == null) {
await prefs.setInt(LONGBREAK, int.parse('20'));
}
setState(() {
txtWork.text = workTime.toString();
txtShort.text = shortBreak.toString();
txtLong.text = longBreak.toString();
});
}
this is the error I recieve:
Exception has occurred.
NoSuchMethodError (NoSuchMethodError: The setter 'text=' was called on null.
Receiver: null
Tried calling: text="30")
I think that most likely your error is not caused by SharedPreferences.
Also assuming that txtWork.text is a textEditingController.
Go up to where you defined TextEditingController textWork;
and change them to this:
TextEditingController textWork = TextEditingController ();
TextEditingController txtLong = TextEditingController ();
TextEditingController txtShort = TextEditingController ();
It should work, please update on what happens.
I think that txtWork the object that have .text is null
so you are trying to do this:
null.text = "30"
Check where you instantiate it.
I managed to do it by moving my textEditing controllers out of my intiState function
old code:
void initState() {
TextEditingController txtWork = TextEditingController();
TextEditingController txtShort = TextEditingController();
TextEditingController txtLong = TextEditingController();
readSettings();
super.initState();
}
new code:
TextEditingController txtWork = TextEditingController();
TextEditingController txtShort = TextEditingController();
TextEditingController txtLong = TextEditingController();
#override
void initState() {
readSettings();
super.initState();
}

Problem implementing shared_preferrences in flutter

The following code is part of my login screen. I am using shared_preferences to save the remember me checkbox and the user name. The checkbox value is working, but the user name is not being set. I know it is being saved because I can see the value using print. But I guess it is being set too late, as my TextField is blank. Any ideas?
class RmoLogin extends StatefulWidget {
static const String id = 'login_screen';
#override
_RmoLoginState createState() => _RmoLoginState();
}
class _RmoLoginState extends State<RmoLogin> {
final TextStyle style = TextStyle(fontFamily: 'Montserrat', fontSize: 20.0);
final TextEditingController usernameController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
bool showSpinner = false;
bool rememberMe = false;
String userName = '';
_saveRememberUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('username', usernameController.text);
prefs.setBool('remember', rememberMe);
}
_getRememberUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
userName = prefs.getString('username') ?? '';
rememberMe = prefs.getBool('remember') ?? false;
}
#override
void initState() {
super.initState();
_getRememberUser();
if (rememberMe) {
usernameController.text = userName;
}
}
#override
Widget build(BuildContext context) {
final userField = UserTextField(style: style, usernameController: usernameController);
final passwordField = PasswordTextField(style: style, passwordController: passwordController);
final rememberMeCheckbox = Checkbox(
value: rememberMe,
onChanged: (newValue) {
setState(() {
rememberMe = newValue;
});
},
);
Because the SharedPreferences instantiation is asynchronous and the build method itself is not, by the time the instance is created and the value is accessed, the build method would have already been called and your widgets built.
However, For things like SharedPreferences and databases, the best way to implement them is to use the Singleton approach, i.e, one instance that you can use across the entire application.
In this case instead of creating a new SharedPreferences instance whenever either method is called, it will be best to create a single instance of it and use that instance to update the set and get the values.
You could also create a service for the SharedPreferences which you could use across the entire application.
class SharedPreferencesService {
final SharedPreferences _prefs;
SharedPreferencesService(this._prefs);
// define methods here
}
Then in your main method, you can create an instance of SharedPreferences and use it to initialize the SharedPreferencesService.
eg.
SharedPreferencesService service;
Future<void> main() async {
// flutter will complain if this isn't present
WidgetsFlutterBinding.ensureInitialized();
final prefs = await SharedPreferences.getInstance();
service = SharedPreferencesService(prefs);
runApp(YourApp());
}
Then wherever you want to use it in your app, you can call the method name on the service. It is best to use Dependency Injection for the SharedPreferencesService though, you can try the get_it library.
Just a brief look.... but
You are calling _getRememberUser synchronously within initState() when it is an async method
initState() isn't the correct place to be calling it as initState() itself is a synchronus #override.
My solution would be to use a FutureBuilder in your build() method, and call _getRememberUser there.
You just need to update the state that's it check the below solution:
bool rememberMe = false;
String userName = '';
#override
void initState() {
// TODO: implement initState
super.initState();
_getRememberUser();
}
_getRememberUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
userName = prefs.getString('username') ?? '';
rememberMe = prefs.getBool('remember')?? false;
});
if (rememberMe) {
usernameController.text = userName;
}
print(userName +'-->'+rememberMe.toString());
}
Happy Coding!!

Flutter, how to dispose textController

I'm learning Flutter and I have in my app, two textFields linked to textControllers in an AlertDialog to get the input from a user as text and display it in cards in the body of the screen. My problem, that I can't solve on my own, is that after I added setState(() {}) in the 'Save' button of the AlertDialog, for the text to acutally get displayed on the screen in body, well after this change the text entered in the TextFields doesn't get cleared aymore after pressing 'Save'.
My Code:
class _HomeScreenState extends State<HomeScreen> {
final TextEditingController titleController = TextEditingController();
final TextEditingController textController = TextEditingController();
DummyDataProvider notes;
#override
void dispose() {
// Clean up the controller when the widget is disposed.
titleController.dispose();
textController.dispose();
super.dispose();
}
The textControllers in question:
MaterialButton(
onPressed: () {
setState(() {
final title = titleController.text;
final text = textController.text;
NoteProvider.insertNote({'title': title, 'text': text});
Navigator.pop(context);
});
What i mean by text not disposing:
https://imgur.com/a/8pyTPM7,
https://imgur.com/a/lr8a3Eh
Thank you in advance!
Why not just use clear()?
final _textController = TextEditingController();
.....
.....
onPressed: () {
_textController.clear();
}
You can reset your text controllers.
For example in onpressed:
titleController = new TextEditingController();
textController = new TextEditingController();
Set state is not required for this.
TextEditingController
Is very expensive object, don't create it often
just use
TextEditingController.text == '';
to clear the text,