Generating JSON Models in Flutter, Filter a List, and Delay Search in Flutter GetX.

Inzimam Bhatti
Dev Genius
Published in
6 min readAug 7, 2022

--

In this article, we will see how to automatically generate JSON models, filter lists, and perform searches with delay in Flutter & GetX.

Note: State is managed by GetX if you are using a simple project pattern then use setState() or whatever you want to manage the state.

1- Create a Flutter project

Create a new flutter project on your android studio.

Note: if you want to shift the project to the GetX pattern, see here to shift a project with GetCli. You can do your simple project as well.

2- Add Dependencies

Add these dependencies to your pubspec.yaml file and run pub get.

dependencies: 
cupertino_icons: ^1.0.2
flutter:
sdk: flutter
json_model: ^1.0.0 //add this package
json_serializable: ^6.3.1 // add this package
json_annotation: ^4.6.0 //add thispackage
http: ^0.13.5 //add this package

dev_dependencies:
build_runner: ^2.2.0 //add this package
flutter_lints: ^2.0.0
flutter_test:

3- Main URL

Below is the URL for which we will parse and create the models.

https://jsonplaceholder.typicode.com/users

Here you can see 10 User records.

Let’s Start…

4- Auto Generate the All Models from JSON

The first thing we have to do is to create a folder named ‘jsons‘ at the root of our project. This is the default folder, but you can have your own name. In that case, you need to specify the folder named while running the auto-generate commands in the terminal.

Now create a new file named “user.json” in the ‘jsons‘ folder and copy the user record into it.

{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere@april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
}

Then go to the terminal and run the following command.

flutter packages pub run json_model

Now you should see a new folder named “models” inside the “lib” folder.

There you can see the auto-generated user model file.

import 'package:json_annotation/json_annotation.dart';
import "company.dart";
part 'user.g.dart';

@JsonSerializable()
class User {
User();

late num id;
late String name;
late String username;
late String email;
late Map<String,dynamic> address;
late String phone;
late String website;
late Company company;

factory User.fromJson(Map<String,dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}

So far so good…but it's not over.

We have nested objects inside the user object.

The “address” property is the nested object.

Create a new ‘address.json’ file inside the ‘jsons’ folder and change the json in the users.json to below.

Run the command again and you should see the new generated files and the User model is updated like below.

flutter packages pub run json_model

Address model will be generated like

import 'package:json_annotation/json_annotation.dart';

part 'address.g.dart';

@JsonSerializable()
class Address {
Address();

late num id;
late String name;
late String username;
late String email;
late Address address;
late String phone;
late String website;
late Map<String,dynamic> company;

factory Address.fromJson(Map<String,dynamic> json) => _$AddressFromJson(json);
Map<String, dynamic> toJson() => _$AddressToJson(this);
}

Do the same thing for ‘geo’ and ‘company’ nested objects same as I did below.

Create a new file ‘users.json’ and update it like this

{
"users": "$[]user"
}

Running the command again should generate users. dart.

5- Parse the Url

Create a file named “Services. dart” and copy the below contents.

This will parse the response and get the user's list.

import 'dart:convert';
import 'package:http/http.dart' as http;
import '../../models/user.dart';
import '../../models/users.dart';

class Services {
static const String url = 'https://jsonplaceholder.typicode.com/users';

static Future<Users> getUsers() async {
try {
final response = await http.get(Uri.parse(url));
if (200 == response.statusCode) {
return parseUsers(response.body);
} else {
return Users();
}
} catch (e) {
print('Error ${e.toString()}');
return Users();
}
}

static Users parseUsers(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();
List<User> users = parsed.map<User>((json) => User.fromJson(json)).toList();
Users u = Users();
u.users = users;
return u;
}
}

6- Add the Delay for Searching

We want to search the list when the user types in the TextField, but we don’t want to do it with every keystroke, instead we will wait for the user to stop typing and search.

For that, we will write a separate class.

In this class, we will use a timer to cancel the search and start the search.

Create class debounce. dart

import 'dart:async';

import 'package:flutter/material.dart';

class Debouncer {
final int milliseconds;

VoidCallback ?action;
Timer ?_timer;
Debouncer({required this.milliseconds});

run(VoidCallback action) {
if (null != _timer) {
_timer?.cancel();
}
_timer = Timer(Duration(milliseconds: milliseconds), action);
}
}

Below is the function we use to search through the list. You can call this function in the onChange event of the TextField.

create it inside users. dart model

static Users filterList(Users users, String filterString) {
Users tempUsers = users;
List<User> _users = tempUsers.users
.where((u) =>
(u.name.toLowerCase().contains(filterString.toLowerCase())) ||
(u.email.toLowerCase().contains(filterString.toLowerCase())))
.toList();
users.users = _users;
return users;
}

7- Complete UI

Go to lib/app/module/home/views/HomeView.dart(only if your project is GetX pattern)

HomeView.dart

import 'package:flutter/material.dart';

import 'package:get/get.dart';

import '../controllers/home_controller.dart';

class HomeView extends GetView<HomeController> {
const HomeView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return GetBuilder<HomeController>(
builder: (context) {
return Scaffold(
appBar: AppBar(
title: Text(controller.title!),
),
body: Container(
padding: EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
controller.searchTF(),
SizedBox(
height: 10.0,
),
controller. list(),
],
),
),
);
}
);
}
}

Go to lib/app/module/home/controllers/HomeController.dart(only if your project is GetX pattern)

HomeController.dart

import 'package:data_modeling_filtering/models/users.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

import '../../../../services/debouncer.dart';
import '../../../../services/services.dart';

class HomeController extends GetxController {
//TODO: Implement HomeController

final count = 0.obs;
final debouncer = Debouncer(milliseconds: 1000);
Users? users;
String? title;
@override
///list
Widget list() {
return Expanded(
child: GetBuilder<HomeController>(
builder: (context) {
return ListView.builder(
itemCount: users!.users == null ? 0 : users!.users.length,
itemBuilder: (BuildContext context, int index) {
return row(index);

},
);
}
),
);

}
///
/// list row
Widget row(int index) {
return Card(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
users!.users[index].name,
style: const TextStyle(
fontSize: 16.0,
color: Colors.black,
),
),
const SizedBox(
height: 5.0,
),
Text(
users!.users[index].email.toLowerCase(),
style: const TextStyle(
fontSize: 14.0,
color: Colors.grey,
),
),
],
),
),
);
}
///search tf
Widget searchTF() {
return TextField(
decoration: const InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(
5.0,
),
),
),
filled: true,
fillColor: Colors.white60,
contentPadding: EdgeInsets.all(15.0),
hintText: 'Filter by name or email',
),
onChanged: (string) {
debouncer.run(() {

title = 'Searching...';
update();
Services.getUsers().then((usersFromServer) {

users = Users.filterList(usersFromServer, string);
title = title;
update();
});
});
},
);

}
void onInit() {

super.onInit();
title = 'Loading users...';
users = Users();
Services.getUsers().then((usersFromServer) {

users = usersFromServer;
title = title;

});
}

@override
void onReady() {
super.onReady();
}

@override
void onClose() {
super.onClose();
}

void increment() => count.value++;
}

Output:

Output while searching:

Congratulations!

You are all done. You rocked it. Today you have learned very important concepts of the fluter. Data modeling and filtering are important in flutter and in real-world app development. Clap the article and follow me for more interesting flutter & GetX articles.

Stay home, Stay healthy

Source code

The complete code of the project is here, Go and practice.

--

--

A young Mobile Apps Developer using Flutter (SDK) & Dart ( Programming Language). GetX specialist.