ViewModel extending ChangeNotifier clears the value when not called in init

50 Views Asked by At

I have my BaseViewModel that is extending ChangeNotifer and then other viewModels extending the baseViewModel. The problem I am facing is when I call an api function inside init of baseViewModel it does works well and stores the value to the variables of that child viewModel but when I need to pass the values from UI and don't want the api function to be run in init rather I want to call it from the UI, the api works fine but doesn't stores the values to variables of child viewModel. Here is my BaseViewModel that is extending the ChangeNotifier:


abstract class BaseViewModel with ChangeNotifier {
  bool _isLoading = false;
  bool _isDisposed = false;
  bool _isInitializeDone = false;

  FutureOr<void> _initState;

  BaseViewModel() {
    _init();
  }

  FutureOr<void> init();

  void _init() async {
    this.isLoading = true;
    _initState = init();
    await _initState;
    this._isInitializeDone = true;
    this.isLoading = false;
  }

  void changeStatus() => isLoading = !isLoading;

  void reloadState() {
    if (!isLoading) notifyListeners();
  }

  @override
  void dispose() {
    _isDisposed = true;
    super.dispose();
  }

  //Getters
  FutureOr<void> get initState => _initState;

  bool get isLoading => _isLoading;

  bool get isDisposed => _isDisposed;

  bool get isInitialized => _isInitializeDone;

  //Setters
  set isLoading(bool value) {
    _isLoading = value;
    scheduleMicrotask(() {
      if (!_isDisposed) notifyListeners();
    });
  }
}

Here is my Child ViewModel extending the above baseViewModel:


class RoutesViewModel extends BaseViewModel {
  RoutesViewModel({
    required this.routesUseCase,
  });

  @override
  FutureOr<void> init() async {
    await getWeeklyRoutesByDriverID();
    // await getWeeklyJobByRouteID(
    //   routeID: '34',
    //   driverID: '',
    //   memoryCache: 0,
    // );
  }

  List<RoutesDetailModel> _routesDetailModel = [];

  final RoutesUseCase routesUseCase;
  String errorMessage = '';
  List<JobDetailsModel> _jobDetailsModel = [];
  RoutesDetailModel _routesDetailsModel = RoutesDetailModel.empty();

  Future getWeeklyRoutesByDriverID() async {
    changeStatus();
    final response = await routesUseCase.getWeeklyRoutesByDriverID();
    return response.fold(
      (success) {
        _routesDetailModel = success;
        changeStatus();
        return Left(
          _routesDetailModel,
        );
      },
      (r) {
        changeStatus();
        return Right(
          errorMessage = r.message,
          // showToast(
          //   message: r.message,
          //   context: context,
          // ),
        );
      },
    );
  }

  FutureOr<void> getWeeklyJobByRouteID({
    required String routeID,
    required String driverID,
    required int memoryCache,
  }) async {
    changeStatus();
    reloadState();
    notifyListeners();
    final response = await routesUseCase.getWeeklyJobsByRouteID(
      routeID: routeID,
      driverID: driverID,
      memoryCache: memoryCache,
    );
    return response.fold(
      (success) {

        _jobDetailsModel = success;
        changeStatus();
        notifyListeners();
        reloadState();
        return Left(
          _jobDetailsModel,
        );
      },
      (r) {
        changeStatus();
        return Right(
          Failure(
            message: r.message,
            status: r.status,
          ),
        );
      },
    );
  }
  ///Getters
  int get routesCount => _routesDetailModel.length;

  int get jobsCount => _jobDetailsModel.length;

  String getData(int index) => _routesDetailModel[index].route.toString();

  // int? getRouteID (int index) => _routesDetailModel[index].routeId;

  List<RoutesDetailModel> getRoutesModel(int index) => [
        _routesDetailModel[index],
      ];
}

You might see that one api call is being made in init and the other one is commented out. The first one works well and does store the values in _routesDetaiLModel but the other one doesn't as it requires params also I am calling it form UI. Here is how I am calling it from the UI:

class _JobsScreenState extends State<JobsScreen> {
  @override
  void initState() {
    final provider = Provider.of<RoutesViewModel>(context, listen: false);
    Future.delayed(
      Duration(seconds: 3),
      () {
        provider.getWeeklyJobByRouteID(
          routeID: widget.routesDetailModel[0].routeId.toString(),
          driverID: '',
          memoryCache: 0,
        );
      },
    );
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    // Provider.of<RoutesViewModel>(
    //   context,
    //   listen: true,
    // );
    return SafeArea(
      child: Scaffold(

I have tried calling like this as well in init: context.read<RoutesViewModel>().getWeeklyJobByRouteID( routeID: widget.routesDetailModel[0].routeId.toString(), driverID: '', memoryCache: 0, );

I also have tried using "with" keyword ChangeNotifer.

I have tried calling like this as well in init: context.read<RoutesViewModel>().getWeeklyJobByRouteID( routeID: widget.routesDetailModel[0].routeId.toString(), driverID: '', memoryCache: 0, ); I am expecting the result to be stored in _jobsDetailModel and should give me the jobsCount. It does show me data being returned.

0

There are 0 best solutions below