prashant.fepale
prashant.fepale

Reputation: 577

Flutter - Update parant widget class UI on child button click

enter image description here

I have such kind of scenario

Widget build(BuildContext context) {
return Scaffold(
  appBar: AppBar(
    title: Text("Hello"),
  ),
  body: Container(
    child: ChildWidget(
      listControl: this.sentToScreenBuildJson,
      notifyParent: refresh,
    ),
  ),
);
}

this is my parent build method where I have added ChildWidget a another statfulscreen and passing is a json and a refresh funtion

as per json child will able to draw UI and on button click I am able to get callback to refresh method.

refresh() {
print("I get refreshed from child");
setState(() {
  print("I get refreshed from child in setState");
  this.sentToScreenBuildJson = this.newJson;
});
}

on button click both print get execute but UI is not updating as per newJson. Like I am expecting that as setState run parent has to call build with passing updated json. which is not working.

thanks for any help.

Upvotes: 0

Views: 518

Answers (3)

OMi Shah
OMi Shah

Reputation: 6186

An alternative to @Darish's answer, you can declare a static variable in your class 1, access that static variable in class 2 and then update the state of the variable in the class 2.

For example:

import 'package:flutter/material.dart';

class Demo extends StatefulWidget {
  static UserObject userObject;

  @override
  _Demo createState() => _Demo();
}

class _Demo extends State<Demo> {
  @override
  void initState() {
    Demo.userObject = new UserObject(name: "EXAMPLE NAME");
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Color(0xfff3f3f3),
        appBar: AppBar(title: Text("DEMO")),
        body: InkWell(
            onTap: () {
              Navigator.push(context,
                  MaterialPageRoute(builder: (context) => HeroClass()));
            },
            child: Center(
                child: Hero(
                    tag: "tag-demo-id",
                    child: Container(
                        color: Colors.black,
                        padding: EdgeInsets.all(20),
                        child: Text("${Demo.userObject.name} -> CLICK HERE",
                            style: TextStyle(color: Colors.white)))))));
  }
}

class HeroClass extends StatefulWidget {
  @override
  _HeroClassState createState() => _HeroClassState();
}

class _HeroClassState extends State<HeroClass> {
  final myController = TextEditingController();

  @override
  void initState() {
    myController.text = Demo.userObject.name;
    super.initState();
  }

  @override
  void dispose() {
    // Clean up the controller when the widget is removed from the widget tree.
    // This also removes the _printLatestValue listener.
    myController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text("DEMO HERO")),
        body: Hero(
            tag: "tag-demo-id",
            child: Container(
              child: TextField(
                controller: myController,
              ),
            )),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            setState(() {
              Demo.userObject.name = myController.text;
            });
          },
          child: Icon(Icons.save),
        ));
  }
}

// object class
class UserObject {
  String name;

  UserObject({this.name});

  UserObject.fromJson(Map<String, dynamic> json) {
    name = json['name'];
  }
}

Upvotes: 0

Kalpesh Kundanani
Kalpesh Kundanani

Reputation: 5763

When you want to pass data from Child to Parent you should use NotificationListener at parent and dispatch Notification from child.

Instance of Notification class will be having data that you can consume in Parent using NotificationListener.

Mostly all the Flutter Widgets are using this technique, for example tab controller receive OverscrollNotification when user reaches to the last tab and still try to swipe.

Following is the demo that you can use to understand how you can use NotificationListener in your code.

import 'package:flutter/material.dart';

void main() => runApp(ParentWidget());

class ParentWidget extends StatefulWidget {
  ParentWidget({Key key}) : super(key: key);

  @override
  _ParentWidgetState createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State<ParentWidget> {
    String _text = 'You have not pressed the button yet';
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: NotificationListener<IntegerNotification>(
          onNotification: (IntegerNotification notification) {
            setState(() {
              print(notification);
             _text = 'You have pressed button ${notification.value} times'; 
            });
            return true;
          },
          child: Column(
            children: <Widget>[
              Text(_text),
              ChildWidget(),
            ],
          )
        ),
      ),
    );
  }
}

class ChildWidget extends StatefulWidget {
  const ChildWidget({Key key}) : super(key: key);

  @override
  _ChildWidgetState createState() => _ChildWidgetState();
}

class _ChildWidgetState extends State<ChildWidget> {
  int _counter = 0;
  @override
  Widget build(BuildContext context) {
    return RaisedButton(onPressed: (){
      IntegerNotification(++_counter).dispatch(context);
    },child: Text('Increment counter'),);
  }
}

@immutable
class IntegerNotification extends Notification{
  final int value;

  const IntegerNotification(this.value);

  String toString(){
    return value.toString();
  }
}

Upvotes: 1

Darish
Darish

Reputation: 11481

Update parant widget class UI on child button click

This is a common use case in flutter and flutter has built in InheritedWidget class for these kind of purpose. You may either directly use it for your purpose or use some ready made package solution which uses InheritedWidget behind the scenes like Provider.

Upvotes: 0

Related Questions