How to retrieve data from phpmyadmin in dropdown form using flutter - mysql

I have to fetch data from the PHPMyAdmin and display it as a dropdown menu and I have a problem how to display the data in the dropdown menu. I want to create the registration form and get the dropdown menu list from DB.
This is my coding
class RegisterForm extends StatefulWidget{
#override
RegisterFormState createState(){
return RegisterFormState();
}
}
class RegisterFormState extends State<RegisterForm>{
String _mySelection;
List data=[];
final _formKey = GlobalKey<FormState>();
#override
void initState(){
fetchData();
super.initState();
}
void fetchData() async{
final response = await http.get('http://10.0.2.2/Shazay/getData.php');
if (response.statusCode == 200) {
setState(() {
data = json.decode(response.body);
});
}
}
and this is the coding for the dropdown menu:
new Row(
children: <Widget>[
new Text("Energy Bubble ",style: new TextStyle(fontSize: 18.0,color: Colors.blue),),
new DropdownButton(
items: data.map((item){
return new DropdownMenuItem(
child:new Text(item['EbName']),
value: item['EbName'].toString(),
);
}).toList(),
onChanged: (newVal){
setState(() {
_mySelection=newVal;
});
},
value: _mySelection,
}),
],
)

Edit original question is describe in Step 3
revised question is previously describe in Step 2 and need further info such as JSON string format from user
Step 1 : Get your JSON string get from mysql / PHPMyAdminservice
Step 2 : Transfer this JSON string to List of Map
Step 3 : convert it In items of DropdownButton which means generate DropdownMenuItem
code snippet from Flutter populate dropdownmenu with JSON
String _mySelection;
List<Map> _myJson = [{"id":0,"name":"<New>"},{"id":1,"name":"Test Practice"}];
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new DropdownButton<String>(
isDense: true,
hint: new Text("Select"),
value: _mySelection,
onChanged: (String newValue) {
setState(() {
_mySelection = newValue;
});
print (_mySelection);
},
items: _myJson.map((Map map) {
return new DropdownMenuItem<String>(
value: map["id"].toString(),
child: new Text(
map["name"],
),
);
}).toList(),
),
),
);
}

Related

A RenderFlex overflowed by 99397 pixels on the bottom

import 'package:flutter/material.dart';
import 'package:http_request/carditem.dart';
import 'package:http_request/user_data.dart';
// here we chose to have statefull widget because the state needs to be updated and we need to update some variables according to some conditions.
class UserScreen extends StatefulWidget {
const UserScreen({Key key}) : super(key: key);
#override
_UserScreenState createState() => _UserScreenState();
}
class _UserScreenState extends State<UserScreen> {
// here we created a variable to keep our information in it . this information comes from our user data class where we get the user data from http requests.
Map<String, dynamic> userinfo = {};
// this method is called as soon as the main widget is created . we call our http method here to have the live data as soon as we open the app .be aware that we cant use async and await here . we just call the method.
#override
void initState() {
super.initState();
getData();
}
// here we get hte live data from our userdata class .
Future getData() async {
//we create a userData object to get access to the getuserdata method.
UserData userData = UserData();
//we handle any error here
try {
// here we create a variable to the exact same type we are expecting .
//then we wait for the result of calling our userdata information.
Map<String, dynamic> data = await userData.getUserData();
// we call setState because we need to update a certain value here.
setState(() {
//we assign the the value of data to our variable called userinfo .try the reaosn we see no error behind them is that they are the same type.
userinfo = data;
});
// we catch errors here .
} catch (e) {
print(e);
}
}
// our nice build method ...this method is from our stateful class.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Work Harder'),
centerTitle: true,
),
body: ListView.builder(
itemBuilder: (context, index) => CardItem(
firstName: userinfo['firstName'],
avatarLink: userinfo['avatarLink'],
id: userinfo['id'],
lastName: userinfo['lastName'],
email: userinfo['email'],
),
),
);
}
}
as you can see here is my user_screen dart file the problem is when i hot reload the app is see the renderflex error, while everything seems fine. im a begginner in flutter and i would really appreciate your help.
i have tried singlechild scrollview , list view , expanded widget , but it doesn't work . please help me hotrestart may app without these long errors
import 'package:flutter/material.dart';
// we chose stateless because we don't need to change the state of our app.
class CardItem extends StatelessWidget {
const CardItem({
Key key,
this.firstName,
this.email,
this.avatarLink,
this.id,
this.lastName,
}) : super(key: key);
final String firstName;
final String email;
final String avatarLink;
final String id;
final String lastName;
#override
Widget build(BuildContext context) {
return Card(
color: Colors.lightBlueAccent[200],
elevation: 3,
shadowColor: Colors.blue[100],
child: Column(
children: [
Stack(
children: [
ListTile(
leading: Icon(Icons.check_box),
trailing: CircleAvatar(
child: Image.network(avatarLink),
),
title: Text(firstName),
subtitle: Text(lastName),
),
Positioned(
left: 48,
top: 15,
child: Text(
id,
style: TextStyle(
color: Colors.white70,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
Positioned(
left: 120,
top: 30,
child: Text(
'Email : $email',
style: TextStyle(
color: Colors.blue[900].withOpacity(0.6),
),
),
),
],
),
],
),
);
}
}
here is my card widget , if it helps.
import 'dart:convert';
import 'package:http/http.dart' as http;
// this is the file for our main http requests.
class UserData {
UserData({
this.firstName,
this.lastName,
this.email,
this.id,
this.avatarLink,
});
final String firstName;
final String lastName;
final String email;
final String id;
final String avatarLink;
//this method is response for getting the live data we want also its responsible for decoding it with 'dart convert' library and returning the result as an output.
Future getUserData() async {
//the url we are working with
final String stringUrl = 'https://reqres.in/api/users?page=2';
//sending the request to web and storing the result to a variable. we also have to wait for the results . (asynchronous operation).
http.Response response = await http.get(
Uri.parse(stringUrl),
);
//we create a variable to the exact type of our output . we want to add our items to this map to use it in the main screen.
Map<String, dynamic> userdetails = {};
//here we want to check if our request was successful if so, we continue our operation and if not we throw an error .
if (response.statusCode == 200) {
// here we are decoding the data that we got from our request above to a variable of type map.
Map<String, dynamic> decodedData = jsonDecode(response.body);
//here we try to iterate through a map .. but im not sure if its correct or not .
for (var user in decodedData.values) {
Map<String, dynamic> myusersInfo = {
'firstName': decodedData['data'][0]['first_name'],
'lastName': decodedData['data'][0]['last_name'],
'email': decodedData['data'][0]['email'],
'id': decodedData['data'][0]['id'].toString(),
'avatarLink': decodedData['data'][0]['avatar'],
};
// here we are trying to add the items to the map specified.
userdetails.addEntries(myusersInfo.entries);
return userdetails;
}
} else {
print(response.statusCode);
throw 'Problem with the get request';
}
}
}
the whole goal of this app was to practice some http request.
the last file I have in this app . I just added this maybe it helps you . thanks in advance.
A Column likes to expand until infinity.
This can be solved by putting an intrinsicHeight around the Column as followed:
This class is useful, for example, when unlimited height is available and you would like a child that would otherwise attempt to expand infinitely to instead size itself to a more reasonable height.
IntrinsicHeight(
child: Column(
children: [
],
)
);
https://api.flutter.dev/flutter/widgets/IntrinsicHeight-class.html
try column inside SingleChildScrollView

How to show Event on Table Calendar using my API on flutter

I have UI for show event calendars and I need to show events from my API. but I don't know how to do it. I try to change List on _event but there's no response. And I need to show it on the calendar so my company calendar can show the event.
this my UI Calendar
import 'package:intl/intl.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:urus_flutter/persentation/custom_color.dart';
import 'package:urus_flutter/persentation/custom_text_style.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Calender extends StatefulWidget {
#override
State<StatefulWidget> createState() => CalenderState();
}
class CalenderState extends State<Calender> {
CalendarController _controller;
Map<DateTime, List<dynamic>> _events;
List<dynamic> _selectedEvents;
DateTime _selectedDate;
SharedPreferences prefs;
#override
void initState(){
super.initState();
_controller = CalendarController();
_events = {
DateTime(2021, 6, 22) : ['Meeting URUS', 'Testing Danai Mobile', 'Weekly Report', 'Weekly Meeting'],
DateTime(2021, 6, 25) : ['Weekly Testing'],
DateTime(2021, 6, 4) : ['Weekly Testing'],
DateTime(2021, 6, 11) : ['Weekly Testing'],
DateTime(2021, 6, 18) : ['Weekly Testing'],
};
}
Map<String, dynamic> encodeMap(Map<DateTime, dynamic> map) {
Map<String, dynamic> newMap = {};
map.forEach((key, value) {
newMap[key.toString()] = map[key];
});
return newMap;
}
Map<DateTime, dynamic> decodeMap(Map<String, dynamic> map) {
Map<DateTime, dynamic> newMap = {};
map.forEach((key, value) {
newMap[DateTime.parse(key)] = map[key];
});
return newMap;
}
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
ListView(
padding: EdgeInsets.only(left: 16, right: 16, top: 52, bottom: 126),
children: [
Text("Kalender Kegiatan",
style: CustomTextStlye.proxima_bold_18_black,),
Container(
child: Padding(
padding: const EdgeInsets.only(top: 28.0),
child: Text("Kalender Anda",
style: CustomTextStlye.proxima_bold_16_black,),
),
),
SizedBox(
height: 20,
),
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5.0),
boxShadow: [
BoxShadow(
offset: Offset(0, -1),
color: CustomColor.border_grey,
blurRadius: 3.0,
spreadRadius: 1.0)
]
),
child: TableCalendar(
initialCalendarFormat: CalendarFormat.month,
calendarStyle: CalendarStyle(
todayColor: Color(0x9429AAE1),
todayStyle: CustomTextStlye.proxima_bold_12_white,
selectedColor: Color(0xFF29AAE1),
selectedStyle: CustomTextStlye.proxima_bold_12_white,
weekdayStyle: CustomTextStlye.proxima_bold_12_black,
weekendStyle: CustomTextStlye.proxima_bold_12_red,
unavailableStyle: CustomTextStlye.proxima_bold_12,
holidayStyle: CustomTextStlye.proxima_bold_12_red,
markersColor: Color(0xFFA2CD3A),
),
headerStyle: HeaderStyle(
centerHeaderTitle: true,
formatButtonVisible: false,
titleTextStyle: CustomTextStlye.proxima_bold_14_black,
),
availableCalendarFormats: const {CalendarFormat.month: '',},
startingDayOfWeek: StartingDayOfWeek.monday,
calendarController: _controller,
events: _events,
onDaySelected: (date, events,holidays) {
setState(() {
_selectedEvents = events;
_selectedDate = date;
});
},
),
)
],
),
),
Container(
child:Padding(
padding: const EdgeInsets.only(top: 28.0),
child: Text("Kegiatan Anda",
style: CustomTextStlye.proxima_bold_16_black,),
),
),
Container(
child: _selectedEvents != null ? Column(
children: List.generate(_selectedEvents.length, (index) =>
Container(
padding: const EdgeInsets.all(8.0),
child: Container(
height: MediaQuery.of(context).size.height/15,
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Color.fromRGBO(228, 228, 228, 1)))
),
child:
Center(
child:
Container(child:
Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 10.0),
height: MediaQuery.of(context).size.height/10,
decoration: BoxDecoration(
border: Border.all(color:Color(0xFF29AAE1)),
color:Color(0xFF29AAE1),
borderRadius: BorderRadius.circular(3.0),
),
child: Text(DateFormat('d').format(_selectedDate),
style: CustomTextStlye.proxima_bold_18_white,
),
),
),
Text(_selectedEvents[index],
style: CustomTextStlye.proxima_bold_14_black,
),
],
),
)
),
),
),
),
) : Container(),
)
],
),
],
),
);
}
}
Here my eventCalendarService.dart
import 'dart:convert';
import 'dart:io';
import 'package:http/io_client.dart';
import 'package:urus_flutter/data/eventController.dart';
import 'package:urus_flutter/data/model/base/event_calendar.dart';
Future<List<Event_Calendar>> fetchEventCalendar(String id, int company_id, {String date}) async {
String requestBody = '';
print(requestBody);
final ioc = new HttpClient();
ioc.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
final http = new IOClient(ioc);
final response = await http.get(
getStringUrl+'staffs/GetCalendar?companyid=$company_id&month=$date',
);
print(response.statusCode);
print(response.body);
if (response.statusCode == 200) {
var parsed = jsonDecode(response.body);
return List<Event_Calendar>.from(parsed.map((model) => Event_Calendar.fromJson(model)));
} else {
throw Exception(response.body);
}
}
And here my model event_calendar.dart
class Event_Calendar {
final String id;
final String type;
final String date;
final String event_name;
final int company_id;
Event_Calendar(
{
this.id,
this.type,
this.date,
this.event_name,
this.company_id,
}
);
factory Event_Calendar.fromJson(Map<String, dynamic> json) {
return Event_Calendar(
id: json['id'] as String,
type: json['type'] as String,
date: json['date'] as String,
event_name: json['event_name'] as String,
company_id: json['company_id'] as int,
);
}
}
I hope anyone can give me an answer on how to show _events to my API. Thank you. And this is the example value from my API
Well folks now I'm going to show you the way I found to show events and cards coming from an api using the table calendar.
I don't even need to say that this is the way I found things, feel free to add new things and give tips here. so let's go.
first of all we will show the calendar events, but in this step only the markers, your data coming from the api must contain dates if you are here, in my case the dates come as a String, so let's create the model for them
import 'dart:convert';
class EventsModel {
final String dataDoJob;
EventsModel({
required this.dataDoJob,
});
Map<String, dynamic> toMap() {
return {
'data_acao': dataDoJob,
};
}
factory EventsModel.fromMap(Map<String, dynamic> map) {
return EventsModel(
dataDoJob: map['data_acao'],
);
}
String toJson() => json.encode(toMap());
factory EventsModel.fromJson(String source) => EventsModel.fromMap(json.decode(source));
}
this is my model, as you can see I'm just getting the dates. Now let's do the get method to retrieve this data from the api, I'm using getConnect but you can use the http client you want.
#override
Future<List<EventsModel>> getEvents() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
final int? id = sharedPreferences.getInt("idInfluencer");
final String token = sharedPreferences.getString("token") ?? "";
final Response result = await _restClient.get<List<EventsModel>>(
"/job_acoes?influenciador_id=${id.toString()}",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token'
}, decoder: (data) {
if (data != null) {
return data
.map<EventsModel>((event) => EventsModel.fromMap(event))
.toList();
}
return <EventsModel>[];
});
if (result.hasError) {
print(result.statusCode);
throw "Erro ao buscar dados";
}
print(result.body);
print(result.statusCode);
return result.body;
}
Well done that we already have a list of dates in hand, but in my case they are strings so I'll have to convert them, like this:
final events = await _jobsServices.getEvents();
//final dateFormat = DateFormat("yyyy-MM-dd");
final eventsConvert =
events.map((date) => (DateTime.parse(date.dataDoJob))).toList();
eventsList.assignAll(eventsConvert);
print("Lista de eventos : $eventsList");
streamController.add(events);
on the first line I'm saving the list in a variable called events and right below I'm converting the strings into date time using the map method, And adding them to an empty list which I created then step by step and this: Create an empty list and add the converted data to it as I did above, my empty list is called eventsList
done that we will show this list in the table calendar
class CalendarWidget extends GetView<HomeController> {
const CalendarWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamBuilder<List<EventsModel>>(
stream: controller.streamController.stream,
builder: (context, snapshot) {
return Obx(() {
return TableCalendar(
eventLoader: (day) => controller.eventsList.where((event) => isSameDay(event,day)).toList(), //THIS IS IMPORTANT
focusedDay: controller.focusedDay.value,
firstDay: DateTime(2019),
lastDay: DateTime(2050),
headerStyle:
const HeaderStyle(formatButtonVisible: false), //WEEK VISIBLE
locale: 'pt_BR',
daysOfWeekVisible: true,
calendarFormat: controller.format.value,
onFormatChanged: (CalendarFormat _format) =>
controller.calendarFormat(_format),
onDaySelected: (DateTime userSelectedDay, DateTime focusedDay) =>
controller.selectedDay(userSelectedDay, focusedDay),
calendarStyle: CalendarStyle(
selectedTextStyle: const TextStyle(color: Colors.white),
isTodayHighlighted: true,
selectedDecoration: BoxDecoration(
color: context.buttomThemeClicled,
shape: BoxShape.circle)),
selectedDayPredicate: (DateTime date) {
return isSameDay(controller.focusedDay.value, date);
},
);
});
});
}
}
remembering that i'm using a stateless widget so i need a state manager, and i use getx so it has an obx involving the whole calendar.
in the event loader some people have doubts, you can pass a list or a map on it, in my case I'm working with a list for simplicity's sake, notice that in the event loader I'm doing a simple filtering, comparing the dates of the my calendar with the dates I get from the api, simple isn't it? by doing this your api-based bookmarks will already be shown. Ah, a detail, the stream builder serves to redo my widget whenever there are changes in the api, if you don't know how to work with it, this video will explain: https://www.youtube.com/watch?v=BBelgajHgzY
now let's go to the display part of your events based on days, my events will be displayed on cards like this:
so I built it on a separate page from my home, this part is important because your code will be easier and cleaner, with the widget done, we'll show them on screen like this:
child: Obx(() {
return ListView(
scrollDirection: Axis.vertical,
children: controller.cards
.map(
(c) => AgendaCards(
bottomPosition: 80,
leftPositioned: 260,
maxRadius: 5,
rightPositioned: 5,
secondMaxradius: 5,
topPositioned: 20,
model: c,
),
)
.toList(),
);
}));
the widget called calendar cards is nothing more than the card in the photo above, on it I asked for a model called
final JobsDescriptionCardsModel model;
and called him in the constructor
AgendaCards({
required this.leftPositioned,
required this.rightPositioned,
required this.topPositioned,
required this.bottomPosition,
required this.maxRadius,
required this.secondMaxradius,
required this.model, //HERE
Key? key,
}) : super(key: key);
so let's create this model
class JobsDescriptionCardsModel {
final String descricaoJob;
final String dataDoJob;
final String horarioDoJob;
final int jobId;
final String nome;
JobsDescriptionCardsModel({
required this.descricaoJob,
required this.dataDoJob,
required this.horarioDoJob,
required this.jobId,
required this.nome,
});
Map<String, dynamic> toMap() {
return {
'descricaoJob': descricaoJob,
'dataDoJob': dataDoJob,
'horarioDoJob': horarioDoJob,
'jobId': jobId,
'nome': nome,
};
}
factory JobsDescriptionCardsModel.fromMap(Map<String, dynamic> map) {
return JobsDescriptionCardsModel(
descricaoJob: map['descricao'] ?? "",
dataDoJob: map['data_acao'] ?? "",
horarioDoJob: map['hora_inicial_acao'],
jobId: map['job_acao_id'] ?? 0,
nome: map['job'] ["cliente"] ["nome"] ?? "",
);
}
String toJson() => json.encode(toMap());
factory JobsDescriptionCardsModel.fromJson(String source) => JobsDescriptionCardsModel.fromMap(json.decode(source));
}
and get it on the api
#override
Future<List<JobsDescriptionCardsModel>> getJobsDescrition() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
final int? id = sharedPreferences.getInt("idInfluencer");
final String token = sharedPreferences.getString("token") ?? "";
final result = await _restClient.get<List<JobsDescriptionCardsModel>>(
"/job_acoes?influenciador_id=${id.toString()}",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token'
}, decoder: (data) {
if (data != null) {
return data
.map<JobsDescriptionCardsModel>(
(j) => JobsDescriptionCardsModel.fromMap(j))
.toList();
}
return <JobsDescriptionCardsModel>[];
});
if (result.hasError) {
throw ("erro ao buscar dados");
}
return result.body ?? <JobsDescriptionCardsModel>[];
}
the api gives me a list that is important. With the list in hand, we're going to get into the concepts of the table calendar. To proceed and understand what will be done, I recommend that you watch this video: https://www.youtube.com/watch?v=HKuzPQUV21Y&t=291s
having done the configuration of your calendar, I believe you have noticed that when you click on a date and print the variable that has the date data, you will notice that the table calendar gives you a date time as a return, and if you have rendered it the attention in my model i also have a date coming from the api, knowing that we only need to filter the list coming from the api based on the table calendar data like this:
first create an empty list like we did before and a list that will be filtered:
//LISTA DE JOBS CARDS
final cards = <JobsDescriptionCardsModel>[].obs;
//LISTA FILTRADA
var cardsFiltered = <JobsDescriptionCardsModel>[];
the empty list will be filled with the api data like this:
final jobsCards = await _jobsServices.getJobsDescrition();
cards.assignAll(jobsCards);
and with the populated list in hand we will filter this list based on the api dates, like this:
cardsFiltered = jobsCards;
var novaLista = cardsFiltered.where((model) {
return model.dataDoJob
.toString()
.contains(focusedDay.value.toString().substring(1, 10));
});
see that first I assign my populated list to a new list, then I filtered this list based on my model only in the part that contains the date that I stringed, comparing with my variable that has the date when I click on it remembers ? also converted to string, as the table calendar gives me the date along with other numbers that I believe are time information I got the data only from index 1 to 10 which will give me exactly the date contained in the variable. With that done, the table calendar has a property called onDaySelected, and it will display our filtered list like this:
selectedDay(DateTime selectedDayInfo, DateTime focusDayInfo) {
userSelectedDay.value = selectedDayInfo;
focusedDay.value = focusDayInfo;
print(userSelectedDay.value);
print(focusedDay.value);
print("Lista de eventos 2 ${eventsList}");
var novaLista = cardsFiltered.where((model) {
return model.dataDoJob
.toString()
.contains(focusedDay.value.toString().substring(0, 10));
});
cards.assignAll(novaLista);
I created this separate function in a controller and called it in table calendar like this:
onDaySelected: (DateTime userSelectedDay, DateTime focusedDay) =>
controller.selectedDay(userSelectedDay, focusedDay),
done that your calendar will already be displaying the default markers and your cards based on the widget you built, remember to pass the data to your cards using the model you requested via the constructor because it contains the api data. I hope I have help and I'm sorry for the google translator english
_event was not used in the newer version of table_calendar. you can use eventLoader it will display your events on the calendar.
Example:
calendar widget as follows,
TableCalendar<Event>(
firstDay: kFirstDay,
lastDay: kLastDay,
focusedDay: _focusedDay,
selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
eventLoader: _getEventsForDay, // this will load events on calendar
),
_getEventsForDay method as follows,
List<Event> _getEventsForDay(DateTime day) {
return kEvents[day] ?? [];
}
kEvents (event list which you need to mark on the calendar) is as follows, you don't need to create this one if you have a list of events.
final kEvents = LinkedHashMap<DateTime, List<Event>>(
equals: isSameDay,
hashCode: getHashCode,
)..addAll(_kEventSource);
final _kEventSource = Map.fromIterable(List.generate(50, (index) => index),
key: (item) => DateTime.utc(kFirstDay.year, kFirstDay.month, item * 5),
value: (item) => List.generate(
item % 4 + 1, (index) => Event('Event $item | ${index + 1}')))
..addAll({
kToday: [
Event('Event 1'),
Event('Event 2'),
],
});
Event class as follows, (as well you can make it as you prefer)
class Event {
final String title;
const Event(this.title);
#override
String toString() => title;
}
Hope you got it!

How do I initialize my json response in another class that depends on a search input in flutter?

this is my first question here on stackoverflow.
I'm working on my first real app after attending a few CS classes at University and some courses on Udemy. So I'm lacking a lot of software engineering knowledge.
My goal: I want to build a search for stocks by using an external API endpoint. For that, I have created 4 dart files to handle the searchscreen with inputs (My UI), networking, parsing, and basically returning the data.
My NetworkAPI class to handle all sorts of network requests looks like this. I'm trying to use the jsonDecode already here and returning that. This class waits for an URL that will be put together in another class (financeData):
class NetworkAPI {
final String url;
NetworkAPI(this.url);
Future getData() async {
http.Response response = await http.get(url);
if (response.statusCode == 200) {
String data = response.body;
return jsonDecode(data);
} else {
print(response.statusCode);
}
}
}
This is basically the Json I want to parse. If I understood the theory correctly it's a map with a list of objects.
{
"bestMatches": [
{
"1. symbol": "TESO",
"2. name": "Tesco Corporation USA",
"3. type": "Equity",
"4. region": "United States",
"5. marketOpen": "09:30",
"6. marketClose": "16:00",
"7. timezone": "UTC-04",
"8. currency": "USD",
"9. matchScore": "0.8889"
}
{....}
]
}
To parse this, I saw some really good explanations here on stack overflow. I'm basically trying to retrieve the information I'm interested in.
class SearchOutput {
final List<BestMatch> bestMatches;
SearchOutput({this.bestMatches});
factory SearchOutput.fromJson(Map<String, dynamic> parsedJson){
var list = parsedJson['bestMatches'] as List;
print(list.runtimeType);
List<BestMatch> searchResultList = list.map((i) => BestMatch.fromJson(i)).toList();
return SearchOutput(
bestMatches: searchResultList,
);
}
}
class BestMatch {
String symbol;
String name;
String type;
String region;
String currency;
BestMatch({
this.symbol,
this.name,
this.type,
this.region,
this.currency,
});
factory BestMatch.fromJson(Map<String, dynamic> parsedJson){
return BestMatch(
symbol: parsedJson["1. symbol"],
name: parsedJson["2. name"],
type: parsedJson["3. type"],
region: parsedJson["4. region"],
currency: parsedJson["8. currency"],
);
}
}
Now I created a class with a method that should return all my data and format it into a list. The URL still needs an searchInput, which will be handed over from a TextField Widget in the UI.
const apiKey = 'demo';
const alphaVantageSearchUrl =
'https://www.alphavantage.co/query?function=SYMBOL_SEARCH';
class FinanceData {
Future<dynamic> getSearchData(String searchInput) async {
var url = '$alphaVantageSearchUrl&keywords=$searchInput&apikey=$apiKey';
NetworkAPI networkAPI = NetworkAPI(url);
var searchData = await networkAPI.getData();
SearchOutput searchOutput = new SearchOutput.fromJson(searchData);
return searchOutput;
}
}
Testing with some print statements seems to fullfill my goal of being able to access the data. For example printing out the name of the second object out of my response.
print(searchOutput.bestMatches[1].name);
The last file is my UI where we have a TextField, that I push to the financeData class in order to build the URL. Currently, my goal would be, to be able to show just the name of any given object in my response in the UI. I have no idea how to initialize my financeDate and how to use the return from my finaceData class in the UI. (I took some design styles out of the code snippet).
class SearchScreenWatchlist extends StatefulWidget {
#override
_SearchScreenWatchlistState createState() => _SearchScreenWatchlistState();
}
class _SearchScreenWatchlistState extends State<SearchScreenWatchlist> {
String searchInput;
FinanceData financeData = FinanceData();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Container(
child: TextField(
onChanged: (value) {
searchInput = value;
},
),
),
TextButton(
onPressed: () {
financeData.getSearchData(searchInput);
setState(() {
});
},
child: Text('Search')),
Text(('Search Results for: $searchInput')),
Container(child: Text('**SHOW HERE THE NAME**')),
],
),
);
}
}
It would be my goal to show in the last container the name on any given object from my response for example RESPONSE.name[1]. Later on I will try to iterate throw all the objects and show a list of all names of the response.
Thanks a lot! I really appreciate your help!
I think changing SearchScreenWatchlist to the following should display the name of the first bestMatches entry after you pressed the Search button (if I didn't miss something).
Make sure to look further into setState and initState (And the StatefulWidget lifecycle in general). Also it may not be the most elegant way to initialize FinanceData() and SearchOutput() this way - However, awesome starter project!
class SearchScreenWatchlist extends StatefulWidget {
#override
_SearchScreenWatchlistState createState() => _SearchScreenWatchlistState();
}
class _SearchScreenWatchlistState extends State<SearchScreenWatchlist> {
String searchInput;
FinanceData financeData;
SearchOutput searchOutput;
#override
initState() {
super.initState();
financeData = FinanceData();
searchOutput = SearchOutput();
}
_handleButtonPress() async {
final fetchedSearchOutput = await financeData.getSearchData(searchInput);
setState(() {
searchOutput = fetchedSearchOutput;
});
}
_buildSearchResult() {
if(searchOutput.bestMatches != null && searchOutput.bestMatches.isNotEmpty) {
return Text(searchOutput.bestMatches.first.name);
}
else {
return Text("No data fetched");
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Container(
child: TextField(
onChanged: (value) {
setState(() {
searchInput = value;
});
},
),
),
TextButton(
onPressed: () => _handleButtonPress(),
child: Text('Search'),
),
Text(('Search Results for: $searchInput')),
Container(
child: _buildSearchResult(),
),
],
),
);
}
}

Flutter/Dart: Passing this.variable as parameter

I have a list of profile fields that I would like to create using a single widget, but I'm new to Flutter and can't seem to work out one single thing: passing a variable through a parameter. I have been able to create many widgets that work just fine, using this.variable = value, but now that I'm trying to convert it to a single widget as not to repeat myself, that's where I'm having the problem.
I have the following code (of course removing all that I believe to be unnecessary). Here it currently shows an error of The setter 'listType' isn't defined for the class '_ProfileDataState'.
class _ProfileDataState extends State<ProfileData> {
final _countries = DropDownLists.countries;
String _country;
var listType; //<-- added this per comments
Widget profileDropDown(var list, var listType) {
return Card(
onTap: () async {
AlertDialog(
content: DropdownButtonFormField<String>(
isExpanded: true,
items: list.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
isDense: true,
value: listType,
onChanged: (value) {
FocusScope.of(context).requestFocus(FocusNode());
setState(() {
this.listType = value;
});
},
)
)
}
)
}
#override
Widget build(BuildContext context) {
return profileDropDown(_countries, _country),
...
class _ProfileDataState extends State<ProfileData> {
String _country;
var listType; // declare a variable
#override
void initState() {
super.initState();
listType = widget.listType; // assign it a value here
}
Widget profileDropDown(var listType) {
return Card(
onTap: () async {
AlertDialog(
onChanged: (value) {
FocusScope.of(context).requestFocus(FocusNode());
setState(() {
this.listType = value; // works
});
},
)
}
)
}
// other methods
}

How do I display images from a JSON file in a carousel(slider) in Flutter

I have a local json file assets/properties.json in which key "image" has [5 different images] stored with other keys as well like name, place, etc. I want this images be displayed in a carouselSlider.
I have searched but cant find something specific to what i am trying to do.
import 'package:flutter/material.dart';
import 'package:carousel_pro/carousel_pro.dart';
import 'package:flutter_test_app/test_page.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'dart:convert';
import 'dart:async';
import 'package:flutter_test_app/propery_details_widget.dart';
class PropertyDetails extends StatefulWidget {
#override
_PropertyDetailsState createState() => _PropertyDetailsState();
}
class _PropertyDetailsState extends State<PropertyDetails> {
List properties;
Future<String> loadJsonData() async {
var jsonText = await rootBundle.loadString("assets/properties.json");
setState(() {
properties = json.decode(jsonText);
});
return 'success';
}
int index = 1;
List<String> listaTela = new List();
CarouselSlider instance;
#override
void initState() {
super.initState();
this.loadJsonData();
listaTela.add("assets/images/houses/house.jpg");
listaTela.add('assets/images/houses/house1.jpg');
listaTela.add('assets/images/houses/house2.jpg');
listaTela.add('assets/images/houses/house3.jpg');
listaTela.add('assets/images/houses/house4.jpg');
}
#override
Widget build(BuildContext context) {
instance = new CarouselSlider(
autoPlay: true,
autoPlayDuration: new Duration(seconds: 2),
items: listaTela.map((it) {
return new Container(
width: MediaQuery.of(context).size.width,
// margin: new EdgeInsets.symmetric(horizontal: 5.0),
decoration: new BoxDecoration(
// color: Colors.amber,
),
child: new Image.asset(it),
);
}).toList(),
height: 200,
);
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("Test App"),
),
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Column(
children: <Widget>[
instance,
Flexible(
fit: FlexFit.tight,
child: Container(
child: Details(),
),
)
],
),
),
);
}
}
Instead of calling images from assests listaTela.add("assets/images/houses/house.jpg"); like this i want to call them from my "image" key in JSON file. outside my Carousel i can call my images by properties[index]["image"][0],
Try this. (There's a chance that the map won't work because it will have the wrong type. I don't think you included the whole json, as you are indexing it by index, yet you don't show a [] surrounding the json indicating a json array.)
class _PropertyDetailsState extends State<PropertyDetails> {
List properties;
int index = 1;
Future<void> loadJsonData() async {
var jsonText = await rootBundle.loadString("assets/properties.json");
setState(() {
properties = json.decode(jsonText);
});
}
#override
void initState() {
super.initState();
loadJsonData();
}
#override
Widget build(BuildContext context) {
Widget carousel = properties == null
? CircularProgressIndicator()
: CarouselSlider(
items: properties[index]["image"].map((it) {
return new Container(
width: MediaQuery.of(context).size.width,
decoration: new BoxDecoration(),
child: new Image.asset(it),
);
}).toList(),
autoPlay: true,
autoPlayDuration: new Duration(seconds: 2),
height: 200,
);
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("Test App"),
),
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Column(
children: <Widget>[
carousel,
Flexible(
fit: FlexFit.tight,
child: Container(
child: Details(),
),
)
],
),
),
);
}
}
As far as I can understand you problem, there are a couple of challenges.
you probably want to map the JSON to Dart objects
you want to display a set of images in the Slider starting from index
mechanics to update you widget tree when you want to update the slider
JSON and Dart
Takes some getting used to built package:built_value is a nice way to go. It will allow you to have Dart object or list of objects mapped from a JSON file. Or, if you want to go simpler, you could do what's described here: https://flutter.dev/docs/development/data-and-backend/json#serializing-json-manually-using-dartconvert
Images from index & update
Basically, what you want to do in your initState is:
load image data from json -> set start index -> somehow get Flutter to map N image paths to Image widgets and update tree
A pseudo-code like initState could look like so:
void initState() {
super.initState();
// step 1: load json and map it to Dart objects
this.loadFromJson().then(() {
// loadFromJson returns with a Future, `then` allows you to do computation after it returns
setState(() {
// setting property in setState tells Flutter: hey buddy, stuff happened, rebuild!
this.startIndex = 0;
});
});
}
inside your build:
// [...]
CarouselSlider(
items: listaTela.skip(this.startIndex).take(5).map((imgObj) => Image.asset(imgObj.assetPath))
);
Hope I understood your problem and gave you relevant answer.