I need to let the consumer widget listen to multiple variables depending on a boolean value.
this is the model class
class Lawyer{
Data? data;
double? distance = 0;
Lawyer({this.data, this.distance});
factory Lawyer.fromJson(Map<String, dynamic> json) =>
Lawyer(data: Data.fromJson(json['listing_data']));
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
class Data{
String? title;
String? email;
String? phone;
Location? location;
List<String>? logo;
List<String>? cover;
Data({this.title, this.email, this.phone, this.logo, this.cover, this.location});
factory Data.fromJson(Map<String, dynamic> json) {
var logo = json['_job_logo'];
var cover = json['_job_cover'];
var long = json['geolocation_long'];
var lat = json['geolocation_lat'];
return Data(title: json['_job_tagline'], email: json['_job_email'],
location: Location(latitude: json['geolocation_lat'], longitude: json['geolocation_long']),
phone: json['_job_phone'], logo: List<String>.from(logo),
cover: List<String>.from(cover)
);
}
}
and this is the view model notifier
class LawyerAPIServices extends ChangeNotifier{
final url = "https://dalilvision.com/wp-json/wp/v2/job_listing";
List<Lawyer> lawyersList = [];
List<Lawyer> staticLawyersList = [];
Future<List<Lawyer>> fetchLawyers() async{
final response = await get(Uri.parse(url.toString()));
if(response.statusCode == 200){
var dynamicLawyersList = jsonDecode(response.body);
print('$dynamicLawyersList');
lawyersList = List<Lawyer>.from(dynamicLawyersList.map((x) => Lawyer.fromJson(x)));
staticLawyersList = lawyersList;
lawyersList.forEach((element) {print('all lawyers: ${element.data!.location}');});
notifyListeners();
return lawyersList;
}
else{
notifyListeners();
throw Exception(response.statusCode);
}
}
Future<List<Lawyer>> getFullListOfLawyers() async {
notifyListeners();
print('fulll list: ${staticLawyersList.length}');
return staticLawyersList;
}
}
and finally this is the consumer widget
Consumer<LawyerAPIServices>(
builder: (context, value, child) => FutureBuilder(
future: _list,
builder: (BuildContext context, AsyncSnapshot<List<Lawyer>> snapshot) {
if (snapshot.hasData){
return ListView.separated(
physics: const NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
shrinkWrap: true,
separatorBuilder: (context, index) => const Divider(color: Colors.transparent),
itemCount: value.lawyersList.length,
itemBuilder: (context, index) {
return InkWell(
child: LawyerWidget(
title: snapshot.data![index].data!.title!,
email: snapshot.data![index].data!.email!,
phone: snapshot.data![index].data!.phone!,
logo: snapshot.data![index].data!.logo![0],
cover: snapshot.data![index].data!.cover![0]
),
);
}
}
);
}
else if(snapshot.hasError){
return Center(
child: Text(snapshot.error.toString())
);
}
else {
return const CircularProgressIndicator(
strokeWidth: 2,
);
}
},
),
)
In the notifier class
there are two lists, the staticLawyerList
is initialized only once when getting the list from a network call and then used as a backup list, and the lawyersList
is the one that will be manipulated.
what I have done until now is to get the initial value of lawyersList
by a network call, then somehow the staticLawyersList
values are always equal to lawyersList
, even if I made any change or manipulate the lawyersList
these changes will automatically reflect on the staticLawyersList
which is really weird.
now what I want to achieve exactly is to apply a condition to update the UI with the appropriate list depending on this condition.
if(setByPosition == false){
//update UI with `staticLawyersList`
}
else {
//update UI with `lawyersList`
}
update!!!!!!!!
here's how I update my consumer
CheckboxListTile(
activeColor: Colors.black,
value: isChecked,
onChanged: (value) async {
saveSharedPreferences(value: value!);
if(value == true) {
Provider.of<LawyerAPIServices>(context, listen: false).sortLawyersList(
devicePosition: widget.position, lawyersList: widget.list);
}
else{
Provider.of<LawyerAPIServices>(context, listen: false).getFullListOfLawyers();// the list returned by this function don't applied to the consumer
}
setState(() {
isChecked = value;
Navigator.pop(context);
});
},
title: const Text('Filter by distance'),
),
as @Saichi-Okuma said that to copy the content of a list you should use staticLawyersList = List.from(lawyersList)
because in dart and most of the java compiler programming languages when you use staticLawyersList = lawyersList
this means that you are referring to the lawyersList
by the staticLawyersList
.
then I manipulate the lawyersList
as I want with help of staticLawyersList
lawyersList.clear();
lawyersList.addAll(staticLawyersList);
But when I did so, the consumer didn't apply the changes based on the staticLawyersList
although the logcat shows that the staticLawyersList
length is 10 which is what I want (full list without filtration).
the conclusion of my problem can be listed in two points:
1- the consumer is listening to only one list lawyersList
and I think it still exists.
2- the pointer problem as @Saichi-Okuma mentioned.
here are the full code changes
void getFullListOfLawyers() {
lawyersList.clear(); // to make sure that the list is clean from older operations
lawyersList.addAll(staticLawyersList);// the trick
notifyListeners();
}
Future<List<Lawyer>> fetchLawyers() async{
final response = await get(Uri.parse(url.toString()));
if(response.statusCode == 200){
var dynamicLawyersList = jsonDecode(response.body);
print('$dynamicLawyersList');
lawyersList = List<Lawyer>.from(dynamicLawyersList.map((x) => Lawyer.fromJson(x)));
staticLawyersList = List.from(lawyersList);// use this statment instead of staticLawyersList = lawyersList
lawyersList.forEach((element) {print('all lawyers: ${element.data!.location}');});
notifyListeners();
return lawyersList;
}
else{
notifyListeners();
throw Exception(response.statusCode);
}
}