Problem :
Im trying to delete data from Flutter DataTable, when i pressed the alertdialog and click yes the Data already deleted on the Database but the data still shown in the screen until i click the back navigation button and back to list of user.
Expected :
The Datatable should automatically refreshed with current data minus the data that i deleted earlier.
Datatable
// ignore_for_file: deprecated_member_use
import 'package:flutter/material.dart';
import 'package:flutter_auth/Models/nasabah.dart';
import 'package:flutter_auth/network/nasabah_service.dart';
import 'package:flutter_auth/screens/Menu/DataNasabah/detailnasabah.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';
class DataNasabah extends StatefulWidget {
#override
_DataNasabahState createState() => _DataNasabahState();
}
class _DataNasabahState extends State<DataNasabah> {
String nama_debitur = '';
List<Nasabah> _nasabah = [];
#override
void initState() {
super.initState();
_loadUserData();
_getNasabah();
}
_loadUserData() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
var user = jsonDecode(localStorage.getString('user'));
if (user != null) {
setState(() {
nama_debitur = user['nama_debitur'];
});
}
}
_getNasabah() {
NasabahService.getUser().then((nasabah) {
if (mounted) {
setState(() {
_nasabah = nasabah;
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('Data Nasabah'),
// backgroundColor: Color(0xff151515),
// automaticallyImplyLeading: false,
),
body: SingleChildScrollView(
child: PaginatedDataTable(
rowsPerPage: 10,
header: Align(
alignment: Alignment.center,
child: Text(
'Data Nasabah',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
// Text("Data Nasabah"),
columns: [
DataColumn(
label: Expanded(
child: Text(
'ID Nasabah',
textAlign: TextAlign.center,
)),
),
DataColumn(
label: Expanded(
child: Text(
'Nama Nasabah',
textAlign: TextAlign.center,
)),
),
DataColumn(
label: Expanded(
child: Text(
'Aksi',
textAlign: TextAlign.center,
)),
),
],
source: NasabahDataTableSource(userData: _nasabah, context: context),
),
),
);
}
}
class NasabahDataTableSource extends DataTableSource {
BuildContext context;
NasabahDataTableSource({this.context, this.userData});
final List<Nasabah> userData;
#override
DataRow getRow(int index) {
return DataRow.byIndex(
index: index,
cells: [
DataCell(Align(
alignment: Alignment.center,
child: Text(
"${userData[index].id}",
))),
DataCell(Align(
alignment: Alignment.center,
child: Text("${userData[index].nama_debitur}"),
)),
DataCell(
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
icon: Icon(Icons.navigate_next),
color: Colors.blueAccent,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailNasabah(
nasabah: userData[index],
),
),
);
},
),
IconButton(
icon: Icon(Icons.delete),
color: Colors.red,
onPressed: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Hapus Data Nasabah'),
content: Text(
'Apakah anda yakin ingin menghapus data nasabah ini?'),
actions: [
FlatButton(child: Text('Yes'), onPressed: () {
NasabahService.deleteUser(userData[index].id);
Navigator.pop(context);
})
],
),
);
},
)
],
),
),
// DataCell(
// FlatButton(
// child: Icon(
// Icons.chevron_right,
// color: Colors.red,
// ),
// onPressed: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => DetailNasabah(
// nasabah: userData[index],
// ),
// ),
// );
// },
// ),
// ),
],
);
}
#override
bool get isRowCountApproximate => false;
#override
int get rowCount => userData.length;
#override
int get selectedRowCount => 0;
void sort<T>(Comparable<T> getField(Nasabah d), bool ascending) {
userData.sort((Nasabah a, Nasabah b) {
if (!ascending) {
final Nasabah c = a;
a = b;
b = c;
}
final Comparable<T> aValue = getField(a);
final Comparable<T> bValue = getField(b);
return Comparable.compare(aValue, bValue);
});
notifyListeners();
}
}
Api
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
class Network {
final String _url = 'http://192.168.100.207:8080/api/';
// 192.168.1.2 is my IP, change with your IP address
var token;
_getToken() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
token = jsonDecode(localStorage.getString('token'));
}
auth(data, apiURL) async {
var fullUrl = _url + apiURL;
return await http.post(fullUrl,
body: jsonEncode(data), headers: _setHeaders());
}
getData(apiURL) async {
var fullUrl = _url + apiURL;
await _getToken();
return await http.get(
fullUrl,
headers: _setHeaders(),
);
}
deleteData(apiURL, id) async {
var fullUrl = _url + apiURL + '/' + id.toString();
await _getToken();
return await http.delete(
fullUrl,
headers: _setHeaders(),
);
}
_setHeaders() => {
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token',
};
}
Service
import 'package:flutter_auth/Models/nasabah.dart';
import 'api.dart';
import 'dart:convert';
class NasabahService {
static String baseUrl = "mstdebitur";
static Future<List<Nasabah>> getUser() async {
final response = await Network().getData(baseUrl);
List<Nasabah> list = parseResponse(response.body);
return list;
}
static Future<List<Nasabah>> deleteUser(id) async {
final response = await Network().deleteData(baseUrl, id);
List<Nasabah> list = parseResponse(response.body);
return list;
}
static List<Nasabah> parseResponse(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<Nasabah>((json) => Nasabah.fromJson(json)).toList();
}
}
Related
i have data stucture like:
/Admin/Dashboard/MRmZh9mixve1CV3M0EI8wfyDnb82/20220607/Anonymous/Entry
i want to read all that data that is under
/Admin/Dashboard/MRmZh9mixve1CV3M0EI8wfyDnb82
i tried this buts it returns empty
String collection = "/Admin/Dashboard/MRmZh9mixve1CV3M0EI8wfyDnb82";
await FirebaseFirestore.instance.collection(collection).get().then(
(res) => print("Successfully completed ${res}"),
onError: (e) => print("Error completing: $e"),
);
so basically i want lo read all the collections in it that has further documents in each collection
I could use this way to extract data from specific documents and collections.
final _firestore = FirebaseFirestore.instance;
void getMessages() async{
final docRef = await _firestore.collection('1234#123.com').doc('123123').collection('record').get();
for (var Ref in docRef.docs) {
print(Ref.data());
}
}
void getMessages44() async{
final docRef = await _firestore.collection('Admin').doc('Dashboard').collection('MRmZh9mixve1CV3M0EI8wfyDnb82').get();
for (var Ref in docRef.docs) {
print(Ref.data());
}
}
void test() async {
print("test");
// List<dynamic> userList = [];
QuerySnapshot querySnapshot = await _firestore.collection('1234#123.com').doc('123123').collection('record').where('Item', isEqualTo:"sdfsf").get();
// userList = querySnapshot.docs.map((e) => dynamic.User.fromMap(e.data())).toList();
final allData = querySnapshot.docs.map((doc) => doc.data()).toList();
// final allData = querySnapshot.docs.map((doc) => doc.get('fieldName')).toList();
print(allData);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Record'),
leading: null,
actions: <Widget>[
IconButton(
icon: const Icon(Icons.add),
onPressed: (){
Navigator.pushNamed(context, creationCategory.id);
},
),
IconButton(
icon: const Icon(Icons.settings),
onPressed: () async {
// await getData();
// getMessages();
// getMessages();
getMessages44();
test();
// getMessages33();
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => const ItemDetailsScrrent()),
// );
},
),
],
),
body: SafeArea(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('Trahs Collection',
style: const TextStyle(
color: Colors.black38, fontWeight: FontWeight.bold, fontSize: 40),
),
ItemStream(),
],
),
),
),
);
}
bloc.dart
part 'news_article_loader_event.dart';
part 'news_article_loader_state.dart';
part 'news_article_loader_bloc.freezed.dart';
#injectable
class NewsArticleLoaderBloc
extends Bloc<NewsArticleLoaderEvent, NewsArticleLoaderState> {
NewsArticleLoaderBloc(this.iBlogPost)
: super(NewsArticleLoaderState.initial());
final INewsArticle iBlogPost;
#override
Stream<NewsArticleLoaderState> mapEventToState(
NewsArticleLoaderEvent event) async* {
yield NewsArticleLoaderState.loadInProgress();
final failureOrSuccess = await iBlogPost.getDataNews();
yield failureOrSuccess.fold((l) => NewsArticleLoaderState.loadFailure(l),
(r) => NewsArticleLoaderState.loadSuccess(r));
}
}
repository.dart
import 'dart:convert';
import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart';
import 'package:injectable/injectable.dart';
import 'package:mone/app_constant.dart';
import 'package:mone/model/news/blog_post.dart';
import 'package:mone/repositories/i_news_repository.dart';
import 'package:shared_preferences/shared_preferences.dart';
#Injectable(as: INewsArticle)
class BLogPostRepository implements INewsArticle {
final Dio dio;
// int page = 1;
final SharedPreferences prefs;
BLogPostRepository(this.dio, this.prefs);
#override
Future<Either<String, List<NewsBlogModel>>> getDataNews() async {
try {
final token = prefs.get(kAccesTokenKey);
String url = '/api/v1/cms?size=30';
var response = await dio.get(url,
options: Options(
headers: {
'Accept': 'aplication/json',
'Authorization': 'bearer $token',
},
));
if (response.statusCode == 200) {
final listNews = (response.data['items'] as List)
.map((e) => NewsBlogModel.fromJson(e as Map<String, dynamic>))
.toList();
return right(listNews);
}
return left('error: ${response.statusCode}');
} catch (e) {
return left('error get data $e');
}
}
#override
Future<Either<String, List<NewsBlogModel>>> getDataNewsbyId() async {
// TODO: implement getDataNewsbyId
try {
final token = prefs.get(kAccesTokenKey);
String urlbyid = '/api/v1/cms/id';
var response = await dio.get(urlbyid,
options: Options(headers: {
'Accept': 'aplication/json',
'Authorization': 'bearer $token',
}));
if (response.statusCode == 200) {
final dataNewsbyId = (response.data['items'] as List)
.map((e) => NewsBlogModel.fromJson(e as Map<String, dynamic>))
.toList();
return right(dataNewsbyId);
}
return left("error:${response.statusCode}");
} catch (e) {
return left("error get data $e");
}
}
}
I have the code below where I have provided the BLoC code for the code and also for the repository code. but I'm still confused about how to connect it to the UI that I made. explanation please.
below also my code has succeeded to call all data list from API. but when I want to try to find the data list in the get, but can't.
UI.dart
part of '../screens.dart';
class NewsScreen extends StatefulWidget {
#override
_NewsScreenState createState() => _NewsScreenState();
}
class _NewsScreenState extends State<NewsScreen> {
Widget customTitleBar = const Text('Berita');
Icon customIcon = new Icon(Icons.search, color: primaryColor);
TextEditingController filterController = TextEditingController();
// String filter = '';
// void initState(){
// }
#override
Widget build(BuildContext context) {
// bloc provider berguna untuk menambahkan data dari bloc ke ui,
return BlocProvider(
create: (context) =>
getIt<NewsArticleLoaderBloc>()..add(NewsArticleLoaderEvent.started()),
child: Scaffold(
appBar: AppBar(
title: customTitleBar,
actions: <Widget>[
IconButton(
onPressed: () {
setState(() {
if (this.customIcon.icon == Icons.search) {
this.customIcon =
new Icon(Icons.close, color: primaryColor, size: 30);
this.customTitleBar = new TextField(
style: new TextStyle(
color: Colors.white,
),
decoration: new InputDecoration(
prefixIcon: new Icon(Icons.search,
color: primaryColor, size: 30),
hintText: "Search...",
hintStyle: new TextStyle(color: Colors.white)),
cursorColor: primaryColor,
onChanged: (value) async {
if (value.isEmpty) {
setState(() {});
return;
}
},
controller:filterController,
);
} else {
this.customIcon =
new Icon(Icons.search, color: primaryColor, size: 30);
this.customTitleBar = new Text("Berita");
}
});
},
icon: customIcon,
),
],
),
body: BlocBuilder<NewsArticleLoaderBloc, NewsArticleLoaderState>(
builder: (context, state) {
return state.map(
initial: (_) => Container(),
loadInProgress: (_) => Center(
child: SpinKitCircle(
color: primaryColor,
),
),
loadFailure: (state) => Center(
child: Text(state.failure),
),
loadSuccess: (state) {
if (state.datenews.isEmpty) {
return Center(
child: Text("data tidak di temukan"),
);
} else {
return ListView.separated(
padding: EdgeInsets.all(8.0),
itemCount: state.datenews.length,
separatorBuilder: (BuildContext context, int index) {
return SizedBox(
height: 4,
);
},
itemBuilder: (BuildContext context, int index) {
final newsBlog = state.datenews[index];
return ContentNews(
newsBlog: newsBlog,
);
},
);
}
},
);
},
),
),
);
}
}
I am using some code from an older version of File Picker, the null safety version will mess up my other code so I'm using 1.1.1.
the code isn't incorrect because it the same on the file picker package example. can anyone help plz?
the code goes as followed
void openFileExplorer() async {
try {
_path = null;
if (_multiPick) {
_paths = await FilePicker.getMultiFilePath(
type: _pickType, **fileExtension**: _extension);
} else {
_path = await FilePicker.getFilePath(
type: _pickType, **fileExtension**: _extension);
}
uploadToFirebase();
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
}
if (!mounted) return;
}
Try this one
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: UploadMultipleImageDemo(),
);
}
}
class UploadMultipleImageDemo extends StatefulWidget {
UploadMultipleImageDemo() : super();
final String title = 'Firebase Storage';
#override
UploadMultipleImageDemoState createState() => UploadMultipleImageDemoState();
}
class UploadMultipleImageDemoState extends State<UploadMultipleImageDemo> {
//
String _path;
Map<String, String> _paths;
List<String> extensions;
FileType _pickType;
bool _multiPick = false;
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
List<StorageUploadTask> _tasks = <StorageUploadTask>[];
void openFileExplorer() async {
try {
_path = null;
if (_multiPick) {
_paths = await FilePicker.getMultiFilePath(
type: _pickType, allowedExtensions: extensions);
} else {
_path = await FilePicker.getFilePath(
type: _pickType, allowedExtensions: extensions);
}
//uploadToFirebase();
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
}
if (!mounted) return;
}
// uploadToFirebase() {
// if (_multiPick) {
// _paths.forEach((fileName, filePath) => {upload(fileName, filePath)});
// } else {
// if (_path != null) {
// String fileName = _path
// .split('/')
// .last;
// String filePath = _path;
// upload(fileName, filePath);
// }
// }
// }
// upload(fileName, filePath) {
// extensions = fileName.toString().split('.').last as List<String>;
// StorageReference storageRef =
// FirebaseStorage.instance.ref().child(fileName);
// final StorageUploadTask uploadTask = storageRef.putFile(
// File(filePath),
// StorageMetadata(
// contentType: '$_pickType/$extensions',
// ),
// );
// setState(() {
// _tasks.add(uploadTask);
// });
// extensions = null;
// }
dropDown() {
return DropdownButton(
hint: new Text('Select'),
value: _pickType,
items: <DropdownMenuItem>[
new DropdownMenuItem(
child: new Text('Audio'),
value: FileType.audio,
),
new DropdownMenuItem(
child: new Text('Image'),
value: FileType.image,
),
new DropdownMenuItem(
child: new Text('Video'),
value: FileType.video,
),
new DropdownMenuItem(
child: new Text('Any'),
value: FileType.any,
),
],
onChanged: (value) => setState(() {
_pickType = value;
}),
);
}
String _bytesTransferred(StorageTaskSnapshot snapshot) {
return '${snapshot.bytesTransferred}/${snapshot.totalByteCount}';
}
#override
Widget build(BuildContext context) {
final List<Widget> children = <Widget>[];
_tasks.forEach((StorageUploadTask task) {
final Widget tile = UploadTaskListTile(
task: task,
onDismissed: () => setState(() => _tasks.remove(task)),
onDownload: () => downloadFile(task.lastSnapshot.ref),
);
children.add(tile);
});
return new MaterialApp(
home: new Scaffold(
key: _scaffoldKey,
appBar: new AppBar(
title: Text(widget.title),
),
body: new Container(
padding: EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
dropDown(),
SwitchListTile.adaptive(
title: Text('Pick multiple files', textAlign: TextAlign.left),
onChanged: (bool value) => setState(() => _multiPick = value),
value: _multiPick,
),
OutlineButton(
onPressed: () => openFileExplorer(),
child: new Text("Open file picker"),
),
SizedBox(
height: 20.0,
),
Flexible(
child: ListView(
children: children,
),
),
],
),
),
),
);
}
Future<void> downloadFile(StorageReference ref) async {
final String url = await ref.getDownloadURL();
final http.Response downloadData = await http.get(url);
final Directory systemTempDir = Directory.systemTemp;
final File tempFile = File('${systemTempDir.path}/tmp.jpg');
if (tempFile.existsSync()) {
await tempFile.delete();
}
await tempFile.create();
final StorageFileDownloadTask task = ref.writeToFile(tempFile);
final int byteCount = (await task.future).totalByteCount;
var bodyBytes = downloadData.bodyBytes;
final String name = await ref.getName();
final String path = await ref.getPath();
print(
'Success!\nDownloaded $name \nUrl: $url'
'\npath: $path \nBytes Count :: $byteCount',
);
_scaffoldKey.currentState.showSnackBar(
SnackBar(
backgroundColor: Colors.white,
content: Image.memory(
bodyBytes,
fit: BoxFit.fill,
),
),
);
}
}
class UploadTaskListTile extends StatelessWidget {
const UploadTaskListTile(
{Key key, this.task, this.onDismissed, this.onDownload})
: super(key: key);
final StorageUploadTask task;
final VoidCallback onDismissed;
final VoidCallback onDownload;
String get status {
String result;
if (task.isComplete) {
if (task.isSuccessful) {
result = 'Complete';
} else if (task.isCanceled) {
result = 'Canceled';
} else {
result = 'Failed ERROR: ${task.lastSnapshot.error}';
}
} else if (task.isInProgress) {
result = 'Uploading';
} else if (task.isPaused) {
result = 'Paused';
}
return result;
}
String _bytesTransferred(StorageTaskSnapshot snapshot) {
return '${snapshot.bytesTransferred}/${snapshot.totalByteCount}';
}
#override
Widget build(BuildContext context) {
return StreamBuilder<StorageTaskEvent>(
stream: task.events,
builder: (BuildContext context,
AsyncSnapshot<StorageTaskEvent> asyncSnapshot) {
Widget subtitle;
if (asyncSnapshot.hasData) {
final StorageTaskEvent event = asyncSnapshot.data;
final StorageTaskSnapshot snapshot = event.snapshot;
subtitle = Text('$status: ${_bytesTransferred(snapshot)} bytes sent');
} else {
subtitle = const Text('Starting...');
}
return Dismissible(
key: Key(task.hashCode.toString()),
onDismissed: (_) => onDismissed(),
child: ListTile(
title: Text('Upload Task #${task.hashCode}'),
subtitle: subtitle,
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Offstage(
offstage: !task.isInProgress,
child: IconButton(
icon: const Icon(Icons.pause),
onPressed: () => task.pause(),
),
),
Offstage(
offstage: !task.isPaused,
child: IconButton(
icon: const Icon(Icons.file_upload),
onPressed: () => task.resume(),
),
),
Offstage(
offstage: task.isComplete,
child: IconButton(
icon: const Icon(Icons.cancel),
onPressed: () => task.cancel(),
),
),
Offstage(
offstage: !(task.isComplete && task.isSuccessful),
child: IconButton(
icon: const Icon(Icons.file_download),
onPressed: onDownload,
),
),
],
),
),
);
},
);
}
}
I'm trying to make an app that has basically the same mechanics as a simple todo-app. My problem is, when I try to open the screen where I can create a new project/todo(new_project_screen), there should be loaded some TextFields, but they don't. Instead, this error occurs. I tried several solutions from stackoverflow, but nothing worked and I have no idea why it's not working.(sorry for my bad english, I'm not a native xD)
Here is my code:
main.dart:
import 'package:flutter/material.dart';
import 'package:leisy/surface/main_screen.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(App());
}
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Leisy',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MainScreen(),
);
}
}
main_screen.dart:
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:sqflite/sqflite.dart';
import 'package:leisy/db/database_helper.dart';
import 'package:leisy/model/project.dart';
import 'package:leisy/surface/settings_screen.dart';
import 'package:leisy/surface/new_project_screen.dart';
class MainScreen extends StatefulWidget {
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
DatabaseHelper databaseHelper = DatabaseHelper();
List<Project> projectList = [];
int count = 0;
#override
Widget build(BuildContext context) {
if (projectList == null) {
projectList = <Project>[];
updateListView();
}
debugPrint("Building entire main screen scaffold");
return Scaffold(
appBar: AppBar(
title: Text("Leisy"),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Center(
child: Text(
"Menü",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 25,
),
),
),
decoration: BoxDecoration(color: Colors.blue),
),
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
onTap: () => {Navigator.of(context).pop()},
),
ListTile(
leading: Icon(Icons.add),
title: Text('Neues Projekt'),
onTap: () => {
Navigator.of(context).push(new MaterialPageRoute(
builder: (context) => new NewProjectScreen()))
},
),
ListTile(
leading: Icon(Icons.settings),
title: Text('Einstellungen'),
onTap: () => {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => SettingsScreen()))
},
)
],
),
),
body: getProjectListView(),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: navigateToNewProject,
),
);
}
ListView getProjectListView() {
TextStyle titleStyle = Theme.of(context).textTheme.subtitle1;
return ListView.builder(
itemCount: count,
itemBuilder: (BuildContext context, int position) {
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blue,
),
title: Text(
this.projectList[position].name,
style: titleStyle,
),
subtitle: Text(this.projectList[position].date),
onTap: () {
debugPrint('ListTile Tapped');
//navigateToDetail() einfügen
},
),
);
});
}
void _showSnackBar(BuildContext context, String message) {
final snackBar = SnackBar(
content: Text(message),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
void navigateToNewProject() async {
bool result = await Navigator.push(context, MaterialPageRoute(builder: (context) => NewProjectScreen()));
if (result == true) {
updateListView();
}
}
void updateListView() {
final Future<Database> dbFuture = databaseHelper.initDB();
dbFuture.then((database) {
Future<List<Project>> projectListFuture = databaseHelper.getProjectList();
projectListFuture.then((projectList) {
setState(() {
this.projectList = projectList;
this.count = projectList.length;
});
});
});
}
}
new_project_screen.dart:
import 'package:flutter/material.dart';
import 'package:leisy/db/database_helper.dart';
import 'package:leisy/model/project.dart';
import 'package:leisy/surface/main_screen.dart';
import 'package:leisy/surface/settings_screen.dart';
class NewProjectScreen extends StatefulWidget {
#override
_NewProjectScreenState createState() => _NewProjectScreenState();
}
class _NewProjectScreenState extends State<NewProjectScreen> {
Project project;
DatabaseHelper helper = DatabaseHelper();
TextEditingController nameController = TextEditingController();
TextEditingController dateController = TextEditingController();
TextEditingController locationController = TextEditingController();
#override
Widget build(BuildContext context) {
nameController.text = project.name;
dateController.text = project.date;
locationController.text = project.location;
return Scaffold(
appBar: AppBar(
title: Text("Neues Projekt"),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
},
),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Center(
child: Text(
"Menü",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 25,
),
),
),
decoration: BoxDecoration(color: Colors.blue),
),
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
onTap: () => {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => MainScreen()))
},
),
ListTile(
leading: Icon(Icons.add),
title: Text('Neues Projekt'),
onTap: () => {Navigator.of(context).pop()},
),
ListTile(
leading: Icon(Icons.settings),
title: Text('Einstellungen'),
onTap: () => {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => SettingsScreen()))
},
)
],
),
),
body: Padding(
padding: EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
TextField(
controller: nameController,
decoration: InputDecoration(labelText: 'Name'),
style: TextStyle(fontSize: 20),
onChanged: (value) {
setState(() {
updateName();
});
},
),
TextField(
decoration: InputDecoration(labelText: 'Datum'),
style: TextStyle(fontSize: 20),
onChanged: (value) {
setState(() {
updateDate();
});
},
),
TextField(
decoration: InputDecoration(labelText: 'Ort'),
style: TextStyle(fontSize: 20),
onChanged: (value) {
setState(() {
updateLocation();
});
},
),
Row(
children: <Widget>[
Expanded(
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
Theme.of(context).primaryColorDark),
),
child: Text('Speichern'),
onPressed: () {
setState(() {
_save();
});
},
)),
Expanded(
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
Theme.of(context).primaryColorDark),
),
child: Text('Abbrechen'),
onPressed: () {
setState(() {
_cancel();
});
},
)),
],
)
],
)
)
);
}
void _save() async {
Navigator.pop(context, true);
await helper.insertProject(project);
}
void _showSnackBar(String message) {
SnackBar snackBar = SnackBar(content: Text(message));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
void _cancel() async {
Navigator.pop(context, true);
_showSnackBar('Vorgang abgebrochen');
}
void updateName() {
project.name = nameController.text;
}
void updateDate() {
project.date = dateController.text;
}
void updateLocation() {
project.location = locationController.text;
}
}
project.dart:
class Project {
int _id;
String _name;
String _date;
String _location;
String _personaldb;
Project(this._name, this._date, this._location, this._personaldb);
Project.withId(
this._id, this._name, this._date, this._location, this._personaldb);
int get id => _id;
String get name => _name;
String get date => _date;
String get location => _location;
String get personalDB => _personaldb;
set name(String newName) {
if (newName.length <= 63) {
this._name = newName;
}
}
set date(String newDate) {
this._date = newDate;
}
set location(String newLocation) {
this._location = newLocation;
}
set personalDB(String newPersonalDB) {
this._personaldb = newPersonalDB;
}
Map<String, dynamic> toMap() {
var map = Map<String, dynamic>();
if (id != null) {
map['id'] = _id;
}
map['name'] = _name;
map['date'] = _date;
map['location'] = _location;
map['personalDB'] = _personaldb;
return map;
}
Project.fromMapObject(Map<String, dynamic> map) {
this._id = map['id'];
this._name = map['name'];
this._date = map['date'];
this._location = map['location'];
this._personaldb = map['personalDB'];
}
}
database_helper.dart:
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:leisy/model/project.dart';
class DatabaseHelper {
static DatabaseHelper _databaseHelper;
static Database _database;
String projectTable = 'project_table';
String colId = 'id';
String colName = 'name';
String colDate = 'date';
String colLocation = 'location';
String colPersonalDB = 'personalDB';
DatabaseHelper._createInstance();
factory DatabaseHelper() {
if (_databaseHelper == null) {
_databaseHelper = DatabaseHelper._createInstance();
}
return _databaseHelper;
}
Future<Database> get database async {
if (_database == null) {
_database = await initDB();
}
return _database;
}
Future<Database> initDB() async {
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + 'projects.db';
var projectsDB = await openDatabase(path, version: 1, onCreate: _createDB);
return projectsDB;
}
void _createDB(Database db, int newVersion) async {
await db.execute('CREATE TABLE $projectTable('
'$colId INTEGER PRIMARY KEY AUTOINCREMENT,'
'$colName TEXT,'
'$colDate TEXT,'
'$colLocation TEXT,'
'$colPersonalDB TEXT)');
}
Future<List<Map<String, dynamic>>> getProjectMapList() async {
Database db = await this.database;
var result = await db.query(projectTable);
return result;
}
Future<int> insertProject(Project project) async {
Database db = await this.database;
var result = await db.insert(projectTable, project.toMap());
return result;
}
Future<int> updateProject(Project project) async {
var db = await this.database;
var result = await db.update(projectTable, project.toMap(), where: '$colId = ?', whereArgs: [project.id]);
return result;
}
Future<int> deleteProject(int id) async {
var db = await this.database;
int result = await db.delete(projectTable, where: '$colId = $id');
return result;
}
Future<int> getCount() async {
Database db = await this.database;
List<Map<String, dynamic>> x = await db.rawQuery('SELECT COUNT (*) from $projectTable');
int result = Sqflite.firstIntValue(x);
return result;
}
Future<List<Project>> getProjectList() async {
var projectMapList = await getProjectMapList();
int count = projectMapList.length;
List<Project> projectList = <Project>[];
for (int i = 0; i < count; i++) {
projectList.add(Project.fromMapObject(projectMapList[i]));
}
return projectList;
}
}
Error:
======== Exception caught by widgets library =======================================================
The following NoSuchMethodError was thrown building NewProjectScreen(dirty, state: _NewProjectScreenState#670bc):
The getter 'name' was called on null.
Receiver: null
Tried calling: name
The relevant error-causing widget was:
NewProjectScreen file:///C:/Users/gabri/AndroidStudioProjects/leisy/lib/surface/main_screen.dart:116:89
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
#1 _NewProjectScreenState.build (package:leisy/surface/new_project_screen.dart:24:35)
#2 StatefulElement.build (package:flutter/src/widgets/framework.dart:4612:27)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4495:15)
#4 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4667:11)
...
====================================================================================================
If anybody can help me, I would really appreciate it. And if anything in my code is inconvenient or badly implemented, please be kind with me I'm a beginner at this.
The file new_project_screen.dart has the problem
To be exact, the problem can be found in lines 24:35
And seems like that project variable is null project.name;
That is because you are creating Project project but isn't instancied yet. Is just a null variable
See the image below, will help you to understand a bit:
https://dartpad.dev/1ebc897cd3f547cc0b79e52290a63653
So to fix it, you need to create the instance previously
I have a problem with FutureBuilder, it refresh and execute code again when there is a change like when i change value of radio button, i click on radio and it reloads all futurebuilder it seems.
EDIT : i have corrected the problem and here is my solution, i am not sure it works all time
My full code is :
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'dart:async';
// Create a Form widget.
class Affiche_grille extends StatefulWidget {
#override
_Affiche_grille_State createState() {
return _Affiche_grille_State();
}
}
// Create a corresponding State class.
// This class holds data related to the form.
class _Affiche_grille_State extends State<Affiche_grille> {
#override
final _formKey = GlobalKey<FormState>();
List<String> radioValues = [];
Future<List<Match>> grid;
Future <List<Match>> Grille_display() async {
// SERVER LOGIN API URL
var url = 'http://www.axis-medias.fr/game_app/display_grid.php';
// Store all data with Param Name.
var data = {'id_grille': 1};
// Starting Web API Call.
var response = await http.post(url, body: json.encode(data));
// Getting Server response into variable.
var jsondata = json.decode(response.body);
List<Match> Matchs = [];
for (var u in jsondata) {
Match match = Match(u["equipe1"],u["equipe2"],u["type_prono"]);
Matchs.add(match);
radioValues.add("N");
}
return Matchs;
}
void initState() {
grid = Grille_display();
super.initState();
}
#override
Widget build(BuildContext context) {
final appTitle = 'MONEYFREE';
return MaterialApp(
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: Text(appTitle),
),
body: Container(
child:
FutureBuilder(
future: grid,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Container (
child: Center(
child: Text("Chargement en cours...")
)
);
}
else {
List<Match> values = snapshot.data;
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
DataTable(
columnSpacing: 20,
columns: [
DataColumn(
label: Text("Libelle Match"),
numeric: false,
tooltip: "",
),
DataColumn(
label: Text("1"),
numeric: false,
tooltip: "",
),
DataColumn(
label: Text("N"),
numeric: false,
tooltip: "",
),
DataColumn(
label: Text("2"),
numeric: false,
tooltip: "",
),
],
rows:
List.generate(values.length, (index) {
return DataRow(
cells: [
DataCell(
Text(values[index].equipe1.toString() + " - " + values[index].equipe2.toString()),
),
DataCell(
Radio(
value: "1",
groupValue: radioValues[index],
onChanged: (val) {
setState(() {
radioValues[index] = val;
print('Change 1');
print(radioValues);
});
},
),
),
DataCell(
Radio(
value: "N",
groupValue: radioValues[index],
onChanged: (val) {
setState(() {
radioValues[index] = val;
print('Change N');
print(radioValues);
});
},
),
),
DataCell(
Radio(
value: "2",
groupValue: radioValues[index],
onChanged: (val) {
setState(() {
radioValues[index] = val;
print('Change 2');
print(radioValues);
});
},
),
),
]
);
}).toList(),
),
Center(
child: RaisedButton(
color: Colors.green,
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(9, 9, 9, 9),
child: Text('VALIDER VOTRE GRILLE'),
onPressed: () {
Valide_grille();
},
),
),
],
)
);
};
},
),
),
),
);
}
Future Valide_grille() async{
// For CircularProgressIndicator.
bool visible = false ;
// Showing CircularProgressIndicator.
setState(() {
visible = true ;
});
// SERVER LOGIN API URL
var url = 'http://www.axis-medias.fr/game_app/valide_grid.php';
var concatenate='';
radioValues.forEach((item){
concatenate=concatenate+item;
});
// Store all data with Param Name.
var data = {'id_membre':1, 'id_grille':1,'result':concatenate};
print (data);
var grille_encode=jsonEncode(data);
print(grille_encode);
// Starting Web API Call.
var response = await http.post(url, body: grille_encode);
print(response.body);
// Getting Server response into variable.
var message = json.decode(response.body);
// If the Response Message is Matched.
if(message == 'OK')
{
print('VALIDATION DE LA GRILLE OK');
// Hiding the CircularProgressIndicator.
setState(() {
visible = false;
});
}else{
// If Email or Password did not Matched.
// Hiding the CircularProgressIndicator.
setState(() {
visible = false;
});
// Showing Alert Dialog with Response JSON Message.
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text(message),
actions: <Widget>[
FlatButton(
child: new Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
}
class Match {
final String equipe1;
final String equipe2;
final String typeprono;
const Match(this.equipe1, this.equipe2, this.typeprono);
}
You can copy paste run full code below
Reason
didUpdateWidget of the FutureBuilder state is being called every time a rebuild is issued. This function checks if the old future object is different from the new one, and if so, refires the FutureBuilder.
https://github.com/flutter/flutter/issues/11426#issuecomment-414047398
Solution
Future _future;
#override
void initState() {
// TODO: implement initState
_future = Grille_display();
}
...
child: FutureBuilder(
future: _future,
working demo
full code
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'dart:async';
// Create a Form widget.
class Affiche_grille extends StatefulWidget {
#override
_Affiche_grille_State createState() {
return _Affiche_grille_State();
}
}
// Create a corresponding State class.
// This class holds data related to the form.
class _Affiche_grille_State extends State<Affiche_grille> {
#override
final _formKey = GlobalKey<FormState>();
List<String> radioValues = [];
Future<List<Match>> Grille_display() async {
// SERVER LOGIN API URL
var url = 'http://www.axis-medias.fr/game_app/display_grid.php';
// Store all data with Param Name.
var data = {'id_grille': 1};
// Starting Web API Call.
var response = await http.post(url, body: json.encode(data));
// Getting Server response into variable.
var jsondata = json.decode(response.body);
List<Match> Matchs = [];
for (var u in jsondata) {
Match match = Match(u["equipe1"], u["equipe2"], u["type_prono"]);
Matchs.add(match);
}
return Matchs;
}
Future _future;
#override
void initState() {
// TODO: implement initState
_future = Grille_display();
}
#override
Widget build(BuildContext context) {
final appTitle = 'MONEYFREE';
return MaterialApp(
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: Text(appTitle),
),
body: Container(
child: FutureBuilder(
future: _future,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(child: Text("Chargement en cours...")));
} else {
List<Match> values = snapshot.data;
values.forEach((m) {
radioValues.add("N");
//like N or something
});
print('valeur radio après initialisation');
print(radioValues);
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
DataTable(
columnSpacing: 20,
columns: [
DataColumn(
label: Text("Libelle Match"),
numeric: false,
tooltip: "",
),
DataColumn(
label: Text("1"),
numeric: false,
tooltip: "",
),
DataColumn(
label: Text("N"),
numeric: false,
tooltip: "",
),
DataColumn(
label: Text("2"),
numeric: false,
tooltip: "",
),
],
rows: List.generate(values.length, (index) {
return DataRow(cells: [
DataCell(
Text(values[index].equipe1.toString() +
" - " +
values[index].equipe2.toString()),
),
DataCell(
Radio(
value: "1",
groupValue: radioValues[index],
onChanged: (val) {
setState(() {
radioValues[index] = val;
print('Change 1');
print(radioValues);
});
},
),
),
DataCell(
Radio(
value: "N",
groupValue: radioValues[index],
onChanged: (val) {
setState(() {
radioValues[index] = val;
print(radioValues);
});
},
),
),
DataCell(
Radio(
value: "2",
groupValue: radioValues[index],
onChanged: (val) {
setState(() {
radioValues[index] = val;
print(radioValues);
});
},
),
),
]);
}).toList(),
),
Center(
child: RaisedButton(
color: Colors.green,
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(9, 9, 9, 9),
child: Text('VALIDER VOTRE GRILLE'),
onPressed: () {
Valide_grille();
},
),
),
],
));
}
;
},
),
),
),
);
}
Future Valide_grille() async {
// For CircularProgressIndicator.
bool visible = false;
// Showing CircularProgressIndicator.
setState(() {
visible = true;
});
// SERVER LOGIN API URL
var url = 'http://www.axis-medias.fr/game_app/valide_grid.php';
// Store all data with Param Name.
var data = jsonEncode(radioValues);
print(radioValues);
// Starting Web API Call.
var response = await http.post(url, body: json.encode(data));
// Getting Server response into variable.
var message = json.decode(response.body);
// If the Response Message is Matched.
if (message == 'OK') {
print('VALIDATION DE LA GRILLE OK');
// Hiding the CircularProgressIndicator.
setState(() {
visible = false;
});
} else {
// If Email or Password did not Matched.
// Hiding the CircularProgressIndicator.
setState(() {
visible = false;
});
// Showing Alert Dialog with Response JSON Message.
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text(message),
actions: <Widget>[
FlatButton(
child: new Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
}
class Match {
final String equipe1;
final String equipe2;
final String typeprono;
const Match(this.equipe1, this.equipe2, this.typeprono);
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Affiche_grille(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}