I want to remove an entry from listview and db at the same time using swipe like this:
onPressed: () {
// Delete the item from DB
setState(() {
data.indexOf(data[index]);
data.removeAt(index);
});
Navigator.of(context).pop();
},
the methode doesn't seem to be working also i want help with how can I trigger the update on this page without the user to reopen the page.
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
List<Ia> data = snapshot.data;
print(data);
return Dismissible(
background: slideRightBackground(),
secondaryBackground: slideLeftBackground(),
key: Key(data[index].toString()),
// ignore: missing_return
confirmDismiss: (direction) async {
if (direction == DismissDirection.endToStart) {
final bool res = await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: Text(
"Are you sure you want to delete ` ${data[index]}?"),`
actions: <Widget>[
// ignore: deprecated_member_use
FlatButton(
child: Text(
"Cancel",
style:
TextStyle(color: Colors.black),
),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text(
"Delete",
style: TextStyle(color: Colors.red),
),
onPressed: () {
// Delete the item from DB
setState(() {
data.indexOf(data[index]);
data.removeAt(index);
});
Navigator.of(context).pop();
},
),
],
);
});
return res;
} else {
// Navigate to edit page;
}
},
child: Card(
child: ListTile(
title: Text(data[index].name,
style: TextStyle(fontSize: 16)),
subtitle: Row(
children: [
Text(
"Status",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold),
),
SizedBox(
width: 5,
),
Text(
data[index].state,
style: TextStyle(
color: Colors.lightBlue,
fontSize: 12,
),
),
],
),
),
),
);
});
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Right now you're only removing it from the list, which is pointless as the stream is from the database. You need to remove it from the database only.
In your onPressed(), remove setState() and add this :
await _fireStoreInstance.runTransaction(
(Transaction transaction) async {
transaction.delete(YOUR_DOC_REF_HERE); // i'd assume data[index].reference
},
Calling API in dismiss should be working,if you are using api to delete data from server database you need to call a delete function
Sample UI Code
class MyAppState extends State<MyApp> {
final items = List<String>.generate(20, (i) => 'Item ${i + 1}');
#override
Widget build(BuildContext context) {
final title = 'Dismissing Items';
return MaterialApp(
title: title,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return Dismissible(
key: Key(item),
// what to do after an item has been swiped away.
onDismissed: (direction) {
// Remove the item from the data source.
setState(() {
Deletedata(pass your id here);
items.removeAt(index);
});
// Then show a snackbar.
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('$item deleted')));
},
// Show a red background as the item is swiped away.
background: Container(color: Colors.red),
child: ListTile(title: Text('$item')),
);
},
),
),
);
}
}
Delete function
Future<void> Deletedata(String id) async{
var response = await http.delete(Uri.parse("http://xxx.xx.xx.xx/api/delete_route/$id"), headers: {'Content-Type': 'application/json;charset=UTF-8', 'Charset': 'utf-8', 'Authorization': 'token',},);
print('Response status: ${response.statusCode}');
print('Response body: ${response.body}');
}
Related
I am trying to toggle between Login Screen and HomeScreen based on the user status. The logic seems to be working as long as I don't put HomeScreen.
I replaced HomeScreen with a different screen to check and the app works as it should. It displays different screens on hot restart based on the user's login status. But as soon as I try to put HomeScreen I get null operator used on null value error.
Here is the toggle logic.
class Testing extends StatefulWidget {
const Testing({super.key});
#override
State<Testing> createState() => _TestingState();
}
class _TestingState extends State<Testing> {
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: TodoServiceHelper().checkifLoggedIn(),
builder: ((context, snapshot) {
if (!snapshot.hasData) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
if (snapshot.hasError) {
print(snapshot.hasError);
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
if (snapshot.data!.isNotEmpty) {
print(snapshot.data);
return RegisterPage();
// returning HomePage gives null check operator used on null value error
} else
return Login();
}),
);
}
}
Here is the HomeScreen
class HomePage extends StatefulWidget {
String? username;
HomePage({this.username});
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final GlobalKey<FormState> formKey = GlobalKey();
TextEditingController termController = TextEditingController();
void clearText() {
termController.clear();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
onPressed: () {
User loginUser =
User(username: widget.username.toString(), isLoggedIn: false);
TodoServiceHelper().updateUserName(loginUser);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (BuildContext context) => Login()));
},
icon: Icon(Icons.logout),
color: Colors.white,
)
],
title: FutureBuilder(
future: TodoServiceHelper().getTheUser(widget.username!),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
return Text(
'Welcome ${snapshot.data!.username}',
style: TextStyle(color: Colors.white),
);
}),
),
body: SingleChildScrollView(
child: Column(children: [
Column(
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: Form(
key: formKey,
child: Column(
children: <Widget>[
TextFormField(
controller: termController,
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(),
labelText: 'search todos',
),
),
TextButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ShowingSerachedTitle(
userNamee: widget.username!,
searchTerm: termController.text,
)),
);
print(termController.text);
clearText();
setState(() {});
},
child: Text(
'Search',
)),
Divider(
thickness: 3,
),
],
),
),
),
],
),
Container(
child: Stack(children: [
Positioned(
bottom: 0,
child: Text(
' done Todos',
style: TextStyle(fontSize: 12),
),
),
IconButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
CheckingStuff(userNamee: widget.username!)),
);
setState(() {});
},
icon: Icon(Icons.filter),
),
]),
),
Divider(
thickness: 3,
),
Container(
child: TodoListWidget(name: widget.username!),
height: 1000,
width: 380,
)
]),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Color.fromARGB(255, 255, 132, 0),
onPressed: () async {
await showDialog(
barrierDismissible: false,
context: context,
builder: ((context) {
return AddNewTodoDialogue(name: widget.username!);
}),
);
setState(() {});
},
child: Icon(Icons.add),
),
);
}
}
The function used to return user with loginStatus true
Future<List<User>> checkifLoggedIn() async {
final Database db = await initializeDB();
final List<Map<String, Object?>> result = await db.query(
'users',
where: 'isLoggedIn = ?',
whereArgs: ['1'],
);
List<User> filtered = [];
for (var item in result) {
filtered.add(User.fromMap(item));
}
return filtered;
}
the problem is here
you used ! sign on a nullable String , and this string is nullable,
try to use this operation (??) so make it
widget.username??"" by this line you will check if the user name is null it will be replaced by an empty string.
When I delete the data on the row, there are no changes after doing the delete, but when I return the menu to the dashboard page and open to the new Customer Data page, the changes are visible. Here I have given setState so that the list view can be refreshed immediately, but after I give setState it still can't be refreshed. And then an error like the following appears.
My problem on link https://youtu.be/gC0P-k-2myw
This is mystatefullwidget.
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,
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,
onUserDeleted:(){
setState(() {
});
}
),
),
),
);
}
}
class NasabahDataTableSource
class NasabahDataTableSource extends DataTableSource {
BuildContext context;
Function onUserDeleted;
NasabahDataTableSource({this.context, this.userData, this.onUserDeleted});
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: [
TextButton(
child: Text('Yes'),
onPressed: () {
NasabahService.deleteUser(userData[index].id);
onUserDeleted();
})
],
),
);
},
)
],
),
),
],
);
}
Full Source Code
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,
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,
onUserDeleted:(){
setState(() {
});
}
),
),
),
);
}
}
class NasabahDataTableSource extends DataTableSource {
BuildContext context;
Function onUserDeleted;
NasabahDataTableSource({this.context, this.userData, this.onUserDeleted});
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: [
TextButton(
child: Text('Yes'),
onPressed: () {
NasabahService.deleteUser(userData[index].id);
onUserDeleted();
})
],
),
);
},
)
],
),
),
],
);
}
i haven't find that solution. Please help.
code snippet
api.dart
deleteData(apiURL, id) async {
var fullUrl = _url + apiURL + '/' + id.toString();
await _getToken();
return await http.delete(
fullUrl,
headers: _setHeaders(),
);
}
nasabah_service
static Future<List<Nasabah>> deleteUser(id) async {
final response = await Network().deleteData(baseUrl, id);
List<Nasabah> list = parseResponse(response.body);
return list;
}
You need to refresh your updated List after delet user.
so we can do
onPressed: () async {
await NasabahService.deleteUser(userData[index].id);
.then((value) async {
await //NasabahService.getUser();
});
},
I have a to do app which lists all todos in in a screen
This is my listview
class assignedTask extends StatefulWidget {
static const String id = 'assignedTask';
#override
_assignedTaskState createState() => _assignedTaskState();
}
class _assignedTaskState extends State<assignedTask> {
String Title;
String Summary;
var tasks;
crudMedthods crudObj = new crudMedthods();
var documentID;
var documents;
Future<bool> addDialog(BuildContext context) async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Add Data', style: TextStyle(fontSize: 15.0)),
content: Container(
height: 125.0,
width: 150.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
decoration: InputDecoration(hintText: 'Enter Title'),
onChanged: (value) {
this.Title = value;
},
),
SizedBox(height: 5.0),
TextField(
decoration: InputDecoration(hintText: 'Enter Summary'),
onChanged: (value) {
this.Summary = value;
},
),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Add'),
textColor: Colors.blue,
onPressed: () {
Navigator.of(context).pop();
crudObj.addData({
'Title': this.Title,
'Summary': this.Summary
}).then((result) {
dialogTrigger(context);
}).catchError((e) {
print(e);
});
},
)
],
);
});
}
Future<bool> updateDialog(BuildContext context, selectedDoc) async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Update Data', style: TextStyle(fontSize: 15.0)),
content: Container(
height: 125.0,
width: 150.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
decoration: InputDecoration(hintText: 'Title'),
onChanged: (value) {
this.Title = value;
},
),
SizedBox(height: 5.0),
TextField(
decoration: InputDecoration(hintText: 'Enter Summary'),
onChanged: (value) {
this.Summary = value;
},
),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Update'),
textColor: Colors.blue,
onPressed: () {
Navigator.of(context).pop();
crudObj.updateData(selectedDoc, {
'Title': this.Title,
'Summary': this.Summary
}).then((result) {
// dialogTrigger(context);
}).catchError((e) {
print(e);
});
},
)
],
);
});
}
Future<bool> dialogTrigger(BuildContext context) async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Job Done', style: TextStyle(fontSize: 15.0)),
content: Text('Added'),
actions: <Widget>[
FlatButton(
child: Text('Alright'),
textColor: Colors.blue,
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
}
#override
void initState() {
crudObj.getData().then((results) {
setState(() {
tasks = results;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Assigned Tasks'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
addDialog(context);
},
),
IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
crudObj.getData().then((results) {
setState(() {
tasks = results;
});
});
},
)
],
),
body: _TaskList(),
);
}
Widget _TaskList() {
if (tasks != null) {
return StreamBuilder(
stream: tasks,
// ignore: missing_return
builder: (context, snapshot) {
if (snapshot.data != null) {
return ListView.builder(
itemCount: snapshot.data.documents.length,
padding: EdgeInsets.all(7.0),
itemBuilder: (context, i) {
return ListTile(
title: Text(snapshot.data.documents[i].data["Title"]??""),
subtitle: Text(snapshot.data.documents[i].data["Summary"]??""),
/*onTap: () {
*//*
updateDialog(
context, snapshot.data.documents[i].documentID);
},*/
onTap: (){
Navigator.push(context,MaterialPageRoute(builder:(context)=>DetailPage(snapshot.data.douments[i])));
}, onLongPress: () {
crudObj.deleteData(snapshot.data.documents[i].documentID);
},
);
},
);
}
return CircularProgressIndicator();
},
);
} else {
return Text('Loading, Please wait..');
}
}
}
When i press ontap it should go to the detail page which shows details of only that particular task(note: i now have only the values Title and summary for now, i will add rest later they should show in the detail page)
My detailview is as follows
class DetailPage extends StatelessWidget {
DocumentSnapshot detailDocument;
DetailPage(this.detailDocument);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text( detailDocument.data["Title"]),
),
body: Center(
child: Text(detailDocument.data["Summary"]),
),
);
}
}
I am getting an error
The following NoSuchMethodError was thrown building Builder(dirty):
Class 'QuerySnapshot' has no instance getter 'douments'.
Receiver: Instance of 'QuerySnapshot'
Tried calling: douments
The relevant error-causing widget was:
MaterialApp file:///C:/Users/TRICON/AndroidStudioProjects/taskmanager/lib/main.dart:21:14
When the exception was thrown, this was the stack:
0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
1 _assignedTaskState._TaskList.... (package:taskmanager/screens/assignedtask.dart:208:106)
You are using
Navigator.push(context,MaterialPageRoute(builder:(context)=>DetailPage(snapshot.data.douments[i])));
instead of
Navigator.push(context,MaterialPageRoute(builder:(context)=>DetailPage(snapshot.data.documents[i])));
It's just a difference in the spelling of douments as documents.
EDIT - Complete Code. I added SetState and it didnt refresh.
class ForumPost extends StatefulWidget {
#override
_ForumPostState createState() => new _ForumPostState();
final User user;
final String postID;
final Features features;
ForumPost({Key key, #required this.user, #required this.postID, #required this.features}) : super(key: key);
}
class _ForumPostState extends State<ForumPost> {
List<TabItem> navItems = <TabItem>[
TabItem(icon: Icons.home, title: 'Home'),
TabItem(icon: Icons.help_outline, title: 'Support'),
TabItem(icon: Icons.people, title: 'Contacts'),
TabItem(icon: Icons.chat_bubble, title: 'Forum')
];
List data;
Future<String> getPostsByCategory() async {
var response = await http.post(
Uri.encodeFull("http://url/api/ForumPostByPostID"),
headers: {"Content-Type": "application/json",
'Accept': 'application/json',},
body: json.encode({'PostID' : widget.postID }));
this.setState(() {
data = json.decode(response.body);
}
);
return "Success!";
}
#override void initState() {
this.getPostsByCategory();
}
#override
Widget build(BuildContext context) {
Future forumUpVote(String userid, String postID) async {
final response =
await http.post('http://url/api/ForumUpvote',
headers: {"Content-Type": "application/json",
'Accept': 'application/json',},
body: json.encode({'userid' : userid , 'postID' : widget.postID}));
if (response.statusCode == 204) {
// Call was successful
// Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ForumPost(user: widget.user, postID: widget.postID, features: widget.features)));
setState(() {
});
}
}
return new Scaffold(
appBar: AppBar(
backgroundColor: Colors.grey,
centerTitle: true,
actions: <Widget>[
new IconButton( icon: new Icon(
FontAwesomeIcons.plusCircle,),
tooltip: 'Ask Question',
onPressed: (){
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ForumAskQuestion( user: widget.user, features: widget.features)));
}
),
new IconButton( icon: new Icon(
FontAwesomeIcons.search,),
tooltip: 'Search Community',
onPressed: (){
print('pressed');
}
)
]
),
bottomNavigationBar: ConvexAppBar.builder(
user: widget.user,
features: widget.features,
count: navItems.length,
backgroundColor: Colors.grey[700],
tabBuilder: (BuildContext context, int index, bool active) {
var navigationItem = navItems[index];
var _color = active ? Colors.white : Colors.white60;
var _icon = active
? navigationItem.activeIcon ?? navigationItem.icon
: navigationItem.icon;
return Container(
color: Colors.transparent,
padding: EdgeInsets.only(bottom: 2),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Icon(_icon, color: _color),
Text(navigationItem.title, style: TextStyle(color: _color, fontSize: 12.0))
],
),
);
},
actionBuilder: (BuildContext context, int index, bool active) {
var _color = active ? Colors.white : Colors.white60;
return Stack(
alignment: Alignment.center,
children: <Widget>[
SizedBox(
width: 60,
height: 60,
child: Container(
decoration:
BoxDecoration(shape: BoxShape.circle, color: _color),
child: Icon(
Icons.chat_bubble,
size: 40,
color: Colors.red[200],
),
),
)
],
);
},
),
body: Container(
decoration: BoxDecoration(
gradient: new LinearGradient(
colors: [Colors.white, Colors.grey],
begin: Alignment.bottomLeft,
end: Alignment.topRight
)
),
child: ListView.builder(
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, int index){
return new Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.beenhere, color: Colors.red, size: 35.0,),
title: new Text(data[index]["Title"],style: new TextStyle(fontSize: 20.0, color: Colors.grey) ),
subtitle: new Text(data[index]["Content"],style: new TextStyle(fontSize: 15.0, color: Colors.grey)),
trailing: new Text(data[index]["FirstName"],style: new TextStyle(fontSize: 15.0, color: Colors.grey)),
isThreeLine: true,
),
ButtonTheme.bar( // make buttons use the appropriate styles for cards
child: ButtonBar(
children: <Widget>[
FlatButton(
padding: EdgeInsets.all(10.0),
child: Column( // Replace with a Row for horizontal icon + text
children: <Widget>[
Icon(Icons.thumb_up, color: Colors.grey[600]),
Text(data[index]["UpVote"].toString(), style: new TextStyle(color: Colors.grey))
],
),
onPressed: () {
forumUpVote(widget.user.userId, widget.postID);
},
),
FlatButton(
padding: EdgeInsets.all(10.0),
child: Column( // Replace with a Row for horizontal icon + text
children: <Widget>[
Icon(Icons.question_answer, color: Colors.blue),
Text("Answer", style: new TextStyle(color: Colors.grey))
],
),
onPressed: () {
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ForumAnswerQuestion( user: widget.user, postID: widget.postID, posttitle: data[index]["Title"], features: widget.features )));
},
),
FlatButton(
child: Column( // Replace with a Row for horizontal icon + text
children: <Widget>[
Icon(Icons.info_outline, color: Colors.orangeAccent),
Text(data[index]["AnswerCount"].toString(), style: new TextStyle(color: Colors.grey))
],
),
onPressed: () {
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ForumPostsDetail( user: widget.user, postID: widget.postID, posttitle: data[index]["Title"], content: data[index]["Content"], features: widget.features )));
},
),
FlatButton(
child: Column( // Replace with a Row for horizontal icon + text
children: <Widget>[
Icon(Icons.flag, color: Colors.red),
Text("Flag", style: new TextStyle(color: Colors.red))
],
),
onPressed: () {
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ForumPostsDetail( user: widget.user, postID: widget.postID, posttitle: data[index]["Title"], content: data[index]["Content"], features: widget.features )));
},
),
],
),
),
]
),
);
},
)
)
);
}
}
We have a forum written in flutter and an upvote post function that calls a web api via http. We need the icon with the count of upvotes to refresh but not the entire screen. How is this done in flutter? We used to achieve this via AJAX in web pages.
Here is the code for the upvote icon
children: <Widget>[
Icon(Icons.thumb_up, color: Colors.green),
Text(data[index]["UpVote"].toString(), style: new TextStyle(color: Colors.grey))
],
Code for HTTP Call
Future forumUpVote(String userid, String postID) async {
final response =
await http.post('http://url/api/ForumUpvote',
headers: {"Content-Type": "application/json",
'Accept': 'application/json',},
body: json.encode({'userid' : userid , 'postID' : widget.postID}));
if (response.statusCode == 204) {
// Call was successful
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ForumPost(user: widget.user, postID: widget.postID, features: widget.features)));
}
}
When the response is successful it sends them back to the same screen which is why the entire screen refreshes. So Im guessing that we need to setstate() or something along those lines. Im not sure how to fix this.
Can you create a separate stateful widget that is referenced in your current widget which has the upvote button along with the upvote counter?
Then when it is pressed you only call the setState() method within that child widget. This will only refresh that widget and not the whole page.
In below code I made two widgets. The first (called "mainWidget") is the one that you do not want to refresh and it references the second widget (called "refreshingWidget"). They both hold state but only the refreshing widget is updated when you call setState().
class mainWidget extends StatefulWidget {
#override
_mainWidgetState createState() => _mainWidgetState();
}
class _mainWidgetState extends State<mainWidget> {
#override
Widget build(BuildContext context) {
print("Main widget is refreshing");
return new refreshingWidget();
}
}
class refreshingWidget extends StatefulWidget {
#override
_refreshingWidgetState createState() => _refreshingWidgetState();
}
class _refreshingWidgetState extends State<refreshingWidget> {
#override
Widget build(BuildContext context) {
print("Refreshing widget is refreshing.");
return RaisedButton(
onPressed: () {
setState(() {});
},
child: Text("Press to refresh this widget"));
}
}
I have an app which generates a new Card wrapped in a GestureDetector when the FAB of Scaffold is pressed. the app was working fine but i wanted to implement a delete card functionality and when i added that, the app doesnt recognize the return statements in the build function. I feel like im missing something obvious but since i am new to flutter i am struggling to find what went wrong.
Whole code:
class _Starting_screenState extends State<Starting_screen> {
int _count = 1;
#override
Widget build(BuildContext context) {
{
List<Widget> cardList = new List.generate(
_count, (int i) => new createCard());
SystemChrome.setEnabledSystemUIOverlays([]);
_deleteNoDo(int id, int index) async {
debugPrint("Deleted Item!");
setState(() {
cardList.removeAt(index);
});
void addItems() async {
setState(() {
cardList.insert(0, new GestureDetector(
onTap: () async {
await Navigator.push(context, MaterialPageRoute(
builder: (context) =>
TodoList(), // this just navigates to another screen ; not important in this question
)
);
},
child: Card(
child: ListTile(
title: Text("project 1"),
trailing: new Listener(
key: new Key(UniqueKey().toString()),
child: new Icon(Icons.remove_circle,
color: Colors.redAccent,),
onPointerDown: (pointerEvent) => _deleteNoDo(id, index),
),
subtitle: whitefontstylemont(text: "project 1",
size: 20,)) //this is just a custom TextStyle
),
));
});
}
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () async {
setState(() {
_count += 1;
});
},
heroTag: "btn2",
child: Icon(Icons.add, color: Color(whitecolor),),
backgroundColor: Color(redcolor),),
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
flexibleSpace: FlexibleSpaceBar(
),
actions: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.only(top: 20, right: 10),
child: whitefontstyle(
text: "Remaining tasks for today - ${cardList
.length}", size: 20,),
),
),
],
),
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2
),
delegate: new SliverChildBuilderDelegate((context,
index) {
return cardList[index];
},
childCount: cardList.length
)
),
]
)
);
}
}
}
}
delete function:
_deleteNoDo(int id, int index) async {
debugPrint("Deleted Item!");
setState(() {
cardList.removeAt(index);
});
function which adds a card :
void addItems() async {
setState(() {
cardList.insert(0, new GestureDetector(
onTap: () async {
await Navigator.push(context, MaterialPageRoute(
builder: (context) =>
TodoList(), // this just navigates to another screen ; not important in this question
)
);
},
child: Card(
child: ListTile(
title: Text("project 1"),
trailing: new Listener(
key: new Key(UniqueKey().toString()),
child: new Icon(Icons.remove_circle,
color: Colors.redAccent,),
onPointerDown: (pointerEvent) => _deleteNoDo(id, index),
),
subtitle: whitefontstylemont(text: "project 1", size: 20,)) //this is just a custom TextStyle
),
));
});
}
code where cards are displayed in a list
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2
),
delegate: new SliverChildBuilderDelegate((context, index) {
return cardList[index]; // this is where the cards are displayed in a list
},
childCount: cardList.length
)
)