Reputation: 6367
I have an app that allows users to view river gauge data from an API that lists rivers from the entire US. Users can save gauges as favorites which are then displayed in a favorites view. The favorites are stored in user defaults by ID. The favorites view is populated through a favorites view model which is constructed using the user defaults. The favorites are displayed in a list view and when one is tapped the app loads a details view. In the details view, the user can opt to delete the favorite. When returning to the favorites view using the back button, the favorites view should reflect the change, but it does not. I am using Flutter Provider and this is my first implementation of it.
I am defining the provider in main since I will need access to it throughout the app.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
setupServiceLocator();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown])
.then((_) {
runApp(
ChangeNotifierProvider(
create: (context) => FavoritesViewModel(),
child: MyApp(),
)
);
});
}
My ListView
class _FavoritesView extends State<FavoritesView> {
FavoritesViewModel viewModel = FavoritesViewModel(); // serviceLocator<FavoritesViewModel>();
@override
void initState() {
viewModel.loadFavorites();
super.initState();
}
@override
Widget build(BuildContext context) {
return Consumer<FavoritesViewModel>(
builder: (context, model, child) => Scaffold(
appBar: AppBar(
title: Text('=Favorites='),
),
body: ListView.builder(
itemCount: model.favorites.length,
itemBuilder: (context, index) {
return FavoriteCard(model.favorites[index], Key(model.favorites[index]));
},
),
),
);
}
Favorites View Model
class FavoritesViewModel extends ChangeNotifier {
List<String> favorites;
FavoritesViewModel() {
loadFavorites();
}
void deleteFavorite(String id) {
if (favorites.contains(id)) {
this.favorites.remove(id);
}
Storage.initializeList(kFavoritesKey, favorites);
notifyListeners();
}
In the Details view (one place where users can opt to remove a favorite) I am getting a reference to the favorites view model
FavoritesViewModel favesVM = FavoritesViewModel(); // serviceLocator<FavoritesViewModel>();
and calling its deleteFavorite function from within a dialog:
var approveRemovalButton = FlatButton(
child: Text('Remove',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.blue),
),
onPressed: () {
animationDuration = 0;
favesVM.deleteFavorite(widget.gaugeId);
Navigator.pop(context);
},
);
When I tap a button and invoke the deleteFavorite function on the view model, the item is removed from user preferences, and is also removed from the view model, however, upon returning to the favorites list view, the item is still present in the UI. It's as if the Favorites list view is not registered as a listener and doesn't respond to notifyListeners
. Can anyone see what might be causing this? Thanks!
Upvotes: 0
Views: 1024
Reputation: 1824
Update your State<FavoritesView>
like bellow:
class _FavoritesView extends State<FavoritesView> {
FavoritesViewModel viewModel;
@override
void initState() {
super.initState();
viewModel = Provider.of<FavoritesViewModel>(context, listen: false);
viewModel.loadFavorites();
}
@override
Widget build(BuildContext context) {
return Consumer<FavoritesViewModel>(
builder: (context, model, child) => Scaffold(
appBar: AppBar(
title: Text('=Favorites='),
),
body: ListView.builder(
itemCount: model.favorites.length,
itemBuilder: (context, index) {
return FavoriteCard(model.favorites[index], Key(model.favorites[index]));
},
),
),
);
}
Upvotes: 1
Reputation: 2862
Your issue that you have two view models running at the same time, let me explain how :
By calling FavoritesViewModel viewModel = FavoritesViewModel(); // serviceLocator<FavoritesViewModel>();
This will create an instance from the view model.
And also , by doing this
ChangeNotifierProvider(
create: (context) => FavoritesViewModel(),
child: MyApp(),
)
You are creating another view model
so the tricky part is : you have two view models that both contains the same data, You are using the view model from the consumer (not the locator) to show the data into your listview and then you are deleting the data from the locator , so the delete will not be reflected.
As a solution you can wrap your FavoriteCard
by Consumer<FavoritesViewModel>
and use model.deleteFavorite()
Upvotes: 2
Reputation: 4035
I think you are explicitly creating multiple provides and you loaded data in one provider and when you are notifying the changes, the parent notifier is getting notified and changes are not getting reflected. Don't create separate FavoritesViewModel
as you should use the same object. You have already created one object in runApp()
Please replace
FavoritesViewModel viewModel = FavoritesViewModel();
with
FavoritesViewModel viewModel = Provider.of<FavoritesViewModel>(context);
Upvotes: 1