Home > Back-end >  Access Provider variable in child widget methods
Access Provider variable in child widget methods

Time:06-01

I'm trying to access branchSelected, a Provider declared towards the top of my code in the scaffold's child widgets. When I use branchSelected.branchDropdownValue in the original widget, it works. However, when I go into the child widget methods, specifically

ElevatedButton(
        onPressed: () {
          branchSelected.branchChange;
          /*
          refreshBranchData();
          refreshProjectData();
          */
        },
        child: Icon(Icons.refresh))

, I received the error "Undefined name 'branchSelected'." Looking at other documentation, I thought that all child widgets should be able to access the Provider; however, that doesn't seem to be the case here. Any ideas? I've attached my code below:

@override
Widget build(BuildContext context) {
final branchSelected = Provider.of<branchListChanges>(context);
return Scaffold(
  appBar: AppBar(
    title: Text('Build Launcher'),
  ),
  body: Padding(
    padding: const EdgeInsets.all(8.0),
    child: Column(
      children: [
        _buildTopRow(),
        Consumer<branchListChanges>(builder: (context, data, child) {
          return Text(
              'Current Branch: ${branchSelected.branchDropdownValue}');
        }),
        _buildList(),
      ],
    ),
  ),
  backgroundColor: Colors.grey[200],
);
}

Expanded _buildList() {
// Sets which branch to view for the list runs

return Expanded(
  child: RunList(branches, "main"),
);
}

Row _buildTopRow() {
return Row(
  children: [
    Text("Project:"),
    SizedBox(width: 6),
    ProjectDropdown(packages),
    SizedBox(width: 6),
    Text("Branch:"),
    SizedBox(width: 6),
    BranchDropdown(branchNames),
    SizedBox(width: 6),
    Checkbox(
      checkColor: Colors.white,
      fillColor: MaterialStateProperty.all<Color>(Colors.blue),
      value: onlyLatestPerDay,
      onChanged: (bool? value) {
        setState(() {
          onlyLatestPerDay = value!;
        });
      },
    ),
    SizedBox(width: 3),
    Text("Only latest per-day"),
    SizedBox(width: 6),
    Checkbox(
      checkColor: Colors.white,
      fillColor: MaterialStateProperty.all<Color>(Colors.blue),
      value: onlyInstalled,
      onChanged: (bool? value) {
        setState(() {
          onlyInstalled = value!;
        });
      },
    ),
    SizedBox(width: 3),
    Text("Only installed"),
    SizedBox(width: 6),
    ElevatedButton(
        onPressed: () {
          branchSelected.branchChange;
          /*
          refreshBranchData();
          refreshProjectData();
          */
        },
        child: Icon(Icons.refresh))
  ],
);
}
}

I created my Provider in main.dart attached below:

class HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
  return MaterialApp(
    title: 'cornerCan',
    theme: ThemeData(
      primarySwatch: Colors.blue,
  ),
  // EFFECTS: runs mainPage function in main_page.dart
  home: ChangeNotifierProvider<branchListChanges>(
    create: (context) => branchListChanges(),
    child: mainPage(),
  ),
);
}
}

CodePudding user response:

  1. The scope of your branchSelected variable is only inside the build function. You need to declare it outside the build function to access it.
  2. You can also pass it as a parameter to the _buildTopRow() function e.g. _buildTopRow(branchSelected)

CodePudding user response:

I think the problem is that in your build where you call your Provider, it will not find it _buildTopRow because it does not receive it there, why don't you create a new Widget class and call it there? For example :

Instead of :

Row _buildTopRow() {
 return Row(
  children: [
    Text("Project:"),
    SizedBox(width: 6),
    ProjectDropdown(packages),
    SizedBox(width: 6),
    Text("Branch:"),
    SizedBox(width: 6),
    BranchDropdown(branchNames),
    SizedBox(width: 6),
    Checkbox(
      checkColor: Colors.white,
      fillColor: MaterialStateProperty.all<Color>(Colors.blue),
      value: onlyLatestPerDay,
      onChanged: (bool? value) {
      },
    ),
    SizedBox(width: 3),
    Text("Only latest per-day"),
    SizedBox(width: 6),
    Checkbox(
      checkColor: Colors.white,
      fillColor: MaterialStateProperty.all<Color>(Colors.blue),
      value: onlyInstalled,
      onChanged: (bool? value) {
      },
    ),
    SizedBox(width: 3),
    Text("Only installed"),
    SizedBox(width: 6),
    ElevatedButton(
        onPressed: () {
          branchSelected.branchChange;
          /*
          refreshBranchData();
          refreshProjectData();
          */
        },
        child: Icon(Icons.refresh))
  ],
 );
}

You can write :

class _BuildTopRow extends StatelessWidget {
  const _BuildTopRow({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final branchSelected = Provider.of<branchListChanges>(context); // get here the instance

    return Row(
      children: [
        Text("Project:"),
        SizedBox(width: 6),
        ProjectDropdown(packages),
        SizedBox(width: 6),
        Text("Branch:"),
        SizedBox(width: 6),
        BranchDropdown(branchNames),
        SizedBox(width: 6),
        Checkbox(
          checkColor: Colors.white,
          fillColor: MaterialStateProperty.all<Color>(Colors.blue),
          value: onlyLatestPerDay,
          onChanged: (bool? value) {
          },
        ),
        SizedBox(width: 3),
        Text("Only latest per-day"),
        SizedBox(width: 6),
        Checkbox(
          checkColor: Colors.white,
          fillColor: MaterialStateProperty.all<Color>(Colors.blue),
          value: onlyInstalled,
          onChanged: (bool? value) {
          },
        ),
        SizedBox(width: 3),
        Text("Only installed"),
        SizedBox(width: 6),
        ElevatedButton(
            onPressed: () {
              branchSelected.branchChange;
              /*
              refreshBranchData();
              refreshProjectData();
              */
            },
            child: Icon(Icons.refresh))
      ],
    );
  }
}
  • Related