Accessing a text field controller within another widget in Flutter? - flutter

Say I've created a file info_card.dart that I want to use to get the name of a user with the following code:-
import 'package:flutter/material.dart';
class InfoCard extends StatefulWidget {
const InfoCard({ Key? key }) : super(key: key);
#override
State<InfoCard> createState() => _InfoCardState();
}
class _InfoCardState extends State<InfoCard> {
final _nameController = TextEditingController();
#override
void dispose() {
_nameController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return TextField(
controller: _nameController
);
}
}
And then I create a completely different file, home_page.dart for example:-
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({ Key? key }) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: InfoCard(),
);
}
}
How would I access the text controller within the InfoCard() widget, and say store it in a variable so that I could write it to a database? I'm really struggling with this as simply trying to use InfoCard()._nameController doesn't seem to work.

You could create the controller in the home page instead and pass it to the infocard. for example:
class HomePage extends StatefulWidget {
const HomePage({ Key? key }) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final _nameController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: InfoCard(controller: _nameController ),
);
}
#override
void dispose() {
_nameController.dispose();
super.dispose();
}
}
and
class InfoCard extends StatefulWidget {
final TextEditingController controller;
const InfoCard({ Key? key, required this.controller}) : super(key: key);
#override
State<InfoCard> createState() => _InfoCardState();
}
class _InfoCardState extends State<InfoCard> {
#override
Widget build(BuildContext context) {
return TextField(
controller: widget.controller
);
}
}

There are many ways to achieve that in Flutter, the simplest thing you can do:
Instead of creating the controller inside InfoCard, inject it to it by its constructor. So your file will look like this:
class InfoCard extends StatefulWidget {
const InfoCard( this._nameController , { Key? key,}) : super(key: key);
final TextEditingController _nameController;
#override
State<InfoCard> createState() => _InfoCardState();
}
class _InfoCardState extends State<InfoCard> {
#override
Widget build(BuildContext context) {
return TextField(
controller: widget._nameController,
);
}
}
Create a controller in HomePage and pass it to InfoCard, thus, you'll have a reference to that controller in HomePage. So your file will look like this:
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
TextEditingController _infoCardController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: InfoCard(_infoCardController),
);
}
}
Now pass that controller reference _infoCardController wherever you need it, and use simply as
print(_infoCardController.text)

Here i Solve this problem you can follow these steps:
just click the button and check the controller result in the console window
HomePage Code:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
TextEditingController textController = TextEditingController();
void getText(){
print("entered text "+ textController.text);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
InfoCard(textController),
ElevatedButton(onPressed: getText, child: Text("Press Here !")),
],
)),
);
}
}
InfoCard Page:
import 'package:flutter/material.dart';
class InfoCard extends StatefulWidget {
final TextEditingController textController ;
const InfoCard(#required this.textController);
#override
State<InfoCard> createState() => _InfoCardState();
}
class _InfoCardState extends State<InfoCard> {
// final _nameController = TextEditingController();
#override
void dispose() {
widget.textController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.grey,
child: TextField(
controller: widget.textController
),
);
}
}

Related

How to use a method in a Stateful Widget from another Widget

So i have this toggle() method in the Stateful SideBar class
class SideBar extends StatefulWidget {
const SideBar({super.key});
#override
State<SideBar> createState() => _SideBarState();
}
class _SideBarState extends State<SideBar> with SingleTickerProviderStateMixin{
void toggle() {
if (_controller.isCompleted) {
_controller.reverse();
}
else {_controller.forward();}
}
}
and i want to use it in
class SideBarWidget extends StatelessWidget {
SideBarWidget({Key? key}) : super(key: key);
final SideBar sideBarWidget = SideBar(...);
void toggle() {
// here i want to use the toggle() method
}
#override
Widget build(BuildContext context) {
return sideBarWidget;
}
}
I cannot use sideBarWidget.toggle()
I also cannot pass it as a parameter becasue the _controller is in the SideBar() widget
There are many ways, but the most common and simple is to create an instance of the SideBar class inside the SideBarWidget class, for example:
var side = SideBar();
And then you can access the toggle() method like this: side.toggle().
remove underscore from SideBarState
to use method of SideBarState in SideBarWidget use: SideBarState().toggle();
**screen1.dart**
class ParentWidget extends StatefulWidget {
const ParentWidget({Key? key}) : super(key: key);
#override
State<ParentWidget> createState() => ParentWidgetState();
}
class ParentWidgetState extends State<ParentWidget> {
void printData() {
print("parent");
}
#override
Widget build(BuildContext context) {
return const Placeholder();
}
}
**screen2.dart**
import 'package:demo/screen_1.dart';
import 'package:flutter/material.dart';
class ChildWidget extends StatelessWidget {
const ChildWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
ParentWidgetState().printData();
return const Placeholder();
}
}
One way is to give the SideBar a GlobalKey and get the state from the key afterwards. An example:
class SideBar extends StatefulWidget {
const SideBar({super.key});
#override
State<SideBar> createState() => SideBarState();
}
class SideBarState extends State<SideBar> with SingleTickerProviderStateMixin{
#override
Widget build(BuildContext context) {
return Container();
}
void toggle() {
print('toggle');
}
}
class SideBarWidget extends StatelessWidget {
SideBarWidget({Key? key}) : super(key: key);
final GlobalKey<SideBarState> sideBarKey = GlobalKey();
late final SideBar sideBarWidget = SideBar(key: sideBarKey);
void toggle() {
sideBarKey.currentState?.toggle();
}
#override
Widget build(BuildContext context) {
return Column(
children: [
TextButton(onPressed: toggle, child: const Text('click')),
sideBarWidget,
],
);
}
}

Accessing Classes in different pages

can somebody explain me when we have one file like Home.dart i have access to extends state classes and it's static variables
Home.dart
import 'package:flutter/material.dart';
class FirstClass extends StatefulWidget {
const FirstClass({Key? key}) : super(key: key);
#override
State<FirstClass> createState() => _FirstClassState();
}
class _FirstClassState extends State<FirstClass> {
static void someFunc() {
print('nothing');
}
#override
Widget build(BuildContext context) {
return Container();
}
}
class SecondClass extends StatefulWidget {
const SecondClass({Key? key}) : super(key: key);
#override
State<SecondClass> createState() => _SecondClassState();
}
class _SecondClassState extends State<SecondClass> {
#override
Widget build(BuildContext context) {
return ElevatedButton(onPressed: _FirstClassState.someFunc, child: Text(' '));
}
}
but when we have two different file like home1.dart and home2.dart we cant access to extends state classes?
Home1.dart
import 'package:flutter/material.dart';
class FirstClass extends StatefulWidget {
const FirstClass({Key? key}) : super(key: key);
#override
State<FirstClass> createState() => _FirstClassState();
}
class _FirstClassState extends State<FirstClass> {
static void someFunc() {
print('nothing');
}
#override
Widget build(BuildContext context) {
return Container();
}
}
Home2.dart
import 'package:flutter/material.dart';
import 'Home1.dart';
class SecondClass extends StatefulWidget {
const SecondClass({Key? key}) : super(key: key);
#override
State<SecondClass> createState() => _SecondClassState();
}
class _SecondClassState extends State<SecondClass> {
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: **_FirstClassState.someFunc?????**, child: Text(' '));
}
}
i know i can have access to FirstClass but why can not have access to _FirstClassState ?
I think it is better to separate your widget classes and logic classes that contains some function.
Since you are extending Stateless/Stateful widget, the class is becoming a widget.
Create you method or function in another class and don't extend anything if you don't have to then use static keyword in front of the functions so that you can access those functions inside another class or let's say in your stateful widget class.
However, if you need to pass values from one Stateful widget to another then add that object to your widget's constructor. Example as follows:
class FirstClass extends StatefulWidget {
String username = ""; //Creating & initializing username variable
//Adding username variable inside constructor
const FirstClass({Key? key, required this.username}) : super(key: key);
#override
State<FirstClass> createState() => _FirstClassState();
}
class _FirstClassState extends State<FirstClass> {
static void someFunc() {
print('nothing');
}
#override
Widget build(BuildContext context) {
return Text(widget.username); //Accessing username
}
}
Then, pass your value in the widget like this:
class SecondClass extends StatefulWidget {
const SecondClass({Key? key}) : super(key: key);
#override
State<SecondClass> createState() => _SecondClassState();
}
class _SecondClassState extends State<SecondClass> {
#override
Widget build(BuildContext context) {
return FirstClass(username: "Tricolore"); //Passing username value
}
}

How to add custom values in inside expression in flutter math_fork library

class ResultPage extends StatefulWidget {
DataModel dataModel;
ResultPage({Key? key, required this.dataModel}) : super(key: key);
#override
_ResultPageState createState() => _ResultPageState();
}
class _ResultPageState extends State<ResultPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Math.tex("m=/frac "${widget.datamodel.value}"")
);
}
}
but the math.tex is showing error in flutter how to pass custom values in any equation
class ResultPage extends StatefulWidget {
DataModel dataModel;
ResultPage({Key? key, required this.dataModel}) : super(key: key);
#override
_ResultPageState createState() => _ResultPageState();
}
class _ResultPageState extends State<ResultPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body:Math.tex(
"m = ${r'\frac'} {${widget.datamodel.value1}}
{$widget.datamodel.value2}",
textStyle: textStyle,
),
);}}
that is how you can add custom values in the equation in flutter math_fork
The 'Scaffold' need to have a 'body'. Try to add 'Math.text' under 'body'.
Here is a package's sample code that use 'Math.tex'.
https://github.com/simpleclub-extended/flutter_math_fork/blob/9015c77bc79f5e21820de3c927f43ff275b35078/test/helper.dart#L30
https://github.com/simpleclub-extended/flutter_math_fork/blob/9015c77bc79f5e21820de3c927f43ff275b35078/example/lib/display.dart#L29
class ResultPage extends StatefulWidget {
DataModel dataModel;
ResultPage({Key? key, required this.dataModel}) : super(key: key);
#override
_ResultPageState createState() => _ResultPageState();
}
class _ResultPageState extends State<ResultPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Math.tex("m=/frac "${widget.datamodel.value}"")
);
}
}

Is there a way to access the instance of a StatefulWidget inside of it's state?

I have a list of widgets which I want to update if a button on the inside of one of those widgets is pressed.
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
void initState() {
super.initState();
init();
}
List<Training> finalTrainings = [];
void addTraining(Training training){
setState(() {
finalTrainings.add(training);
});
}
#override
Widget build(BuildContext context) {
return Training(addTraining);
}
}
addTraining is the callback function I use
class Training extends StatefulWidget {
const Training({Key? key, required this.addTraining}) : super(key: key);
final Function addTraining;
#override
State<Training> createState() => _TrainingState();
}
class _TrainingState extends State<Training> {
#override
Widget build(BuildContext context) {
ElevatedButton(
child: Text("add training",),
onPressed: () {
widget.addTraining(this);
},
)
}
}
Here I use "this" trying to reference the Training instance but obviously this doesn't work, since it just returns the "_TrainingState" instance. Is there a way I can access the Training instance from within _TrainingState?
If you want to access the instance of a widget from where you use that widget, you should make the state class public by removing its underscore:
class Training extends StatefulWidget {
const Training({Key? key, required this.addTraining}) : super(key: key);
final Function addTraining;
#override
State<Training> createState() => TrainingState();
}
// state class should be public
class TrainingState extends State<Training> {
#override
Widget build(BuildContext context) {
ElevatedButton(
child: Text("add training",),
onPressed: () {
widget.addTraining(this);
},
)
}
}
then use global key:
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final trainingKey = GlobalKey<TrainingState>();
#override
void initState() {
super.initState();
init();
}
List<Training> finalTrainings = [];
void addTraining(Training training){
// widget instance that you want to access
final trainingWidget = trainingKey.currentWidget;
}
#override
Widget build(BuildContext context) {
return Training(key: trainingKey);
}
}

Is there a way to access a field from the state of a StatefulWidget?

I have a field that changes in the state of a StatefulWidget but I want to access it in the widget itself.
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Training();
}
}
class Training extends StatefulWidget {
const Training({Key? key}) : super(key: key);
String trainingToString(){
return('people selected: ' + //Here I would need to access the variable from _TrainingState);
}
#override
State<Training> createState() => _TrainingState();
}
class _TrainingState extends State<Training> {
int peopleSelected = 0;
void updatePeopleSelected(int peopleSelected){
setState((){
this.peopleSelected = peopleSelected;
}
}
#override
Widget build(BuildContext context) {
return Container();
}
}
So I have the field peopleSelected and a function to update it in _TrainingState and when I call Training.trainingToString() I want it to print this field but I can't access the field through Training.
Is there a way you can do it or what would be some alternatives?
you must to call this function you can use only for now
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){updatePeopleSelected()}
child: Container())
}