I want to access variable in dart - database

I want to access imageUrl variable into Scaffold's body.
class _homePageState extends State<homePage> {
Stream<QuerySnapshot> _homeTopSliderData =
FirebaseFirestore.instance.collection("homeTopSliderData").snapshots();
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _homeTopSliderData,
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> querySnapshot) {
if (querySnapshot.hasError) {
return Scaffold(
body: Center(
child: Text("Something went wrong"),
),
);
} else if (querySnapshot.connectionState == ConnectionState.waiting) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
querySnapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
var imageUrl = data['imageUrl'];
});
return Scaffold(
body: Image(
image: NetworkImage(imageUrl),
),
);
});
}
}
It shows error when I use it as network image's url,
I am new to flutter and dart
Thanks!!!

The scope of the variable imageUrl is local, for that reason the scaffold can't access to that variable. To get more info refer to: https://toastguyz.com/dart/dart-variable-scope
It should work in the next way:
class _homePageState extends State<homePage> {
Stream<QuerySnapshot> _homeTopSliderData =
FirebaseFirestore.instance.collection("homeTopSliderData").snapshots();
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _homeTopSliderData,
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> querySnapshot) {
if (querySnapshot.hasError) {
return Scaffold(
body: Center(
child: Text("Something went wrong"),
),
);
} else if (querySnapshot.connectionState == ConnectionState.waiting) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
var imageUrl;
querySnapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
imageUrl = data['imageUrl'];
});
return Scaffold(
body: Image(
image: NetworkImage(imageUrl),
),
);
});
} }

You are streaming a collection, therefore, you will get a List of imageUrls (not 1, you could get up to 5 imageUrls). From your code, you are not using the list of imageUrls for anything, you are simply trying to use the last value of imageUrl. So, I do not think you want to stream a collection. I think you want a particular imageUrl.
To get a particular imageUrl, stream the document like this:
Stream<DocumentSnapshot<Map<String, dynamic>>> _homeTopSliderData =
FirebaseFirestore.instance
.collection("homeTopSliderData")
// TODO: replace DOCUMENTID with your document id.
.doc("DOCUMENTID")
.snapshots();
#override
Widget build(BuildContext context) {
return StreamBuilder<DocumentSnapshot>(
stream: _homeTopSliderData,
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> querySnapshot) {
if (querySnapshot.hasError) {
return Scaffold(
body: Center(
child: Text("Something went wrong"),
),
);
} else if (querySnapshot.connectionState == ConnectionState.waiting) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
Map<String, dynamic> data = querySnapshot.data.data();
print(data['imageUrl']);
return Scaffold(
body: Image(
image: NetworkImage(data['imageUrl']),
),
);
},
);
}
If you want to stream a collection (get all imageUrls in all documents) (bad idea since you are obviously not expecting multiple imageUrls), you can replace this part in your code:
var imageUrl;
querySnapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data = document.data()! as Map<String, dynamic>;
print(data['imageUrl']);
if (data['imageUrl'] != null) {
imageUrl = data['imageUrl'];
}
});
return Scaffold(
body: Image(
image: NetworkImage(imageUrl),
),
);

Related

The argument type 'Object?' can't be assigned to the parameter type 'List<Destination>'

class Destination {
final double lat;
final double lng;
final String name;
final double distance;
const Destination({
required this.lat,
required this.lng,
required this.name,
required this.distance,
});
factory Destination.fromJson(Map<String, dynamic> json) {
return Destination(
lat: json['lat'] as double,
lng: json['lng'] as double,
name: json['name'] as String,
distance: json['distance'] as double,
);
}
}
here is the error
return listViewWidget(List<Destination>.from(snapshot.data));
this my code :
import 'package:flutter/material.dart';
import 'package:flutter_sorting_location/model.dart';
import 'package:geolocator/geolocator.dart';
import 'package:flutter_sorting_location/Utils.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
double? distance;
List<Destination> destinations = [];
Position? _currentPosition;
List<Destination> destinationlist = [];
Future<List<Destination>> getData() async {
var url = 'http://xxxxxxxxxxxxxx/flutter/getlocation.php';
var res =
await http.get(Uri.parse(url), headers: {"Accept": "application/json"});
print(res.body);
if (res.statusCode == 200) {
var data = json.decode(res.body);
var rest = data["articles"] as List;
print(rest);
destinations =
rest.map<Destination>((json) => Destination.fromJson(json)).toList();
}
print("List Size: ${destinations.length}");
return destinations;
}
#override
void initState() {
_getCurrentLocation();
super.initState();
}
Widget listViewWidget(List<Destination> article) {
return Container(
child: ListView.builder(
itemCount: 20,
padding: const EdgeInsets.all(2.0),
itemBuilder: (context, position) {
return Card(
child: ListTile(
title: Text(
'${article[position].name}',
style: TextStyle(
fontSize: 18.0,
color: Colors.black,
fontWeight: FontWeight.bold),
),
leading: Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
child: article[position].name == null
? Image(
image: AssetImage('images/no_image_available.png'),
)
: Image.network('${article[position].name}'),
height: 100.0,
width: 100.0,
),
),
),
);
}),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Location sorting from current location"),
),
body: FutureBuilder(
future: getData(),
builder: (context, snapshot) {
if (snapshot.data != null) {
return listViewWidget(List<Destination>.from(snapshot.data));
} else {
return Center(child: CircularProgressIndicator());
}
}),
);
}
// get Current Location
_getCurrentLocation() {
Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best,
forceAndroidLocationManager: true)
.then((Position position) {
distanceCalculation(position);
setState(() {
_currentPosition = position;
});
}).catchError((e) {
print(e);
});
}
distanceCalculation(Position position) {
for (var d in destinations) {
var km = getDistanceFromLatLonInKm(
position.latitude, position.longitude, d.lat, d.lng);
// var m = Geolocator.distanceBetween(position.latitude,position.longitude, d.lat,d.lng);
// d.distance = m/1000;
//d.distance = km;
destinationlist.add(d);
// print(getDistanceFromLatLonInKm(position.latitude,position.longitude, d.lat,d.lng));
}
setState(() {
destinationlist.sort((a, b) {
// print("a : ${a.distance} b : ${b.distance}");
return a.distance.compareTo(b.distance);
});
});
}
}
this what i found:
getData() is async function. Future<List<Destination>> which is return list of Object not Map or json anymore
so when you call that function here :
body: FutureBuilder(
future: getData(),
builder: (context, snapshot) {
snapshot is List<Destination> , then no need to convert to list anymore.
just like below
return listViewWidget(snapshot);
then on your listViewWidget method , changes this :
title: Text('${article.position.name}',) // no need brackets

Parse complex JSON into List Flutter

I have a json file like this which I stored in the asset:
[
{
"topic":"Title One",
"subTopic":
[
"Overview",
"Install",
"Start"
]
},
{
"topic":"Title Two"
},
{
"topic":"Title Three",
"subTopic":
[
"Overview",
"Emulation",
"2. Install"
]
},
{
"topic":"Title Four",
"subTopic":
[
"Overview",
"Start",
"3. Try"
]
}
]
Which has an array and inside it also has array. I wonder how can I parse the "subTopic" as List and displayed it. My class:
class File {
String topic;
List<String> subTopic;
File({this.topic, this.subTopic});
File.fromJson(Map<String, dynamic> json) {
topic = json['topic'];
subTopic = json['subTopic'];
}
Map<String, dynamic> toJson() => {
'topic': topic,
'subTopic': subTopic,
};
}
What i did in maint.dart:
class MyHomePage extends StatelessWidget {
Future<List<File>> getData() async {
String response = await rootBundle.loadString('file.json');
return await Future.delayed(Duration(seconds: 2), () {
List<dynamic> data = jsonDecode(response);
//Iterate over list and map each object in list
List<File> files=
data.map((data) => File.fromJson(data)).toList();
return files;
});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text("File"),
),
body: Container(
child: FutureBuilder<List<File>>(
future: getData(),
builder: (context, data) {
if (data.connectionState != ConnectionState.waiting &&
data.hasData) {
var fileList = data.data;
return Drawer(
child: ListView.builder(
itemCount: fileList.length,
itemBuilder: (context, index) {
var fileData = fileList[index];
return ExpansionTile(
// key: Key("$index"),
// title: Text(fileData.topics?? ""),
children: <Widget>[
Container(
width: double.infinity,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
//I want to display the list of subTopic here
],
),
),
)
],
);
}),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}),
),
),
);
}
}
I want to displayed the list of subtopic in the listView. How can I do this? Thanks in advance!
It is quite easy you can cast your json['subtype'] as an Iterable to generate a new List<String> object.
Code:
List<String>.from(json['subTopic'] as Iterable)
Full Sample:
class File {
String topic;
List<String> subTopic;
File({this.topic, this.subTopic});
File.fromJson(Map<String, dynamic> json) {
topic = json['topic'];
subTopic = List<String>.from(json['subTopic'] as Iterable);
}
Map<String, dynamic> toJson() => {
'topic': topic,
'subTopic': subTopic,
};
}
It's best if you don't start with an Array map in its json format.
Maybe that's what made it difficult.
enter image description here
https://app.quicktype.io/
It is better to use Provider and ChangeNotifier and you can update the File class as following.
class File {
String topic;
List<String> subTopic;
File({this.topic, this.subTopic});
File.fromJson(Map<String, dynamic> json) {
topic = json['topic'];
subTopic = (json["subTopic"] as List).map((n) => (n.toString())).toList());
}
Map<String, dynamic> toJson() => {
'topic': topic,
'subTopic': subTopic,
};
}
if you need to show topic and subtopic, you can use flutter_section_table_view

Flutter: send data from first screen to second screen

I have little problem and I don't know how I can solve this. I am fetching datas from database and when I click on the list it is navigating to new screen. I mean I want to fetch datas which are on first screen to second screen. it is not giving me error but the simulator gives me this and codes below here:
class ServisIhaleEkran extends StatelessWidget {
final url = 'https://escar.com/cek.php';
Future<List<dynamic>> getIhaleData() async {
var response = await http.get(url);
return json.decode(response.body);
}
String _brand(dynamic user) {
return user['marka'];
}
String _model(dynamic user) {
return user['model'];
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: FutureBuilder<List<dynamic>>(
future: getIhaleData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Card(
child: Column(
children: <Widget>[
ListTile(
title: Text(
_brand(
snapshot.data[index],
).toString(),
),
onTap: () => _sendDataToSecondScreen(context),
),
],
),
);
},
);
} else {
return Center(child: Text('Error'));
}
},
),
);
}
void _sendDataToSecondScreen(BuildContext context) {
String brandSend = _brand.toString();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Details(brand: brandSend),
));
}
}
class Details extends StatelessWidget {
final String brand;
Details({this.brand});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Text(brand),
));
}
}
The First Screen: ServisIhaleEkran
The Second Screen: Details
I think, the problem is here:
void _sendDataToSecondScreen(BuildContext context) {
String brandSend = _brand.toString();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Details(brand: brandSend),
));
}
}
probably String brandSend = _brand.toString(); is giving me error but I don't know what is this, please help me, thanks.
and my first screen:
Rasat change your code as below:
void _sendDataToSecondScreen(BuildContext context, String brandSend) {
//String brandSend = _brand.toString();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Details(brand: brandSend),
));
}
And use it in your widget as:
ListTile(
title: Text(
_brand(
snapshot.data[index],
).toString(),
),
onTap: () => _sendDataToSecondScreen(context, _brand(snapshot.data[index])),
),

How to hide a floatingActionButton after insert data flutter?

I use sqflite for flutter database management. In particular, I would like the user to enter the data only once and therefore I would need to hide and disable the button only once the data has been entered. How can I do?
Home Page, where is the button
class Casa extends StatefulWidget {
static const routeName = '/';
#override
_CasaState createState() => _CasaState();
}
class _CasaState extends State<Casa> {
DataRepository _repository;
#override
void initState() {
super.initState();
_repository = SqlRepository();
}
#override
void dispose() async {
await _repository.closeDB();
super.dispose();
}
void getNewItem(BuildContext context) async {
Attivita newItem =
await Navigator.pushNamed<Attivita>(context, AddItemScreen.routeName);
if (newItem != null) {
await _repository.add(newItem);
setState(() {});
}
}
void switchAndUpdate(Attivita item) async {
await _repository.put(item.id, item);
setState(() {});
}
void delete(Attivita item) async {
await _repository.delete(item.id);
setState(() {});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Colors.lightBlue[900],
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add, color: Colors.lightBlue[900],),
backgroundColor: Colors.white,
onPressed: () {
getNewItem(context);
},
),
body:
FutureBuilder<List<Attivita>>(
future: _repository.getAll(),
builder:
(BuildContext context, AsyncSnapshot<List<Attivita>> snapshot) {
return ListView.builder(
padding: EdgeInsets.all(8),
itemCount: snapshot.data == null ? 0 : snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return Dismissible(
key: UniqueKey(),
background: DecoratedBox(
decoration: BoxDecoration(color: Colors.red),
child: Align(
alignment: Alignment(-0.9, 00),
child: Icon(
Icons.delete,
color: Colors.white,
),
),
),
direction: DismissDirection.startToEnd,
onDismissed: (direction) {
Attivita item = snapshot.data[index];
snapshot.data.removeAt(index);
delete(item);
},
child: Card(
child: ListTile(
title: Text(snapshot.data[index].nome, style: TextStyle(color: Colors.lightBlue[900]),),
onTap: () {
Navigator.pushNamed(context, DettaglioScreen.routeName, arguments: snapshot.data[index]);
},
onLongPress: () {
switchAndUpdate(snapshot.data[index]);
},
),
),
);
},
);
},
)
),
);
}
}
so i have to add some details, because it is written that "it looks like your post is mostly code; please add some more details"
To check if user put so data you can use:
Use sharedPreferences and store bool value if user entered data.
On initState check if database contains data if yes it means user put some data and you can hide button.
I don't use Sqlite in flutter but I think you can use
List<Map<String, dynamic>> result;
result = await db.query(tableName);
isNotData = result.isEmpty;
Or something similar :) You can do it
Choose one way and store bool value eg. in bool isNotData
When you will have bool value about data you can write:
In _CasaState above initState: bool isNotData;
and in Scaffold in floatingActionButton property:
Scaffold(
appBar: AppBar(
title: Text('Material App Bar'),
),
floatingActionButton: isNotData
? FloatingActionButton(
onPressed: () {},
)
: null,
body: Center(
),
),
),

How do I access separate children from Firebase database in Flutter?

Hi I am currently trying to access a child of my database in Flutter so that I can link it to another child. I am able to pull the data from one child, but unable to link this data with my other child. I want to be able to access a field of the 'Record' child and link to the 'Volunteer' child using the "volunteer" field but am unable to get them to link together. Any help would be appreciated!
The database structure is as follows:
This is the code for My Volunteer class:
class Volunteer {
String volunteerID;
String name;
String role;
Volunteer(this.volunteerID, this.name, this.role);
Volunteer.fromSnapshot(DataSnapshot snapshot)
: volunteerID = snapshot.key,
name = snapshot.value["name"],
role = snapshot.value["role"];
toJson() {
return {
"key": volunteerID,
"name": name,
"role": role
};
}
}
And this is the code for my UI:
class SignInPageState extends State<SignInPage> {
List<Volunteer> volunteers;
Volunteer volunteer;
DatabaseReference dbRef;
DatabaseReference volunteerRef;
DatabaseReference recordRef;
#override
void initState() {
super.initState();
volunteers = new List();
volunteer = Volunteer("","", "");
final FirebaseDatabase database = FirebaseDatabase.instance;
dbRef = database.reference();
volunteerRef = database.reference().child('volunteer');
recordRef = database.reference().child('record');
dbRef.onChildAdded.listen(_onEntryAdded);
dbRef.onChildChanged.listen(_onEntryChanged);
volunteerRef.once().then((DataSnapshot snapshot) {
Map<dynamic, dynamic> getMap = snapshot.value;
getMap.forEach((key, values) {
String volunteerRecord = recordRef.child('volunteer').toString();
if (volunteerRecord == volunteer.volunteerID){
volunteer.role = volunteerRecord;
}
volunteers.add(volunteer);
});
});
}
_onEntryAdded(Event event) {
setState(() {
volunteers.add(Volunteer.fromSnapshot(event.snapshot));
});
}
_onEntryChanged(Event event) {
var old = volunteers.singleWhere((entry) {
return entry.volunteerID == event.snapshot.key;
});
setState(() {
volunteers[volunteers.indexOf(old)] = Volunteer.fromSnapshot(event.snapshot);
});
}
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
padding: EdgeInsets.all(10.0),
color: Colors.white,
child: Column(
children: <Widget>[
Expanded(
flex: 8,
child: Container(
child: FirebaseAnimatedList(
query: volunteerRef,
itemBuilder: (BuildContext context, DataSnapshot snapshot,
Animation<double> animation, int index) {
return new ListTile(
title: Text(
(volunteers[index].name + " " + volunteers[index].role),
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontWeight: FontWeight.bold ,color: Color.fromRGBO(139, 195, 68, 1)),
),
onTap: () {
SuccessSignInPage(volunteers[index].name);
},
);
},
),
)
),
],
)),
),
);
}
void Back() async {
await Navigator.of(context).pop();
}
void SuccessSignInPage(String name) async {
var route = new MaterialPageRoute(
builder: (BuildContext context) => new SignInSuccessPage(value: name));
await Navigator.of(context).push(route);
}
}

Resources