Error: Only static members can be accessed in initializers what does this mean?

DartFlutter

Dart Problem Overview


I have something like this. I am having difficulty understanding this error. Why does accessing filterController here give this error here, but it doesn't give this error if I move the current entire TextFormField creation (between comments A and B) inside the build method? How does moving the entire TextFormField inside the build method make filterController static then and resolve this issue?

class AppHomeState extends State<AppHome> with SingleTickerProviderStateMixin
{

	TabController _tabController;
	final filterController = new TextEditingController(text: "Search");
        //----A
		TextFormField email = new TextFormField(
		keyboardType: TextInputType.emailAddress,
		controller: filterController,	 ------>ERROR : Error: Only static members can be accessed in initializers
	    );
       //----B

  @override
	Widget build(BuildContext context)
	{
		return new Scaffold(
				appBar: new AppBar(..),
		);
	}
}

How can I resolve this issue?

Dart Solutions


Solution 1 - Dart

class AppHomeState extends State<AppHome> with SingleTickerProviderStateMixin {

    TabController _tabController;
    final filterController = new TextEditingController(text: "Search");
    TextFormField email = ...

... is an initializer and there is no way to access this at this point. Initializers are executed before the constructor, but this is only allowed to be accessed after the call to the super constructor (implicit in your example) was completed. Therefore only in the constructor body (or later) access to this is allowed.

This is why you get the error message:

controller: filterController,

accesses this.filterController (this is implicit if you don't write it explicit).

To work around your issue (assuming email needs to be final) you can use a factory constructor and a constructor initializer list:

class AppHomeState extends State<AppHome> with SingleTickerProviderStateMixin {
  factory SingleTickerProviderStateMixin() => 
      new SingleTickerProviderStateMixin._(new TextEditingController(text: "Search"));

  SingleTickerProviderStateMixin._(TextEditingController textEditingController) : 
      this.filterController = textEditingController,   
      this.email = new TextFormField(
        keyboardType: TextInputType.emailAddress,
        controller: textEditingController);

  TabController _tabController;
  final filterController;
  final TextFormField email;

or when the email field does not need to be final email can be initialized in the constructor initializer list:

class AppHomeState extends State<AppHome> with SingleTickerProviderStateMixin {

  SingleTickerProviderStateMixin() {
    email = new TextFormField(
        keyboardType: TextInputType.emailAddress,
        controller: filterController,
    );
  }
  
  TabController _tabController;
  final filterController = new TextEditingController(text: "Search");
  TextFormField email;

but in Flutter widgets initState is usually used for that

class AppHomeState extends State<AppHome> with SingleTickerProviderStateMixin {

  @override
  void initState() {
    super.initState();
    email = new TextFormField(
        keyboardType: TextInputType.emailAddress,
        controller: filterController,
    );
  }
  
  TabController _tabController;
  final filterController = new TextEditingController(text: "Search");
  TextFormField email; 

Solution 2 - Dart

You can keep that as a method:

Widget getEmailController(){
return new TextFormField(
        keyboardType: TextInputType.emailAddress,
        controller: filterController,
        );
}

and use it in UI:

body: Container(
child: getEmailController();
)

Solution 3 - Dart

You can convert this variable to a function and you can take context in this function parameters.

Example

Widget myDialog (BuildContext context) {
  return new Scaffold(
    backgroundColor: Colors.white,
    body: new Center(
      child: new Column(
        children: <Widget>[
          new Text("Invalid Username/Password"),
          new Text("Please verify your login credentials"),
          new RaisedButton(
            child: new Text("Ok"),
            onPressed:() {
              Navigator.pop(context);//Error : Only static members can be accessed in initializers
            }
          ),
        ],
      ),
    )
  );
}

// Using if you are doing in a class
this.myDialog(context);

// Using if you are using a global function
myDialog(context);

But, i think you want to show a error message. So, you can do it with a dialog not an page. It's more efficient because you can specify your dialog box with buttons or messages and you can use this error dialog everywhere. Let's look my global helper function for showing error messages.

void showError(BuildContext context, String error) {
  showSnackBar(
    context,
    new Text(
      'Error',
      style: new TextStyle(color: Theme.of(context).errorColor),
    ),
    content: new SingleChildScrollView(
      child: new Text(error)
    ),
    actions: <Widget>[
      new FlatButton(
        child: new Text(
          'Ok',
          style: new TextStyle(
            color: Colors.white
          ),
        ),
        onPressed: () {
          Navigator.of(context).pop();
        },
        color: Theme.of(context).errorColor,
      ),
    ]
  );
}

// Using in everywhere
showError(context, 'Sample Error');

Solution 4 - Dart

I faced the same problem, and I was able to tackle the problem by setting the initial value of the TextFormField by adding the value I need to the controller's text, example:

_carPlateController.text = _initValues['carPlate'];

or

filterController.text = 'search';

I hope this helps! As it is an elegant easy solution for when using controllers.

Solution 5 - Dart

You can do it this way: First declared and after initialised inside your didChangeDependencies() method, like this

Declared your variable

List<Tab> tabsList = [];

initialised tabsList

 tabsList = [
    Tab(text: getTranslated(context, "tab_1")),
    Tab(text: getTranslated(context, "tab_2")),
    Tab(text: getTranslated(context, "tab_3"))
 ];

Full codes Example

class _MyClassState extends State<MyClass>
    with TickerProviderStateMixin<MyClass> {

  TabController tabController;
  List<Tab> tabsList = [];

  @override
  void didChangeDependencies() {
    tabsList = [
      Tab(text: getTranslated(context, "tab_1")),
      Tab(text: getTranslated(context, "tab_2")),
      Tab(text: getTranslated(context, "tab_3"))
    ];
    tabController =
        TabController(length: tabsList.length, vsync: this, initialIndex: 0);

    super.didChangeDependencies();
  }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMistyDView Question on Stackoverflow
Solution 1 - DartGünter ZöchbauerView Answer on Stackoverflow
Solution 2 - DartRuben MartirosyanView Answer on Stackoverflow
Solution 3 - DartAnilcanView Answer on Stackoverflow
Solution 4 - DartYaGeorgeView Answer on Stackoverflow
Solution 5 - DartParesh MangukiyaView Answer on Stackoverflow