Flutter : TextEditingController Only Static member can be accessed in initializer error - flutter

I'm passing data from listmosque.dart to update_screen.dart for updating data.
Anything it's work but i want set default value of textedittingcontroller.
TextEditingController _txtnrp = TextEditingController(text: "${widget.nrpUpdate}"); <- this error
I'm getting message Only static members can be accessed in initializers. in ${widget.nrpUpdate}
How to fix this ?
It's my update_screen.dart
import 'package:flutter/material.dart';
class UpdateScreen extends StatefulWidget {
final String idUpdate;
final String nrpUpdate;
final String namaUpdate;
final String emailUpdate;
final String jurusanUpdate;
UpdateScreen(
{this.idUpdate,
this.nrpUpdate,
this.namaUpdate,
this.emailUpdate,
this.jurusanUpdate});
#override
_UpdateScreenState createState() => _UpdateScreenState();
}
class _UpdateScreenState extends State<UpdateScreen> {
TextEditingController _txtnrp = TextEditingController(text: "${widget.nrpUpdate}"); <- In this line error
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_left),
onPressed: () => Navigator.pop(context, false),
),
centerTitle: true,
title: Text('Update ${widget.namaUpdate}'),
),
body: Container(
child: Center(
child: SingleChildScrollView(
padding: EdgeInsets.all(20),
scrollDirection: Axis.vertical,
child: Column(
children: <Widget>[
TextField(
controller: _txtnrp,
keyboardType: TextInputType.number,
decoration: InputDecoration(hintText: "NRP"),
textAlign: TextAlign.center,
),
],
),
),
),
),
);
}
}
How to fix this ?
Thanks

Move it inside initState:
class _UpdateScreenState extends State<UpdateScreen> {
TextEditingController _txtnrp;
#override
void initState() {
_txtnrp = TextEditingController(text: "${widget.nrpUpdate}");
super.initState();
}

Andrey's answer is correct, but just wanted to add some details:
Problem is indeed that you're trying to access State.widget before it is initialized, and accessing these parameters through State.widget is the recommended way (instead of passing through State constructor).
build() method is always called when state changes, so setting controller to ${widget.nrpUpdate} would actually make the text field behave strangely (resetting it) every time a state changed occured. So, that's another reason why you should set this value inside initState() instead. This, eg would clear the text field every time you clicked the button, even though that's not desired:
class _UpdateScreenState extends State<UpdateScreen> {
TextEditingController _txtnrp;
int _count = 1;
Widget GetColumn(someText) {
print(someText);
return
}
#override
void initState() {
_txtnrp = TextEditingController(text: "${widget.nrpUpdate}");
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_left),
onPressed: () => Navigator.pop(context, false),
),
centerTitle: true,
title: Text('Update ${widget.namaUpdate}'),
),
body: Container(
child: Center(
child: SingleChildScrollView(
padding: EdgeInsets.all(20),
scrollDirection: Axis.vertical,
child: Column(
children: <Widget>[
TextField(
controller: TextEditingController(text: someText),
keyboardType: TextInputType.number,
decoration: InputDecoration(hintText: "NRP"),
textAlign: TextAlign.center,
),
FlatButton(
child: Text("Click"),
onPressed: () => setState(() {_count += 1;})
),
],
),
),
),
),
);
}
}
Other than that, you might want to organize your code when it gets bigger, breaking it into functions and variables. When doing so, you could run into similar "only static objects" errors. One way to avoid this would be:
class _UpdateScreenState extends State<UpdateScreen> {
TextEditingController _txtnrp;
Widget getColumn(someText)
return Column(
children: <Widget>[
TextField(
controller: _txtnrp,
keyboardType: TextInputType.number,
decoration: InputDecoration(hintText: "NRP"),
textAlign: TextAlign.center,
),
],
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: ...,
body: Container(
child: Center(
child: SingleChildScrollView(
padding: EdgeInsets.all(20),
scrollDirection: Axis.vertical,
child: GetColumn("${widget.nrpUpdate}").
),
),
),
),
);
#override
void initState() {
_txtnrp = TextEditingController(text: "${widget.nrpUpdate}");
super.initState();
}

Related

How to fix "Too many positional arguments: 1 expected, but 3 found." issue in flutter

I'm new to flutter.
I need to get product information through a form using flutter provider.
I can get one object(like String name value only). But when I add multiple parameters, it shows the following error.
Too many positional arguments: 1 expected, but 3 found.
This is the code I wrote.
Model class
class Item {
String itemName;
String description;
double itemPrice;
Item(this.itemName, this.description, this.itemPrice);
}
ChangeNotifier class
class ItemAddNotifier extends ChangeNotifier {
List<Item> itemList = [];
addItem(String itemName, String description, double itemPrice) {
Item item = Item(itemName, description, itemPrice);
itemList.add(item);
notifyListeners();
}
}
Add items
class AddItems extends StatelessWidget {
final TextEditingController _itemNameTextEditing = TextEditingController();
final TextEditingController _itemDescriptionTextEditing =
TextEditingController();
final TextEditingController _itemPriceTextEditing = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Kavishka'),
),
body: Container(
padding: EdgeInsets.all(30.0),
child: Column(
children: [
TextField(
controller: _itemNameTextEditing,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(15.0),
hintText: 'Item Name',
),
),
SizedBox(
height: 20.0,
),
TextField(
controller: _itemDescriptionTextEditing,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(15.0),
hintText: 'Item Description',
),
),
SizedBox(
height: 20.0,
),
TextField(
controller: _itemPriceTextEditing,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(15.0),
hintText: 'Item Price',
),
),
SizedBox(
height: 20.0,
),
RaisedButton(
child: Text('ADD ITEM'),
onPressed: () async {
if (_itemNameTextEditing.text.isEmpty) {
return;
}
await Provider.of<ItemAddNotifier>(context, listen: false)
.addItem(
_itemNameTextEditing.text,
_itemDescriptionTextEditing.text,
_itemPriceTextEditing.text);
Navigator.pop(context);
},
),
],
),
),
);
}
}
Home Screen
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Kavishka'),
actions: [
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) {
return AddItems();
},
),
);
},
icon: Icon(Icons.add))
],
),
body: Container(
padding: EdgeInsets.all(30.0),
child: Column(
children: [
Consumer<ItemAddNotifier>(builder: (context, itemAddNotifier, _) {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: itemAddNotifier.itemList.length,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.all(15.0),
child: Column(
children: [
Text(
itemAddNotifier.itemList[index].itemName,
style:
TextStyle(fontSize: 20.0, color: Colors.black),
),
],
),
);
});
})
],
),
),
);
}
}
Main
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (BuildContext context) {
return ItemAddNotifier();
},
child: MaterialApp(
home: Container(
color: Colors.white,
child: HomeScreen(),
),
),
);
}
}
It shows the error in Item item = Item(itemName, description, itemPrice); line.
If someone can help me to fix this issue.
Thank you.

How to control null when bulding widget

Can you tell me how can I include the condition for Image.file on the following page? I would like to build it only when controller.image is not null.
I got an error:
The following NoSuchMethodError was thrown building Container(padding: EdgeInsets.all(32.0)):
The method '[]' was called on null.
Receiver: null
Tried calling:
when I first redirect to this page (and controller.image is null):
class HomePage extends GetView<HomeController> {
final myController1 = TextEditingController();
final myController2 = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Grobonet'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
TextField(
controller: myController1,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Nazwisko'),
),
TextField(
controller: myController2,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Miejscowosc'),
),
IconButton(
icon: Icon(
Icons.add,
size: 30,
),
onPressed: () =>
Get.toNamed(
AppRoutes.PICK_IMAGE
),
color: Colors.pink,
),
IconButton(
icon: Icon(
Icons.save_outlined,
size: 30,
),
/*onPressed: () =>
Get.toNamed(
AppRoutes.PICK_IMAGE
),*/
color: Colors.pink,
),
Container(
padding: EdgeInsets.all(32),
child: GetBuilder<HomeController>(
builder: (_) {
return Image.file(controller.image);
},
),
),
]
),
),
);
}
}
Controller:
class HomeController extends GetxController {
final image = Get.arguments['image'];
final file_loaded = Get.arguments['file_loaded'];
}
You can use collection-if. Just add if (controller.image != null) like so:
if (controller?.image != null)
Container(
padding: EdgeInsets.all(32),
child: GetBuilder<HomeController>(
builder: (_) {
return Image.file(controller.image);
},
),
),
Use Get your arguments on the controller's onInit() method:
class HomeController extends GetxController {
final File image;
final File file_loaded;
onInit(){
image = Get.arguments['image'];
file_loaded = Get.arguments['file_loaded'];
}
}
In this way, you don't need to perform additional null checks except Get.arguments is actually null.
Update
And you also need to update your view like this:
Container(
padding: EdgeInsets.all(32),
child: GetBuilder<HomeController>(
builder: (_) {
return Image.file(_.image); // not return Image.file(controller.image);
// _ here is the instance of HomeController given by the GetBuilder
},
),
),
Update 2
As you mentioned in the comments, you want to send data to a previously opened page (HomePage) from a second page (OCRDetailsPage). Then you don't need to pass arguments. You can get the HomeController instance in your OCRDetailsPage with Get.find() and set the variables and update the state like:
class OCRDetailsPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final OCRDetailsController controller = Get.find();
return Scaffold(
appBar: AppBar(title: Text('OCR Details Page')),
body: Center(
child: FlatButton(
color: Colors.blue,
child: Icon(Icons.save_outlined),
onPressed: () {
final HomeController homeController = Get.find();
homeController.ocr_text = controller.text;
homeController.update();
Get.toNamed(
AppRoutes.HOME,
);
}),
),
);
}
}

OnTap Function in the DropDownMenu Button in Flutter

I've tried to populate the dropdown menu button with the data from the SQLite database.
Then on the onTap Function I wanted to navigate to the selected category.
When I tap on the category it does not navigate.
I have saved each category with an id in the database which is used the identify the selected item.
Here is the code:
'''
class _HomeState extends State<Home> {
TodoService _todoService;
var _selectedValue;
var _categories = List<DropdownMenuItem>();
List<Todo>_todoList=List<Todo>();
#override
initState(){
super.initState();
_loadCategories();
}
_loadCategories() async {
var _categoryService = CategoryService();
var categories = await _categoryService.readCategory();
categories.forEach((category) {
setState(() {
_categories.add(DropdownMenuItem(
child: Text(category['name']),
value: category['name'],
onTap: ()=>Navigator.of(context).push(MaterialPageRoute(builder:(context)=>TodosByCategory(category: category['name'],))),
));
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _globalKey,
appBar: AppBar(
actions: <Widget>[
DropdownButtonHideUnderline(
child: DropdownButton(
value: _selectedValue,
items: _categories,
dropdownColor: Colors.blue,
style: TextStyle(color: Colors.white,fontSize: 16.0),
iconDisabledColor: Colors.white,
iconEnabledColor: Colors.white,
onChanged: (value) {
setState(() {
_selectedValue = value;
});
},
),
),
'''
Here is the todosByCategory():
'''
class _TodosByCategoryState extends State<TodosByCategory> {
List<Todo>_todoList=List<Todo>();
TodoService _todoService=TodoService();
#override
initState(){
super.initState();
getTodosByCategories();
}
getTodosByCategories()async{
var todos=await _todoService.readTodoByCategory(this.widget.category);
todos.forEach((todo){
setState(() {
var model= Todo();
model.title=todo['title'];
model.dueDate=todo['dueDate'];
_todoList.add(model);
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Todos By Category'),
),
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: _todoList.length,
itemBuilder: (context, index){
return Padding(
padding: EdgeInsets.only(top:8.0, left: 8.0, right: 8.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0),
),
elevation: 8.0,
child: ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(_todoList[index].title)
],
),
subtitle: Text(_todoList[index].dueDate),
// trailing: Text(_todoList[index].dueDate),
),
),
);
},),
)
],
),
);
}
}
'''
Please help me out.
Instead of writing the navigation code inside onTap of DropdownMenuItem, you can write it inside onChanged of DropdownButton where you are also getting the category name string as the value. It should work then.

How to bind a textfield's text to a simple text label in flutter

For the most straightforward solution:
class _GreetingPageState extends State<GreetingPage> {
final TextEditingController _nameController = new TextEditingController(text: 'Anonymous');
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hello World'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(_name),
TextField(
autofocus: true,
controller: _nameController,
),
],
),
),
);
}
}
This does not work as expected, while typing in TextField, Text's content doesn't get updated.
I have to change to manage another state for Text:
class _GreetingPageState extends State<GreetingPage> {
String _name = '';
final TextEditingController _nameController = new TextEditingController(text: 'Anonymous');
#override
void initState() {
super.initState();
_nameController.addListener(
() {
setState(() {_name = _nameController.text;});
}
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hello World'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(_name),
TextField(
autofocus: true,
controller: _nameController,
decoration: new InputDecoration(
hintText: 'Type your name',
),
),
],
),
),
);
}
}
This adds too much complexity for such a simple "bind a value to a text" situation.
I tried search for it, official document only give a use case where the _nameController.text is only used when a button is pressed, however I'd like to handle text update on user typing.
I think your problem is that until setState is not called the Text widget doesn't know it has to update. So you always need to call it.
You could do something like this:
class __GreetingPageStateState extends State<_GreetingPageState> {
final TextEditingController _nameController =
new TextEditingController(text: 'Anonymous');
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(_nameController.text),
TextField(
autofocus: true,
controller: _nameController,
onChanged: (text) {
setState(() {});
}),
],
);
}
}

How to create a Checkbox and access global variable from class?

I am trying to create a checkbox inside my view. I declared bool variable isChecked= false in my state class, and while writing constructor for checkbox getting the error on my isChecked variable as 'Only static members can be accessed in intializers'. I made the variable as static, which removed the error on bool variable, but giving the same error on setState(). How do i resolve this ?
import 'package:flutter/material.dart';
class CardScreen extends StatelessWidget{
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Card Screen',
home: new myPetScreen()
);
}
}
class myPetScreen extends StatefulWidget{
myPetScreen({Key key, this.title}) : super(key: key);
final String title;
#override
_myPetScreenState createState() => new _myPetScreenState();
}
class _myPetScreenState extends State<myPetScreen>{
static bool isChecked = false;
final view = new Column(
children: <Widget>[
//did other UI Implementation here
Container(
child: Flexible(
child: ListView.builder(itemBuilder: (context, position){
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Text(position.toString(), style: TextStyle(fontSize: 14.0, color: Colors.black),),
Spacer(),
Checkbox(
value: isChecked,
onChanged: (value) {
setState(() {
isChecked = value;
});
},
),
],
),
)
);
}
),
),
) ,
],
);
#override Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Card Screen')),
body: view,
);
}
}
make some change take your column code into one method then that method called into widget..
like this way..
Column getView(){
var view = new Column(
children: <Widget>[
//did other UI Implementation here
Container(
child: Flexible(
child: ListView.builder(itemBuilder: (context, position) {
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Text(
position.toString(),
style: TextStyle(fontSize: 14.0, color: Colors.black),
),
Spacer(),
Checkbox(
value: isChecked,
onChanged: (value) {
changeState(value);
},
),
],
),
));
}),
),
),
],
);
return view;
}
after that called this way..
body: getView()
You are declaring view as a final variable, so it is immutable. change it to a function like so:
Widget get view => Container(
//...
)
Also, don't forget to remove static from the state declaration (Never do that in a stateful wiget).