0

I have been trying to make a app in flutter where an api is called and data is updated in TextField
Used provider for state management, here is the code for it.

class ProfileProvider with ChangeNotifier {
  var profileData;
  String _url = "http://10.0.2.2:3000/api/v1/user/loggedin_user";

  void getData() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    var token = prefs.getString('token');
    var data = await http.get(
      _url,
      headers: {
        "accept": "application/json",
        "content-type": "application/json",
        'Token': token,
      },
    );
    var infoOfPerson = json.decode(data.body);
    profileData = new ProfileObject(
      name: infoOfPerson['name'],
      mobile: infoOfPerson['mobile'],
      email: infoOfPerson['email'],
      role: infoOfPerson['role'],
    );
    notifyListeners();
  }

  ProfileObject get profileInfo {
    return profileData;
  }
}

I am getting the data fine, now i have to show it in the UI, but sometime data is populated, sometime its not. Can someone please point me the right direction why this is happening.

Here is the code for UI.

 class Profile extends StatefulWidget {
  @override
  _ProfileState createState() => _ProfileState();
}

class _ProfileState extends State<Profile> {
  final emailController = TextEditingController(text: '');
  final nameController = TextEditingController(text: '');
  final mobileController = TextEditingController(text: '');
  var _isInit = true;

  @override
  void didChangeDependencies() {
    if (_isInit) {
      final profileData = Provider.of<ProfileProvider>(context);
      profileData.getData();
      if (profileData.profileInfo != null) {
        emailController.text = profileData.profileInfo.name;
        nameController.text = profileData.profileInfo.email;
        mobileController.text = profileData.profileInfo.mobile;
      }
      _isInit = false;
      super.didChangeDependencies();
    }
  }

  @override
  Widget build(BuildContext context) {
    final profileData = Provider.of<ProfileProvider>(context);

    return Scaffold(
      drawer: NavigationDrawer(),
      body: profileData.profileInfo == null
          ? Center(
              child: CircularProgressIndicator(),
            )
          : Builder(
              builder: (context) => SingleChildScrollView(
                child: Padding(.....

Below the padding, there is normal TextField, can someone tell me why the data is being populated sometime and sometime its coming empty, even I wrapped it with CircularProgressIndicator() and a check the notifyListeners(); is not working there. The loader is not being shown and data is not being loaded.

Thanks

Badro Niaimi
  • 959
  • 1
  • 14
  • 28
Alpit Anand
  • 1,213
  • 3
  • 21
  • 37

2 Answers2

0

for StatelessWidget.

Inside the build method use:

Future.microtask(() async {
  context.read<SomeProvider>().fetchSomething();
});

For StatefulWidgets if you want to call it once. Do this inside the initState() or didChangeDependencies (better if the latter). This will be called at the end of the frame which means after the build or rendering finishes..

void initState() {
  super.initState();
  WidgetsBinding.instance.addPostFrameCallback((_) {
    context.read<SomeProvider>().fetchSomething();       
  });
}

EDIT: WidgetsBinding will also work on build. I forgot on why I used microtask lol

GhoSt
  • 321
  • 2
  • 12
-1

i've created a function which called nextTick, i call it in initState and it works for now, but want to see others method

void nextTick(Function callback, [int milliseconds = 0]) {
  Future.delayed(Duration(milliseconds: 0)).then((_) {
    callback();
  });
}

then use it like below

  @override
  void initState() {
    super.initState();
    nextTick((){
      ProfileProvider profileProvider = Provider.of<ProfileProvider>(context);
      profileProvider.getProfile();
    });
  }

Edit: i store couple of variables to manage them on ui, like isLoading, hasError and errorMessage. Here is my provider class

class ProfileProvider extends ChangeNotifier {
  bool _hasError = false;
  bool _isLoading = true;
  String _errorMsg = '';
  Profile _profileResponse;

  bool get hasError => _hasError;

  bool get isLoading => _isLoading;

  String get errorMsg => _errorMsg;

  Profile get profileResponse => _profileResponse;

  Future<void> getProfile() async {
    this.setLoading = true;
    this.setError = false;
    this.setErrorMsg = '';
    try {
      await dio.post('$api/p/view', data: {}).then((res) {
        print(res.data);
        _profileResponse = Profile.fromJson(jsonDecode(res.data));
        print(_profileResponse.data);
        notifyListeners();
      }).whenComplete(() {
        this.setLoading = false;
      });
    } catch (e) {
      this.setError = true;
      this.setErrorMsg = '$e';
    }
    this.setLoading = false;
  }


  set setError(bool val) {
    if (val != _hasError) {
      _hasError = val;
      notifyListeners();
    }
  }

  set setErrorMsg(String val) {
    if (val != null && val != '') {
      _errorMsg = val;
      notifyListeners();
    }
  }

  set setLoading(bool val) {
    _isLoading = val;
    notifyListeners();
  }
}
Murat Aslan
  • 1,446
  • 9
  • 21