Piyush Jain
Piyush Jain

Reputation: 1986

Flutter Mobx @observable is not rebuilding

I am new to flutter and trying to create simple todo app using mobx. whenever I am adding a new task I can see new updated tasks data in my @action but it is not reflecting on UI.

main.dart

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Provider<TaskList>(
      create: (content) => TaskList(),
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(),
      ),
    );
  }
}

taskList

@observable
  List<Task> tasksList = [
    Task(name: 'buy milk'),
    Task(name: 'buy sugar'),
    Task(name: 'buy bread'),
  ];

@action
  void addTask(String title) {
    final task = Task(name: title);
    tasksList.add(task);
    print(tasksList);
  }

TodoApp class

class TodoApp extends StatelessWidget {
  Widget buildBottomSheet(BuildContext context) {
    return AddTaskScreen();
  }

  @override
  Widget build(BuildContext context) => Provider<TaskList>(
    create: (_) => TaskList(),
    child: Scaffold(
      appBar: AppBar(
        title: const Text('Todos'),
      ),
      floatingActionButton: FloatingActionButton(
        backgroundColor: Colors.lightBlueAccent,
        child: Icon(Icons.add),
        onPressed: () {
          showModalBottomSheet(
            context: context,
            //isScrollControlled: true,
            builder: buildBottomSheet,
          );
        },
      ),
      body: Column(
        children: <Widget>[
          TodoListView(),
        ],
      ),
    ),
  );
}

TodoListView class

class TodoListView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final list = Provider.of<TaskList>(context);

    return Observer(
      builder: (_) => Expanded(
        child: ListView.builder(
          itemBuilder: (content, index) {
            return Observer(
              builder: (_) => TaskTile(
                taskTitle: list.tasksList[index].name,
                isChecked: list.tasksList[index].isDone,
                checkBoxCallback: (checkBoxState) {
                  // taskData.updateTask(task);
                },
                longPressCallBack: () {
                  list.deleteTask(index);
                },
              ),
            );
          },
          itemCount: list.tasksList.length,
        ),
      ),
    );
  }
}

TaskTile Class

class TaskTile extends StatelessWidget {
  final String taskTitle;
  final bool isChecked;
  final Function checkBoxCallback;
  final Function longPressCallBack;

  TaskTile(
      {this.taskTitle,
      this.isChecked,
      this.checkBoxCallback,
      this.longPressCallBack});

  @override
  Widget build(BuildContext context) {
    print('task tile');
    print(taskTitle);
    return ListTile(
      title: Text(
        taskTitle,
        style: TextStyle(
          decoration: isChecked ? TextDecoration.lineThrough : null,
        ),
      ),
      trailing: Checkbox(
        activeColor: Colors.lightBlueAccent,
        value: isChecked,
        onChanged: checkBoxCallback,
      ),
      onLongPress: longPressCallBack,
    );
  }
}

AddTaskScreen Class

class AddTaskScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    String newTaskTitle;
    final list = Provider.of<TaskList>(context);

    return Container(
      child: Container(
        padding: EdgeInsets.only(left: 20.0, top: 20.0, right: 20.0),
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.only(
              topRight: Radius.circular(20.0), topLeft: Radius.circular(20.0)),
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Text(
              'Add a Task',
              style: TextStyle(
                fontSize: 30.0,
                color: Colors.lightBlueAccent,
              ),
              textAlign: TextAlign.center,
            ),
            TextField(
              autofocus: true,
              textAlign: TextAlign.center,
              onChanged: (newTask) {
                newTaskTitle = newTask;
              },
            ),
            SizedBox(
              height: 20.0,
            ),
            FlatButton(
              child: Text(
                'Add',
                style: TextStyle(color: Colors.white, fontSize: 20.0),
              ),
              padding: EdgeInsets.symmetric(vertical: 10.0),
              onPressed: () {
                list.addTask(newTaskTitle);
                Navigator.pop(context);
//                print('piyuhs');
//                print(list);
              },
              color: Colors.lightBlueAccent,
            ),
          ],
        ),
      ),
    );
  }
}

in addTask action value is updating but it is not reflecting on UI. I know I am doing silly mistake here. I have search on google also but still not working.

Thanks in advance

Upvotes: 1

Views: 3511

Answers (1)

Ferdi
Ferdi

Reputation: 788

It's a particular case of mobx indeed.

Actually the notification is fire to the UI when there is a change of instance not only parameter.

Here the list is the same instance and doesn't not trigger UI.

To work around this problem you have to make your list an ObservableList :

  @observable
  ObservableList<Task> tasksList = ObservableList<Task>([  //Change here
    Task(name: 'buy milk'),
    Task(name: 'buy sugar'),
    Task(name: 'buy bread'),
  ]);

  @action
  void addTask(String title) {
    final task = Task(name: title);
    tasksList.add(task);
    print(tasksList);
  }

It should do the job ;)

Upvotes: 3

Related Questions