Flutter: How to display all columns in the same table - mysql

I am working on a test application in Dart. The application is used for displaying and inserting data into a database hosted with 000webhost.com
I am displaying my json data into a table in my app. I would like all the columns to be inside of one table. With my current code it is displaying every column inside of a brand new table
like shown here:
Below is the relevant code for my project:
class ViewData extends StatelessWidget{
final String url = 'https://fourieristic-thousa.000webhostapp.com/index.code.php?action=view';
Future<List<dynamic>> fetchData() async {
var result = await http.get(
Uri.parse(url),
);
print(json.decode(result.body));
return json.decode(result.body);
}
// First entry of each column.
String _test(dynamic test, int index){
return test[index]['testColumn'];
}
// Second entry of each column.
int _test2(dynamic test, int index){
return json.decode(test[index]['testColumn2']);
}
// Third entry of each column (Will some day be a delete function)
int _id(dynamic test, int index){
return json.decode(test[index]['ID']);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test data table'),
),
body: Container(
child: FutureBuilder<List<dynamic>>(
future: fetchData(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.hasData){
return ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
columns: const <DataColumn>[
DataColumn(
label: Text(
'Test',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Test2',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Delete',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
],
rows: <DataRow>[
DataRow(
cells: <DataCell>[
DataCell(
Text(_test(snapshot.data, index).toString())
),
DataCell(
Text(_test2(snapshot.data, index).toString())
),
DataCell(
Text(_id(snapshot.data, index).toString())
)
],
),
],
),
);
}
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
),
);
}
}
I have tried looking for an answer online with no result. I have also tried rewriting my code to attempt to find anything wrong with it. I understand why the app is showing the data in individual tables, but I can not find a way to fix it.

You claim to know what the problem is so I won't go in depth, but the main issue is your ListView.builder; there is no reason to have it there. Instead, you should replace the code between if(snapshot.hasData){ and return SingleChildScrollView( with something like this:
List<DataRow> dataRows = [];
for (var index = 0; index < snapshot.data.length; index++) {
dataRows.add(
DataRow(
cells: <DataCell>[
DataCell(
Text(_test(snapshot.data, index).toString())
),
DataCell(
Text(_test2(snapshot.data, index).toString())
),
DataCell(
Text(_id(snapshot.data, index).toString())
),
],
),
);
}
and then put the dataRows variable in the rows: field of your DataTable. Your tree should end up being Scaffold -> Container -> FutureBuilder -> SingleChildScrollView -> DataTable. This way you won't be building a new table for every entry.

Related

I get this error "_TypeError (type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Iterable<dynamic>')" from api array call

I'm working on a app that you can read quran and bible from it and I'm pulling quran surahs and bible books from firebase and write that data to api so that I get all of chapters at once so I have quran and bible apis for it I take care of bible part but with quran json data has array that I want to retrieve all that array and data under that array but I come of to this error while doing it what I'm doing wrong ? if you can help me I really appreciate it thank you very much
my api code:
Future getQuran(String surah) async {
var uri = Uri.https(
'ajith-holy-bible.p.rapidapi.com',
'/${surah}',
);
var response = await http.get(uri, headers: {
'X-RapidAPI-Key': 'd88d0a8158mshb8b539da6b34179p137959jsn31258093d5c2',
'X-RapidAPI-Host': 'al-quran1.p.rapidapi.com'
});
print(response.statusCode);
print(response.body);
Map<String, dynamic> map = jsonDecode(response.body);
List myData = [];
for (var item in map["verses"]) {
myData.add(item);
}
return myData;
}
this is what api looks like:
id:114
surah_name:"AL-NĀS"
surah_name_ar:"الناس"
translation:"HUMANS"
type:"meccan"
total_verses:6
description:"The surah that opens with the mention of God as the Lord of Humans and teaches one to seek refuge in Him from the whisperings of Satan and those of evil jinn and people. It takes its name from the word “people” or “mankind” (al-nās) which recurs throughout the surah. This is another surah commonly used as an invocation against evil.The surah is also known as: All People, Humankind, Mankind, People, The Men."
▶
verses:{} 6 keys
▶
1:{} 4 keys
id:1.114
content:"قُل أَعوذُ بِرَبِّ النّاسِ"
translation_eng:"Say, ‘I seek the protection of the Lord of humans,"
transliteration:"qul ʾaʿūdhu bi-rabbi n-nāsi"
▶
2:{} 4 keys
id:2.114
content:"مَلِكِ النّاسِ"
translation_eng:"Sovereign of humans,"
transliteration:"maliki n-nāsi"
this is surahs page:
stream: FirebaseFirestore.instance.collection("quran").snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
final quran = snapshot.data!.docs[index];
return Padding(
padding: const EdgeInsets.all(4.0),
child: Card(
borderOnForeground: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SurahReading(
surah: quran["chapter"],
book: quran["surah"],
)));
},
child: Text(quran["surah"]),
),
],
),
),
);
});
this surahs reading page:
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.vertical,
child: Column(
children: [
SingleChildScrollView(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.vertical,
child: FutureBuilder(
future: Api().getQuran(widget.surah),
builder: (context, snapshot) {
final quran = snapshot.data;
if (snapshot.hasData) {
return Container(
child: ListView.builder(
itemCount: quran.length,
itemBuilder: (context, index) {
return Row(
children: [
Center(
child: Text(
quran[index]["content"],
style: TextStyle(fontSize: 15),
),
),
Center(
child: Text(
quran[index]["translation_eng"],
style: TextStyle(fontSize: 15),
),
),
],
);
},
),
);
}
return Center(
child: CircularProgressIndicator(),
);
}),
),
I did try to get all surahs all ayet from api but I come up to a error and I couldn't fix it
Ok ı figured it out if anyone come up to this error change for to foreach
map["verses"].forEach((key, value) {
myData.add(value);
});

How to categorise a list by the date in flutter

I'm trying to get the json list to be represented by the different date according to when it was uploaded
Just something like this
This is what I have instead
I'm trying to group all transaction on the same day to just have one "Today" and the one of tomorrow to just have one "tomorrow" instead of it repeating itself
Container(
//color: Colors.black,
margin: EdgeInsets.only(
left: MediaQuery.of(context).size.width * 0.06,
right: MediaQuery.of(context).size.width * 0.06,
top: 10,
),
child: FutureBuilder(
builder: (context, projectSnap) {
if (projectSnap.connectionState ==
ConnectionState.none &&
projectSnap.hasData == null) {
//print('project snapshot data is: ${projectSnap.data}');
return Text('Nothing To show Here');
} else if (detail == null) {
return Center(child: LoadingWidget());
} else if (detail == []) {
return Center(
child: Text('Nohing to show here'),
);
} else {
return ListView.builder(
itemCount: detaillenght,
itemBuilder: (BuildContext context, int index) {
return SingleChildScrollView(
child: Column(
children: [
Text(
'Today',
style: TextStyle(
color: Theme.of(context)
.primaryColor
.withOpacity(.6),
fontSize: 18,
fontWeight: FontWeight.bold),
),
SizedBox(
height: 10,
),
listview(context, index, amount,
description, detail),
],
),
);
});
}
},
future: fetchlist(),
),
),
This is the code for the future builder I used
Future<void> fetchlist() async {
final prefs = await SharedPreferences.getInstance();
var token = await prefs.getString("token");
var response = await networkHandler.get('/getalert', token);
var data = jsonDecode(response);
detail = data['Detail'];
description = data['description'];
amount = data['amount'];
date = data['date'];
print(detail);
detaillenght = detail.length;
print(date);
}
this is the future function it's calling
[1662392319707, 1662626801573, 1662626802691, 1662626803340, 1662626803835, 1662626829586, 1662626830965]
This is how the date for each list called is arranged
You could use a Map<DateTime, bool> variable declared in the FutureBuilder so you can know whether the date of the current transaction was already built or not, and in every iteration in the ListView, building the text only if it hasn't been built before.
child: FutureBuilder(
builder: (context, projectSnap) {
final builtDates=<DateTime, bool>{};
if (projectSnap.connectionState ==
ConnectionState.none &&
projectSnap.hasData == null) {
//print('project snapshot data is: ${projectSnap.data}');
return Text('Nothing To show Here');
} else if (detail == null) {
return Center(child: LoadingWidget());
} else if (detail == []) {
return Center(
child: Text('Nohing to show here'),
);
} else {
return ListView.builder(
itemCount: detaillenght,
itemBuilder: (BuildContext context, int index) {
var shouldBuildDate=false;
if(builtDates[currentTransactionDate]==null){
shouldBuildDate=true;
builtDates[currentTransactionDate]=true;
}
return SingleChildScrollView(
child: Column(
children: [
if(shouldBuildDate)
Text(
'Today',//convert the date to a text you need here.
style: TextStyle(
color: Theme.of(context)
.primaryColor
.withOpacity(.6),
fontSize: 18,
fontWeight: FontWeight.bold),
),
SizedBox(
height: 10,
),
listview(context, index, amount,
description, detail),
],
),
);
});
}
},
future: fetchlist(),
),

How to keep precedent widgets after setState

I want to create a dynamic listview of cards I create with a title and a content. I'm decoding what I receive from the two textfields of the adding page but then when a card is created, it doesn't work well. For the first card, it works perfectly, but when a second one is created, the two cards are the same. I don't really know how to keep my precedent cards while adding new one. If you have any ideas or tips please tell me. Thank you in advance! Here's my code :
class MyPage extends StatefulWidget {
#override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
static List dreams = [];
static List contentCard = [];
String text;
String title;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: kEdgeColor,
appBar: AppBar(
backgroundColor: kEdgeColor,
elevation: 0,
title: Text('My dreams'),
),
body: Container(
decoration: BoxDecoration(
color: Colors.black),
child: ListView.builder(
itemCount: dreams.length ,
itemBuilder: (BuildContext ctxt, int index) {
return new DreamCard(
Content: text,
title: title,
);
}
)
),
bottomNavigationBar: BottomAppBar(
color: kEdgeColor,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FlatButton(
onPressed: (){
Navigator.popAndPushNamed(context, '/public');
},
child: Icon(Icons.public),
color: Colors.black,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
),
FlatButton(
onPressed: (){
Navigator.popAndPushNamed(context, '/');
},
child: Icon(Icons.bedtime),
color: Colors.black,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
),
],
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: FloatingActionButton(
onPressed: () async {
final result = await Navigator.of(context).push(MaterialPageRoute(builder: (context){return WritingPage();}));
if (null != result) {
dreams.add(result);
Map<String, dynamic> resultat = jsonDecode(result);
setState(() {text = resultat['text'];
title = resultat['title'];});
}
},
child: Icon(Icons.add, size: 30,color: Colors.black,),
backgroundColor: Colors.white,
),
);
}
}
cause you're only update the title and text when press, and your DreamCard has the same title and text, since you'r not reference items in dreams list by index. so your DreamCard in list always look the same.
if (null != result) {
Map<String, dynamic> resultat = jsonDecode(result);
// use setState to update your dreams list to trigger UI change
setState(() {
dreams.add(resultat);
});
}
ListView.builder(
itemCount: dreams.length ,
itemBuilder: (BuildContext ctxt, int index) {
// access item from dreams list by index
return new DreamCard(
Content: dreams[index]['text'],
title: dreams[index]['title],
);
}
)
Your itemBuilder is not referencing index in:
child: ListView.builder(
itemCount: dreams.length ,
itemBuilder: (BuildContext ctxt, int index) {
return new DreamCard(
Content: text,
title: title,
);
}
so of course all cards will always has the same text and title as whatever is in scope. You need to put the data in dreams and reference dreams[index][?something?] to get the two values appropriate for this card.
You cannot see the correct text for the next DreamCard added because you are adding the result received from WritingPage page directly to the dreams list. You are then JSON decoding result and setting the values of variables text and title. These values of the latest WritingPage are sent to DreamCard therefore every DreamCard appears to be the same. Instead you should be JSON decoding the dreams list and using the text and title from dreams list. Please make the following changes.
return new DreamCard(
Content: jsonDecode(dreams[index])["text"],
title: jsonDecode(dreams[index])["title"],
);

How to read data from Real time database firebase using flutter with a complicated JSON tree

I am working on a flutter app and I found obstacles on how to read product_name and price from Firebase and display them in list
I tried this code but it returns the whole JSON tree as a Text
class _BeveragesProductsState extends State<BeveragesProducts> {
var _firebaseRef = FirebaseDatabase().reference().child('Products');
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text(' Beverages Products'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: StreamBuilder(
stream: _firebaseRef.onValue,
builder: (context, snap) {
if (snap.hasData &&
!snap.hasError &&
snap.data.snapshot.value != null) {
Map data = snap.data.snapshot.value;
List item = [];
print("data $data");
data.forEach(
(index, data) => item.add({"key": index, ...data}));
print(item);
return ListView.builder(
reverse: true,
itemCount: item.length,
itemBuilder: (context, index) {
return Column(
children: <Widget>[
Text("$data"),
],
);
});
}
},
),
),
],
),
);
}
}
enter image description here

Flutter dropdownbutton evaluting value from json

```{"Piece": "[{\"sno\":7,\"valueName\":\"3\",\"value\":\"200\"},{\"sno\":7,\"valueName\":\"3\",\"value\":\"200\"},{\"sno\":7,\"valueName\":\"3\",\"value\":\"200\"}]",
"Caret": "[{\"sno\":1,\"valueName\":\"18k\",\"value\":\"1000\"},{\"sno\":1,\"valueName\":\"18k\",\"value\":\"1000\"},{\"sno\":1,\"valueName\":\"18k\",\"value\":\"1000\"},{\"sno\":1,\"valueName\":\"18k\",\"value\":\"1000\"}]"
}```
I have a json response from server like above. and I want to create dropdownbuttons dynamically in a way that how many keys are available like 'Caret' and 'piece' in json, it will create the same no of dropdown and each key has its own list and I want to deploy that list inside the drop down. and when I select any valueName like '18k','22k', it will return value like '1000','2000'.
please help me.
I tried...
Container(
padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0),
child: ListView.builder(
itemCount: data2.keys.length,
primary: false,
shrinkWrap: true,
itemBuilder: (context, i) {
List valueList;
List attributeNameList= List();
data2.forEach((key, value) {attributeNameList.add(key);valueList=jsonDecode(value);});
return DropdownButton<dynamic>(
items: valueList.map((map) {
return DropdownMenuItem(
child: Text(map['valueName']),
value: map['value'],
);
}).toList(),
onChanged: (value) {
print(value);
},
);
},
),
),```