Reputation: 31
I want the search results to be updated every time a character is inputted (or changed) in the search box. I aim to implement this feature as close to clean architecture as possible.
I Use: flutter / flutter-riverpod / get_it
query
in SearchViewModel
.ExploreController
every time a change notification is received.ExploreController
call SearchInteractor
.SearchInteractor
, have SearchInteractor
call and pass the value to SearchPresenter
.SearchPresenter
then calls setItems
of SearchViewModel
.It's peculiar that a ViewModel is calling another ViewModel within itself. However, I thought this flow was okey when using data binding and trying to implement clean architecture. If my assumptions are incorrect, please point it out.
I want to write the following code but,
Since I am using provider
, I need to pass ref
from the controller to the presenter to call the viewmodel. This causes unrelated layers to depend on flutter_riverpod
and leads to an increase in unnecessary passing of ref
. This is causing issues for me.
final searchViewModelProvider =
ChangeNotifierProvider((ref) => DI<SearchViewModel>());
class SearchViewModel extends ChangeNotifier {
final ExploreController _exploreController;
SearchViewModel(this._exploreController);
List<MyResult> _filteredItems = [];
String _query = "";
String get query => _query;
set query(String value) {
_query = value;
_fireController();
notifyListeners();
}
List<MyResult> get filteredItems => _filteredItems;
set filteredItems(List<MyResult> values) {
_filteredItems = values;
notifyListeners();
}
Future<void> _fireController() async {
if (_query.isNotEmpty) {
_exploreController.search(_query);
}
}
}
//controller
//flutter/material.dart have searchcontroller class
class ExploreController {
SearchInteractor _searchInteractor;
ExploreController(this._searchInteractor);
void search(String query) {
_searchInteractor.execute(query);
}
}
//usecase
class SearchInteractor {
MyRepository _myRepository ;
SearchPresenter _presenter;
SearchInteractor(this._myRepository,this._presenter);
void execute(String input) async{
List<MyResult> results=await _myRepository.getMyResults(input);
_presenter.execute(results);
}
}
//presenter
class SearchPresenter {
SearchViewModel _viewModel ;
SearchPresenter(this._viewModel);
void execute(List<MyResult> input) async{
_viewModel.filteredItems=input;
}
}
final DI = GetIt.instance;
void setupLocator() {
//repository
DI.registerSingleton<MyRepository>(() => MyRepository());
//viewmodel
DI.registerFactory<SearchViewModel>(
() => SearchViewModel(DI<ExploreController>()));
//controller
DI.registerFactory<ExploreController>(
() => ExploreController(DI<SearchInteractor>()));
//usecase
DI.registerFactory<SearchInteractor>(() => SearchInteractor(
DI<MyRepository>(), DI<SearchPresenter>()));
//presenter
DI.registerFactory<SearchPresenter>(() => SearchPresenter());
}
Upvotes: 0
Views: 32