I'm trying to implement the provider pattern but i'm struggling in integrating it with a sqflite database. The ChangeNotifier class gets a list of string from the db and then displays it with a ListView. I suppose the problem is that when the ListView builds the widget the ChangeNotifier class has not yet initialised the list so the app crashes. How can i solve this ?
class FavouritesProvider with ChangeNotifier {
List<String> _favourites;
List<String> get favourites => [..._favourites];
FavouritesProvider() {
fetchAndSetFav();
}
Future<void> fetchAndSetFav() async {
final data = await DBHelper.instance.getFavourites();
_favourites = data;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ChangeNotifierProvider(
create: (_) => FavouritesProvider(),
child: Container (
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [
Colors.blue[200],
Colors.blue
],
stops: [0.0,1]
)
),
child: Consumer<FavouritesProvider>(
builder: (context, favouritesProvider, child) => ListView.builder (
itemCount: favouritesProvider.favourites.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
width: double.maxFinite,
child: FavouritePositionWidget(key: new Key(index.toString()), streetName: favouritesProvider.favourites[index])
);
},
)
)
)
)
);
}
this is the error i got:
The following NoSuchMethodError was thrown building Consumer<FavouritesProvider>(dirty, dependencies: [_InheritedProviderScope<FavouritesProvider>]):
The getter 'iterator' was called on null.
Receiver: null
Tried calling: iterator
Future<List<String>> getFavourites() async {
// Get a reference to the database.
Database db = await DBHelper.instance.database;
List<Map> res = await db.query(table, columns: [columnName]);
List<String> list = [];
for (Map i in res){
var str = i.values.toString();
str=str.substring(1, str.length-1);
list.add(str);
}
return list;
}
You need to await for fetchAndSetFav() before build:
class FavouritesProvider with ChangeNotifier {
Future isInitCompleted;
List<String> _favourites;
List<String> get favourites => [..._favourites];
FavouritesProvider() {
isInitCompleted = fetchAndSetFav();
}
Future<void> fetchAndSetFav() async {
final data = await DBHelper.instance.getFavourites();
_favourites = data;
}
}
And:
#override
Widget build(BuildContext context) {
return Scaffold(
body: ChangeNotifierProvider(
create: (_) => FavouritesProvider(),
child: Container (
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [
Colors.blue[200],
Colors.blue
],
stops: [0.0,1]
)
),
child: Consumer<FavouritesProvider>(
builder: (context, favouritesProvider, child) {
return FutureBuilder(
future: favouritesProvider.isInitCompleted,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: favouritesProvider.favourites.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
width: double.maxFinite,
child: FavouritePositionWidget(
key: Key(index.toString()),
streetName: favouritesProvider.favourites[index],
)
);
},
)
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
}
)
)
)
);
}
class DBHelper {
static final _databaseName = "FavDatabase.db";
static final _databaseVersion = 1;
static final table = 'favPosition';
static final columnName = 'street';
static final columnNot = 'notification';
DBHelper._privateConstructor();
static final DBHelper instance = DBHelper._privateConstructor();
static Database _database;
Future<Database> get database async {
if (_database != null) return _database;
_database = await _initDatabase();
return _database;
}
_initDatabase() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, _databaseName);
return await openDatabase(path,
version: _databaseVersion,
onCreate: _onCreate);
}
// SQL code to create the database table
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE $table (
$columnName TEXT NOT NULL PRIMARY KEY,
$columnNot BIT(1) NOT NULL
)
''');
print("db was created");
}
Future<void> insertPos(String street) async {
final Database db = await database;
final List<Map<String, dynamic>> res = await db.query(table, where: "street = ?", whereArgs: [street]);
if (!res.isNotEmpty) {
print("lo deve aggiungere");
Map<String, dynamic> row = {
DBHelper.columnName : street,
DBHelper.columnNot : 1,
};
await db.insert(table, row);
} else {
print("gia aggiunt!");
}
}
//Delete a street from the DB
Future<void> deletePos(String street) async {
Database db = await DBHelper.instance.database;
await db.delete(table, where: 'street = ?', whereArgs: [street]);
}
//Update the notification boolean
Future<void> updateNot(String street, bool value) async {
// Get a reference to the database.
Database db = await DBHelper.instance.database;
Map<String, dynamic> row = {
DBHelper.columnName : street,
DBHelper.columnNot : value?1:0,
};
await db.update(table, row, where: '${DBHelper.columnName} = ?', whereArgs: [street]);
}
//Return a String list of all street's name in the DB
Future<List<String>> getFavourites() async {
// Get a reference to the database.
Database db = await DBHelper.instance.database;
List<Map> res = await db.query(table, columns: [columnName]);
List<String> list = [];
for (Map i in res){
var str = i.values.toString();
str=str.substring(1, str.length-1);
list.add(str);
}
return list;
}
Future<bool> getNotification(String street) async {
// Get a reference to the database.
Database db = await DBHelper.instance.database;
List<Map> res = await db.query(table, columns: [columnNot], where: '${DBHelper.columnName} = ?', whereArgs: [street]);
String value = res[0].values.toString();
value = value.substring(1, 2);
if (value == "1") {
return true;
} else if (value == "0") {
return false;
} else {
throw FormatException("Value can only be 0 or 1");
}
}
}
Related
How to retrieve particular data from id on flutter and want to show data inside list view. I have created view, insert, delete and update operations.i used sqflite
my code is below.
main.dart file
class _SqliteAppState extends State<SqliteApp> {
int? selectedId;
final textController = TextEditingController();
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: TextField(
controller: textController,
),
),
body: Center(
child: FutureBuilder<List<Grocery>>(
future: DatabaseHelper.instance.getGroceries(),
builder: (BuildContext context,
AsyncSnapshot<List<Grocery>> snapshot) {
if (!snapshot.hasData) {
return Center(child: Text('Loading...'));
}
return snapshot.data!.isEmpty
? Center(child: Text('No Groceries in List.'))
: ListView(
children: snapshot.data!.map((grocery) {
return Center(
child: Card(
color: selectedId == grocery.id
? Colors.white70
: Colors.white,
child: ListTile(
title: Text(grocery.name),
onTap: () {
setState(() {
if (selectedId == null) {
textController.text = grocery.name;
selectedId = grocery.id;
} else {
textController.text = '';
selectedId = null;
}
});
},
onLongPress: () {
setState(() {
DatabaseHelper.instance.remove(grocery.id!);
});
},
),
),
);
}).toList(),
);
}),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.save),
onPressed: () async {
selectedId != null
? await DatabaseHelper.instance.update(
Grocery(id: selectedId, name: textController.text),
)
: await DatabaseHelper.instance.add(
Grocery(name: textController.text),
);
setState(() {
textController.clear();
selectedId = null;
});
},
),
),
);
}
The model class code is below
Grocery({this.id, required this.name});
factory Grocery.fromMap(Map<String, dynamic> json) => new Grocery(
id: json['id'],
name: json['name'],
);
Map<String, dynamic> toMap() {
return {
'id': id,
'name': name,
}; } }
This is my db_helper class code. I have created view, insert, delete and update operations.
class DatabaseHelper {
DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
static Database? _database;
Future<Database> get database async => _database ??= await _initDatabase();
Future<Database> _initDatabase() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, 'groceries.db');
return await openDatabase(
path,
version: 1,
onCreate: _onCreate,
);
}
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE groceries(
id INTEGER PRIMARY KEY,
name TEXT
)
''');
}
Future<List<Grocery>> getGroceries() async {
Database db = await instance.database;
var groceries = await db.query('groceries', orderBy: 'name');
List<Grocery> groceryList = groceries.isNotEmpty
? groceries.map((c) => Grocery.fromMap(c)).toList()
: [];
return groceryList;
}
Future<int> add(Grocery grocery) async {
Database db = await instance.database;
return await db.insert('groceries', grocery.toMap());
}
Future<int> remove(int id) async {
Database db = await instance.database;
return await db.delete('groceries', where: 'id = ?', whereArgs: [id]);
}
Future<int> update(Grocery grocery) async {
Database db = await instance.database;
return await db.update('groceries', grocery.toMap(),
where: "id = ?", whereArgs: [grocery.id]);
}
}
You can use this function to get the data by id:
Future<List<Grocery>> getGrocerieById(int id) async {
Database db = await instance.database;
var groceries =
await db.query('groceries', where: 'id = ?', whereArgs: [id]);
List<Grocery> groceryList = groceries.isNotEmpty
? groceries.map((c) => Grocery.fromMap(c)).toList()
: [];
return groceryList;
}
I'm trying to store data that fetched from API using sqflite
Now I'm getting an error saying...
A value of type 'List' can't be returned from the method 'getAllEmployees' because it has a return type of 'Future<List>'.
Here's my employee_provider.dart file
class EmployeeApiProvider {
Future<List<Employee>> getAllEmployees() async {
var url = "http://demo8161595.mockable.io/employee";
var response = await Dio().get(url);
return employeeFromJson(response.data).map((employee) {
DBProvider.db.createEmployee(employee);
}).toList();
}
}
How to fix this?
And other files relevant to this are...
db_provider.dart
class DBProvider {
static Database? _database;
static final DBProvider db = DBProvider._();
DBProvider._();
Future<Database?> get database async {
if (_database != null) return _database;
_database = await initDB();
return _database;
}
initDB() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
final path = join(documentsDirectory.path, 'employee_manager.db');
return await openDatabase(path, version: 1, onOpen: (db) {},
onCreate: (Database db, int version) async {
await db.execute('CREATE TABLE Employee('
'id INTEGER PRIMARY KEY,'
'email TEXT,'
'firstName TEXT,'
'lastName TEXT,'
'avatar TEXT'
')');
});
}
createEmployee(Employee newEmployee) async {
await deleteAllEmployees();
final db = await database;
final res = await db!.insert('Employee', newEmployee.toJson());
return res;
}
Future<int> deleteAllEmployees() async {
final db = await database;
final res = await db!.rawDelete('DELETE FROM Employee');
return res;
}
Future<List<Employee>> getAllEmployees() async {
final db = await database;
final res = await db!.rawQuery("SELECT * FROM EMPLOYEE");
List<Employee> list =
res.isNotEmpty ? res.map((c) => Employee.fromJson(c)).toList() : [];
return list;
}
}
employee_model.dart
List<Employee> employeeFromJson(String str) =>
List<Employee>.from(json.decode(str).map((x) => Employee.fromJson(x)));
String employeeToJson(List<Employee> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Employee {
int id;
String email;
String firstName;
String lastName;
String avatar;
Employee({
required this.id,
required this.email,
required this.firstName,
required this.lastName,
required this.avatar,
});
factory Employee.fromJson(Map<String, dynamic> json) => Employee(
id: json["id"],
email: json["email"],
firstName: json["firstName"],
lastName: json["lastName"],
avatar: json["avatar"],
);
Map<String, dynamic> toJson() => {
"id": id,
"email": email,
"firstName": firstName,
"lastName": lastName,
"avatar": avatar,
};
}
home.dart
class _HomeState extends State<AbcView> {
var isLoading = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Api to sqlite'),
centerTitle: true,
actions: <Widget>[
Container(
padding: const EdgeInsets.only(right: 10.0),
child: IconButton(
icon: const Icon(Icons.settings_input_antenna),
onPressed: () async {
await _loadFromApi();
},
),
),
Container(
padding: const EdgeInsets.only(right: 10.0),
child: IconButton(
icon: const Icon(Icons.delete),
onPressed: () async {
await _deleteData();
},
),
),
],
),
body: isLoading
? const Center(
child: CircularProgressIndicator(),
)
: _buildEmployeeListView(),
);
}
_loadFromApi() async {
setState(() {
isLoading = true;
});
var apiProvider = EmployeeApiProvider();
await apiProvider.getAllEmployees();
await Future.delayed(const Duration(seconds: 2));
setState(() {
isLoading = false;
});
}
_deleteData() async {
setState(() {
isLoading = true;
});
await DBProvider.db.deleteAllEmployees();
await Future.delayed(const Duration(seconds: 1));
setState(() {
isLoading = false;
});
}
_buildEmployeeListView() {
return FutureBuilder(
future: DBProvider.db.getAllEmployees(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
return ListView.separated(
separatorBuilder: (context, index) => const Divider(
color: Colors.black12,
),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: Text(
"${index + 1}",
style: const TextStyle(fontSize: 20.0),
),
title: Text(
"Name: ${snapshot.data[index].firstName} ${snapshot.data[index].lastName} "),
subtitle: Text('EMAIL: ${snapshot.data[index].email}'),
);
},
);
}
},
);
}
}
Maybe you could try to add await in front of the DBProvider.db.createEmployee?
class EmployeeApiProvider {
Future<List<Employee>> getAllEmployees() async {
var url = "http://demo8161595.mockable.io/employee";
var response = await Dio().get(url);
return employeeFromJson(response.data).map((employee) async {
await DBProvider.db.createEmployee(employee);
}).toList();
}
}
Hi I'm trying to create a Visiblity widget that displays if a user is on a Firebase database Array. Looks like this (members Array):
As you can see, I have created a StreamBuilder that should return the Visibility widget if the current user's username is on this Array:
StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('chats').snapshots(),
builder: (context, snapshot){
if(!snapshot.hasData){
}else {
final chats = snapshot.data.documents;
List<ChatCard> chatCards = [];
for (var chat in chats) {
final String nameOfChat = chat.data['name'];
final String lastMessageSent = chat.data['lastMessageSent'];
final List members = chat.data['members'];
final ChatCard chatCard = ChatCard(
nameOfChat: nameOfChat ?? '',
lastMessageSent: lastMessageSent ?? '',
);
chatCards.add(chatCard);
}
return Visibility(
visible: checkIfOnAnyChats(),
child: Expanded(
child: ListView(
children: chatCards,
),
),
);
}
}
),
This is what the 'checkIfOnAnyChats()' Future looks like:
Future<bool> checkIfOnAnyChats() async {
FirebaseUser user = await _auth.currentUser();
final QuerySnapshot result = await _firestore
.collection('chats')
.where('members', arrayContains: _username)
.getDocuments();
final List<DocumentSnapshot> documents = result.documents;
if(documents.length > 0) {
setState(() {
return true;
});
}else{
setState(() {
return false;
});
}
}
I'm trying to assign this value to the 'visible' boolean but it doesn't work because it is a Future bool and not a normal bool.
Any suggestions?
Thanks.
If you want to use bool that returned from a Future, you need to use FutureBuilder;
StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('chats').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
} else {
final chats = snapshot.data.documents;
List<ChatCard> chatCards = [];
for (var chat in chats) {
final String nameOfChat = chat.data['name'];
final String lastMessageSent = chat.data['lastMessageSent'];
final List members = chat.data['members'];
final ChatCard chatCard = ChatCard(
nameOfChat: nameOfChat ?? '',
lastMessageSent: lastMessageSent ?? '',
);
chatCards.add(chatCard);
}
return FutureBuilder<bool>(
future: checkIfOnAnyChats(),
builder: (context, fSnapshot) {
if (fSnapshot.hasData)
return Visibility(
visible: fSnapshot.data,
child: Expanded(
child: ListView(
children: chatCards,
),
),
);
return Center(child: CircularProgressIndicator());
},
);
}
},
),
and you don't need to use setState inside Future functions;
Future<bool> checkIfOnAnyChats() async {
FirebaseUser user = await _auth.currentUser();
final QuerySnapshot result = await _firestore
.collection('chats')
.where('members', arrayContains: _username)
.getDocuments();
final List<DocumentSnapshot> documents = result.documents;
return documents.length > 0;
}
I have seen the questions in stackoverflow which are quite similar to my question, but those question and answer dint work for me. So here is my question how to populate data from sqflite to dropdown list. Below are the dart files which I have written.Please help me with the question
dbhelper.dart
import 'package:abc/model/manage_categories.dart';
import 'package:sqflite/sqflite.dart';
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
class DatabaseHelper {
static DatabaseHelper _databaseHelper; // Singleton DatabaseHelper
static Database _database; // Singleton Database
String categoriesTable = 'categories_table';
String colId = 'id';
String colTitle = 'title';
String colDate = 'date';
DatabaseHelper._createInstance(); // Named constructor to create instance of DatabaseHelper
factory DatabaseHelper() {
if (_databaseHelper == null) {
_databaseHelper = DatabaseHelper._createInstance(); // This is executed only once, singleton object
}
return _databaseHelper;
}
Future<Database> get database async {
if (_database == null) {
_database = await initializeDatabase();
}
return _database;
}
Future<Database> initializeDatabase() async {
// Get the directory path for both Android and iOS to categories database.
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + 'categoriess.db';
// Open/create the database at a given path
var categoriessDatabase = await openDatabase(path, version: 1, onCreate: _createDb);
return categoriessDatabase;
}
void _createDb(Database db, int newVersion) async {
await db.execute('CREATE TABLE $categoriesTable($colId INTEGER PRIMARY KEY AUTOINCREMENT, $colTitle TEXT, '
'$colDate TEXT)');
}
// Fetch Operation: Get all categories objects from database
Future<List<Map<String, dynamic>>> getCategoriesMapList() async {
Database db = await this.database;
// var result = await db.rawQuery('SELECT * FROM $categoriesTable order by $colTitle ASC');
var result = await db.query(categoriesTable, orderBy: '$colTitle ASC');
return result;
}
// Insert Operation: Insert a categories object to database
Future<int> insertCategories(Categories categories) async {
Database db = await this.database;
var result = await db.insert(categoriesTable, categories.toMap());
return result;
}
// Update Operation: Update a categories object and save it to database
Future<int> updateCategories(Categories categories) async {
var db = await this.database;
var result = await db.update(categoriesTable, categories.toMap(), where: '$colId = ?', whereArgs: [categories.id]);
return result;
}
Future<int> updateCategoriesCompleted(Categories categories) async {
var db = await this.database;
var result = await db.update(categoriesTable, categories.toMap(), where: '$colId = ?', whereArgs: [categories.id]);
return result;
}
// Delete Operation: Delete a categories object from database
Future<int> deleteCategories(int id) async {
var db = await this.database;
int result = await db.rawDelete('DELETE FROM $categoriesTable WHERE $colId = $id');
return result;
}
// Get number of categories objects in database
Future<int> getCount() async {
Database db = await this.database;
List<Map<String, dynamic>> x = await db.rawQuery('SELECT COUNT (*) from $categoriesTable');
int result = Sqflite.firstIntValue(x);
return result;
}
// Get the 'Map List' [ List<Map> ] and convert it to 'categories List' [ List<Categories> ]
Future<List<Categories>> getCategoriesList() async {
var categoriesMapList = await getCategoriesMapList(); // Get 'Map List' from database
int count = categoriesMapList.length; // Count the number of map entries in db table
List<Categories> categoriesList = List<Categories>();
// For loop to create a 'categories List' from a 'Map List'
for (int i = 0; i < count; i++) {
categoriesList.add(Categories.fromMapObject(categoriesMapList[i]));
}
return categoriesList;
}
}
Add_store_item.dart
import 'package:flutter/material.dart';
import 'package:abc/database/dbhelper_categories.dart';
import 'package:abc/database/dbhelper_manage_inventory.dart';
import 'package:abc/model/Manageinventory_class.dart';
import 'package:abc/model/manage_categories.dart';
class AddStoreItem extends StatefulWidget {
final Inventory inventory;
AddStoreItem(this.inventory);
#override
State<StatefulWidget> createState() => new AddStoreItemState();
}
class AddStoreItemState extends State<AddStoreItem> {
DatabaseHelper databaseHelper = DatabaseHelper();
List<Categories> categoriesList = <Categories>[];
int count = 0;
DBProvider _db = DBProvider();
TextEditingController _itemController;
TextEditingController _quantityController;
TextEditingController _categoryController;
TextEditingController _unitController;
TextEditingController _locationController;
#override
void initState() {
super.initState();
_loadCategorieslist();
_itemController = new TextEditingController(text: widget.inventory.item);
_quantityController = new TextEditingController(text: widget.inventory.quantity);
_categoryController = new TextEditingController(text: widget.inventory.category);
_unitController = new TextEditingController(text: widget.inventory.unit);
_locationController = new TextEditingController(text: widget.inventory.location);
}
_loadCategorieslist()async{
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Add Inventory')
),
body: SingleChildScrollView(
child: Container(
margin: EdgeInsets.all(15.0),
alignment: Alignment.center,
child: Column(
children: <Widget>[
SizedBox(height: 10),
TextField(
controller: _itemController,
decoration: InputDecoration(labelText: 'Item'),
),
SizedBox(height: 10),
TextField(
controller: _quantityController,
decoration: InputDecoration(labelText: 'Quantity'),
),
SizedBox(height: 10),
DropdownButton<String>(
value: categoriesList,
items: categoriesList.map((String){
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}),
isExpanded: true,
onChanged: (value) {
print("value: $value");
},
hint: Text(
"Units",
style: TextStyle(
// color: Colors.black,
),
),
),
DropdownButton<String>(
items: [
DropdownMenuItem<String>(
value: "1",
child: Text(
"First",
),
),
DropdownMenuItem<String>(
value: "2",
child: Text(
"Second",
),
),
],
isExpanded: true,
onChanged: (value) {
print("value: $value");
},
hint: Text(
"Location",
style: TextStyle(
// color: Colors.black,
),
),
),
SizedBox(height: 10),
RaisedButton(
child: (widget.inventory.id != null) ? Text('Update') : Text('Add Inventory'),
onPressed: () {
_addInventory();
},
),
],
),
),
),
);
}
void _addInventory() {
if (widget.inventory.id != null) {
_db
.updateNote(Inventory.withId(
widget.inventory.id,
_itemController.text,
_quantityController.text,
_categoryController.text,
_unitController.text,
_locationController.text,
))
.then((_) => Navigator.pop(context, 'update'));
} else {
_db
.saveNote(Inventory(
_itemController.text,
_quantityController.text,
_categoryController.text,
_unitController.text,
_locationController.text,
))
.then((_) => Navigator.pop(context, 'save'));
}
}
}
This how I managed to populate the list of data from sqflite to drop down
Declared list from sqflite to AddStoreItemState as below
DatabaseHelper databaseHelper = DatabaseHelper();
List<Categories> categoriesList ;
Categories _category;
Now wrap the drop down button as below
Center(
child: DropdownButtonFormField<Categories>(
hint: Text('Categories'),
value: _category,
onChanged: (Categories value){
setState(() {
_category = value;
});
},
items: categoriesList.map((user) => DropdownMenuItem<Categories>(
child: Text(user.cname),
value: user,
)
).toList(),
),
),
In AddStoreItemState change your _loadCategorieslist()async method to:
Future<List<Categories>> _loadCategorieslist() async => databaseHelper.getCategoriesMapList();
And wrap your DropdownButton with a FutureBuilder
This is how I read data from SqfLite to use it in a drop-down or data table, in this case barcode records.
Here is the model, which includes a fromJson() function like below:
class Barcode {
String code;
String itemNo;
Barcode({
this.code,
this.itemNo,
});
Map<String, dynamic> toMap() => {
'code': code,
'itemNo': itemNo,
};
factory Barcode.fromJson(Map<String, dynamic> parsedJson) {
return Barcode(
code: parsedJson['code'],
itemNo: parsedJson['itemNo'],
);
}
}
Here is how I read barcodes (all) from SqfLite:
static Future<List<Barcode>> getAll() async {
final db = await DbUtil.database;
var response = await db.query(tableName);
List<Barcode> list = response.map((c) => Barcode.fromJson(c)).toList();
return list;
}
Here is for reading just one barcode:
static Future<Barcode> get(String barcode) async {
final db = await DbUtil.database;
var response = await db.query(tableName, where: "$pkName = ?", whereArgs: ['$barcode']);
return response.isNotEmpty ? Barcode.fromJson(response.first) : null;
}
Then to call it:
var barcode = await BarcodeDb.get(scanText);
Try this out, it should work for you.
I have created an app that stores some notes in sqlite database. I did all CRUD operations and it's working well, but when I'm trying to make search operation inside my database with SearchDelegate, I got some problem. I'll show you my code before I make search with SearchDelegate
databaseHelper:
import 'dart:async';
import 'package:plants/model/plant.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class DatabaseHelper {
static final DatabaseHelper _instance = new DatabaseHelper.internal();
factory DatabaseHelper() => _instance;
final String tableNote = 'noteTable';
final String columnId = 'id';
final String columnLocation = 'location';
final String columnTitle = 'title';
final String columnDescription = 'description';
static Database _db;
DatabaseHelper.internal();
Future<Database> get db async {
if (_db != null) {
return _db;
}
_db = await initDb();
return _db;
}
initDb() async {
String databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'notes.db');
// await deleteDatabase(path); // just for testing
var db = await openDatabase(path, version: 1, onCreate: _onCreate);
return db;
}
void _onCreate(Database db, int newVersion) async {
await db.execute(
'CREATE TABLE $tableNote($columnId INTEGER PRIMARY KEY,$columnLocation TEXT, $columnTitle TEXT, $columnDescription TEXT)');
}
Future<int> saveNote(Note note) async {
var dbClient = await db;
var result = await dbClient.insert(tableNote, note.toMap());
// var result = await dbClient.rawInsert(
// 'INSERT INTO $tableNote ($columnTitle, $columnDescription) VALUES (\'${note.title}\', \'${note.description}\')');
return result;
}
Future<List> getAllNotes() async {
var dbClient = await db;
var result = await dbClient.query(tableNote, columns: [columnId, columnLocation , columnTitle, columnDescription]);
// var result = await dbClient.rawQuery('SELECT * FROM $tableNote');
return result.toList();
}
Future<int> getCount() async {
var dbClient = await db;
return Sqflite.firstIntValue(await dbClient.rawQuery('SELECT COUNT(*) FROM $tableNote'));
}
Future<Note> getNote(int id) async {
var dbClient = await db;
List<Map> result = await dbClient.query(tableNote,
columns: [columnId, columnLocation , columnTitle, columnDescription],
where: '$columnId = ?',
whereArgs: [id]);
// var result = await dbClient.rawQuery('SELECT * FROM $tableNote WHERE $columnId = $id');
if (result.length > 0) {
return new Note.fromMap(result.first);
}
return null;
}
Future<int> deleteNote(int id) async {
var dbClient = await db;
return await dbClient.delete(tableNote, where: '$columnId = ?', whereArgs: [id]);
// return await dbClient.rawDelete('DELETE FROM $tableNote WHERE $columnId = $id');
}
Future<int> updateNote(Note note) async {
var dbClient = await db;
return await dbClient.update(tableNote, note.toMap(), where: "$columnId = ?", whereArgs: [note.id]);
// return await dbClient.rawUpdate(
// 'UPDATE $tableNote SET $columnTitle = \'${note.title}\', $columnDescription = \'${note.description}\' WHERE $columnId = ${note.id}');
}
Future close() async {
var dbClient = await db;
return dbClient.close();
}
}
Class Notes
class Note {
int _id;
String _location;
String _title;
String _description;
Note(this._location,this._title, this._description);
Note.map(dynamic obj) {
this._id = obj['id'];
this._location = obj['location'];
this._title = obj['title'];
this._description = obj['description'];
}
int get id => _id;
String get location => _location;
String get title => _title;
String get description => _description;
Map<String, dynamic> toMap() {
var map = new Map<String, dynamic>();
if (_id != null) {
map['id'] = _id;
}
map['location'] = _location;
map['title'] = _title;
map['description'] = _description;
return map;
}
Note.fromMap(Map<String, dynamic> map) {
this._id = map['id'];
this._location = map ['location'];
this._title = map['title'];
this._description = map['description'];
}
}
List.dart
import 'package:flutter/material.dart';
import 'package:plants/AddPlant.dart';
import 'package:plants/model/plant.dart';
import 'database/dbhelper.dart';
class ListViewNote extends StatefulWidget {
#override
State<StatefulWidget> createState() => new ListViewNoteState();
}
class ListViewNoteState extends State<ListViewNote> {
List<Note> items = new List();
DatabaseHelper db = new DatabaseHelper();
#override
void initState() {
super.initState();
db.getAllNotes().then((notes) {
setState(() {
notes.forEach((note) {
items.add(Note.fromMap(note));
});
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Plant List',
),
centerTitle: true,
actions: <Widget>[
IconButton(icon: Icon(Icons.search,
color: Colors.white,), onPressed: (){
showSearch(context: context,
delegate: DataSearch(this.items));
})
],
),
body: Center(
child: ListView.builder(
itemCount: items.length,
padding: const EdgeInsets.all(15.0),
itemBuilder: (context, position) {
return Dismissible(
background: stackBehindDismiss(),
key: ObjectKey(items[position]),
child: Card(
elevation: 2.0,
margin: new EdgeInsets.symmetric(horizontal: 0.0,vertical: 2.0),
child: Column(
children: <Widget>[
ListTile(
title: Text(
'${items[position].title}',
style: TextStyle(
fontSize: 22.0,
color: Colors.deepOrangeAccent,
),
),
subtitle: Text(
'${items[position].description}' + '' + '${items[position].location}',
style: new TextStyle(
fontSize: 18.0,
fontStyle: FontStyle.italic,
),
),
onTap: () => _navigateToNote(context, items[position]),
),
],
),
),
onDismissed: (dirction){
var item = items.elementAt(position);
_deleteNote(context, items[position], position);
Scaffold.of(context).showSnackBar(SnackBar(
content: Text("Item deleted"),
));
},
);
}
),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.green[700],
child: Icon(Icons.add),
onPressed: () => _createNewNote(context),
),
);
}
void _deleteNote(BuildContext context, Note note, int position) async {
db.deleteNote(note.id).then((notes) {
setState(() {
items.removeAt(position);
});
});
}
void _navigateToNote(BuildContext context, Note note) async {
String result = await Navigator.push(
context,MaterialPageRoute(builder: (context) => NoteScreen(note)),
);
if (result == 'update') {
db.getAllNotes().then((notes) {
setState(() {
items.clear();
notes.forEach((note) {
items.add(Note.fromMap(note));
});
});
});
}
}
void _createNewNote(BuildContext context) async {
String result = await Navigator.push(
context,MaterialPageRoute(builder: (context) => NoteScreen(Note('', '', ''))),
);
if (result == 'save') {
db.getAllNotes().then((notes) {
setState(() {
items.clear();
notes.forEach((note) {
items.add(Note.fromMap(note));
});
});
});
}
}
stackBehindDismiss() {
return Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.only(right: 20.0),
color: Colors.green[700],
child: Icon(
Icons.delete,
color: Colors.white,
),
);
}
}
class DataSearch extends SearchDelegate<Note> {
DatabaseHelper db = new DatabaseHelper();
final List<Note> items = new List();
List<Note> suggestion = new List();
// ListViewNoteState i = ListViewNoteState();
DataSearch(this.suggestion);
#override
ThemeData appBarTheme(BuildContext context) {
assert(context != null);
final ThemeData theme = Theme.of(context);
assert(theme != null);
return theme;
}
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(icon: Icon(Icons.clear), onPressed: () {
query = '';
} )
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: (){
close(context, null);
},
);
}
#override
Widget buildResults(BuildContext context) {
}
#override
Widget buildSuggestions(BuildContext context) {
final suggestion = query.isEmpty
? items
: items.where((target) => target.title.startsWith(query)).toList();
if(items.isEmpty)
{
print("Null");
}
return ListView.builder(
itemBuilder: (context, position)=>
ListTile(
title: Text(items[position].title),
),
itemCount: suggestion.length,
);
}
}
On CRUD, everything is working well and I'm adding 3 records but when I'm using SearchDelegate to implement search, I not getting any result.
The thing I need is to searchlist from database using searchbar
Try this:
return ListView.builder(
itemBuilder: (context, index)=>
ListTile(
title: Text(suggestion[index].title),
),
It should work and display the right results, at least mine is working this way, but I think you'll have to point to items list when you build your results or when you tap to open it or something like that.