Getx: Doing update doesn't update value in GET builder,

Created on 27 Jul 2020  ยท  10Comments  ยท  Source: jonataslaw/getx

Describe the bug
The value in GetBuilder doesn't update if value is changed, even if update() is called.

To Reproduce

  1. Here's the sample widget.
class LoadingWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetBuilder<LoadingController>(
      init: LoadingController(),
      builder: (_) => AlertDialog(
        content: Text(
          _.loaderMsg,
        ),
      ),
    );
  }
}
  1. And here's the controller
class LoadingController extends GetxController {
  String loaderMsg = 'TempLoading';

  void showLoader({String msg = 'Loading...'}) {
    loaderMsg = msg;
    update();
    Get.dialog(LoadingWidget()); //<-- even moved it above but not working.
  }

  void hideLoader() {
    Get.back();
  }
}
  1. And call it like:
RaisedButton(
  onPressed: () {
    LoadingController().showLoader(msg: 'Loading some new content');
  },
  child: Text('Show Loader'),
),

Expected behavior
When clicking on Show Loader button the text is in LoadingWidget should update, but whenever the button is click, there's only TempLoading text which is the default text.

Flutter Version:
1.17.5

Get Version:
3.4.0

Describe on which device you found the bug:
Pixel 2 API 28 - Android.

Most helpful comment

@joanofdart and @Nipodemos very appreciated thanks. You don't know how much I love this package. This is one of theeee besssst package ever i have seen. I am exploring it further.

All 10 comments

You are not calling a function, you are creating a new instance, and accessing a function from that newly created instance.

RaisedButton(
  onPressed: () {
    LoadingController().showLoader(msg: 'Loading some new content'); // HERE
  },
  child: Text('Show Loader'),
),

You should have done something like this:

RaisedButton(
  onPressed: () {
    Get.find<LoadingController>().showLoader(msg: 'Loading some new content'); // HERE
  },
  child: Text('Show Loader'),
),

@jonataslaw Thanks for quick response. I also tried that but this didn't work.

โ•โ•โ•โ•โ•โ•โ•โ• Exception caught by gesture โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
The following message was thrown while handling a gesture:
 LoadingController not found. You need call put<LoadingController>(LoadingController()) before

When the exception was thrown, this was the stack
#0      GetInstance.find 
package:get/โ€ฆ/instance/get_instance.dart:162
#1      Inst.find 
package:get/โ€ฆ/instance/extension_instance.dart:19
#2      LoginView.build.<anonymous closure> 
package:bluebox/โ€ฆ/login/login.view.dart:29
#3      _InkResponseState._handleTap 
package:flutter/โ€ฆ/material/ink_well.dart:779
#4      _InkResponseState.build.<anonymous closure> 
package:flutter/โ€ฆ/material/ink_well.dart:862
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#399b8
    debugOwner: GestureDetector
    state: possible
    won arena
    finalPosition: Offset(209.9, 353.9)
    finalLocalPosition: Offset(48.2, 18.2)
    button: 1
    sent tap down
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

I don't want to have Get.put(LoadingController()); everywhere in every widget because I will need to show this dialog many times and in every widget. Is there any easy way?

try lazyput it in main.I just tried it on myapp and it works, shows correct text when open the dialog.

class DI {
  static init() {
    /// Services
    Get.lazyPut<LoadingController>(() => LoadingController());
  }
}

void main() {
  DI.init();
  runApp(GetMaterialApp(
    home: MyApp(),
  ));
}

import 'package:get/get.dart';
import 'package:myapp/screens/loadingwidget.dart';

class LoadingController extends GetxController {
  var loaderMsg = 'TempLoading'.obs;

  void showLoader({String msg = 'Loading...'}) {
    loaderMsg.value = msg;
    Get.dialog(LoadingWidget());

    update();
  }

  void hideLoader() {
    Get.back();
  }
}

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:myapp/services/loadingcontroller.dart';

class LoadingWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetBuilder<LoadingController>(
      init: LoadingController(),
      builder: (data) => AlertDialog(
        content: Text(
          'State:   ${data.loaderMsg.value}',
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
      ),
    );
  }
}

 RaisedButton(
                onPressed: () {
                  Get.find<LoadingController>()
                      .showLoader(msg: 'Loading some new content');
                },
                child: Text('Show Loader'),
              ),

Best!
but wait why did you use .obs? Is it required? I am not using it though.

Good :) Yeah String type will work if you use GetBuilder and update. I am not sure i think @jonataslaw has to answer but if it should be an "observerable" it needs .obs or Rx/Rx{type} so you can use it in OBX functions (no need for update).

@lundin thanks!
I know it and I am in love with Observables and have been using it in TypeScript.
But overuse of it is not good and shouldn't be used just for small tasks like changing the widget text.

Hello! i'd like to explain some things:

You don't need update() in that case

As you know, update() is meant for rerender some Widget that is being show on the screen with a new value you want.

But if you pay attention, you are calling update() before the dialog show on screen! That means that you don't need update() in this occasion, because when dialog get show in the screen, it will get the value msgLoader has, and it will be the value inside the method, because you already changed the value before open a dialog

so, update() in that specific case is doing nothing.

.obs is not needed to work in that case too

since you don't need update, you don't need .obs too, because it is to update value of something that is already showing at the screen. Besides, when you using vars with obs, the widget you need to make it work is GetX(), not GetBuilder(). The reason it worked is because you didn't even needed in the first place

You need to make a instance of the controller before using it

The reason you got this error when you applied the changes @jonataslaw requested is because on the RaisedButton the controller was not initialized yet. And that's why putting it in the main method works. A good thing to do is add fenix: true to controller, like that:

Get.lazyPut<LoadingController>(() => LoadingController(), fenix: true);

By default, controllers are disposed when you are not using them in some screen, so if for example, you use it on the first screen, but don't use it in the second, it will be disposed and in the third screen you will not have the controller to use and it will give error.

the fenix: true argument makes so that whenever you call this method and the controller does not exist anymore, it will recreate the instance for you to use (now the name makes a little more sense right? ๐Ÿ˜… )

that's all. I hope it helps you understanding better this package.

In my opinion, "fenix" is a bad property name, it should just be "recreate".

In my opinion, "fenix" is a bad property name, it should just be "recreate".

or it can have the same name that is used in bindings SmartManagement: keepFactory

although this would probably confuse people. Or not, since it does the same thing

@joanofdart and @Nipodemos very appreciated thanks. You don't know how much I love this package. This is one of theeee besssst package ever i have seen. I am exploring it further.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

na2axl picture na2axl  ยท  3Comments

Denilson-source picture Denilson-source  ยท  3Comments

rupamking1 picture rupamking1  ยท  3Comments

wailashraf71 picture wailashraf71  ยท  4Comments

ChiwanAhn picture ChiwanAhn  ยท  4Comments