Parameter is null instead of an id with ModalRoute.of() - firebase

I am developing a mobile App with Flutter and Firebase.
I am trying to use pushNamed() and hand over a parameter. (an id)
I don't know how i could solve my problem.
Here is my Code:
#override
void didChangeDependencies() {
if (_isInit) {
print(ModalRoute.of(context).settings.arguments);
final productId = ModalRoute.of(context).settings.arguments;
if (productId != null) {
_editedAngebot = Provider.of<Angebote>(context).findByID(productId);
_initValues = {
'titel': _editedAngebot.titel,
'beschreibung': _editedAngebot.beschreibung,
'semester': _editedAngebot.semester.toString(),
'fach': _editedAngebot.fach,
'abteilung': _editedAngebot.abteilung,
};
}
}
_isInit = false;
super.didChangeDependencies();
}
And the other class, where I set the parameter. My "Angebot" object only has a default constructor.
trailing: isAllowed()
? IconButton(
icon: Icon(Icons.edit),
onPressed: () {
Navigator.of(context).maybePop();
Navigator.of(context)
.pushNamed('/editAngebot', arguments: id);
})
Why is my ID null?

Your Id is null because you are popping a page first then pushing new page .
Use pushReplacementNamed()
Here is a code sample
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: FirstPage(),
routes:{
Secondpage.routeName:(context)=>Secondpage(),
}
);
}
}
class FirstPage extends StatelessWidget {
final String id = '01';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child:ElevatedButton(
child: Text('GoTo secondPage'),
onPressed: (){
Navigator.of(context).pushReplacementNamed(Secondpage.routeName,arguments: id);
},
))
);
}
}
class Secondpage extends StatelessWidget {
static const routeName = 'secondpage';
#override
Widget build(BuildContext context) {
final data = ModalRoute.of(context).settings.arguments as String;
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(child:Text('$data')),
ElevatedButton(
child: Text('GoTo FirstPage'),
onPressed: (){
Navigator.of(context).pop();
},
)
],
)
);
}
}

you should probably change the id defined in the class to a dynamic type and it would work.. tested this and it works as fine
class Product with ChangeNotifier {
//changed to dynamic as errors with null and string came topping up
final dynamic id;
final String title;
final String description;
Product(
{required this.id,
required this.title,
required this.description,
});

Related

Stream Provider / Provider.of returning null when data is present

I was following a tutorial of sorts and got to a section where we print out what we have in the firestore database. However for some reason my Provider.of seems to be returning null when there is at least one data entry.
home.dart and MemoryList:
class Home extends StatelessWidget {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
return StreamProvider<List<Person>>.value (
value: DatabaseService().memories,
initialData:[],
child: Scaffold(
backgroundColor: Colors.lightBlueAccent[50],
appBar: AppBar(
title: Text('Memory Bank'),
backgroundColor: Colors.deepPurple[300],
elevation: 0.0,
actions: <Widget>[
TextButton.icon(
icon: Icon(Icons.person),
label: Text('logout'),
onPressed: ()async{
await _auth.signOut();
},
),//textbutton
],//widget[]
),//appbar
body: MemoryList(),
)//scaffold
);//streamProvider.value
}
}
class MemoryList extends StatefulWidget {
#override
_MemoryListState createState() => _MemoryListState();
}
class _MemoryListState extends State<MemoryList> {
#override
Widget build(BuildContext context) {
final memories = Provider.of<List<Person>>(context);
print("current data:");
print(memories);
if(memories != null){
memories.forEach((element) {
print(element.name);
//print(element.name.events);
//print(element.name.likes);
});
}
return ListView.builder(
itemCount: memories.length,
itemBuilder: (context,index){
return MemoryTile(person: memories[index]);
}
);
}
}
For here the Provider.of<List>(context) returns with nothing.
The stream is:
final CollectionReference memoryCollection = FirebaseFirestore.instance.collection('memories');
Stream<List<Person>> get memories {
Stream<QuerySnapshot> snapshot_stream = memoryCollection.snapshots();
print("getting memories: ");
//print(snapshot_stream.first);
//print(snapshot_stream.first.toString());
return memoryCollection.snapshots().map(_memoryListFromSnapshot);
}
With a simple Person model with just a name:
class Person{
final String name;
Person({required this.name});
}
Any help would be appreciated!

How to pass data across Stateful widget?

So my question is i get data from firebase in first widget, then i click and open a bottomsheet through void -> another stateful widget, how can i pass the snapshot data from first widget to the other one?
Below code is not working...
....
Widget build(BuildContext context) {
return Container(
ElevatedButton(
child: Text('Request a tour'),
onPressed: () {
displayBottomSheet(context, widget.snapshot.data()["author"]);
},
),
);
void displayBottomSheet(BuildContext context, String author) { //updated
showModalBottomSheet(
context: context,
builder: (ctx) {
return BottomSheetWidget(author); //updated
});
}
NEW ERROR: Too many positional arguments: 0 expected, but 1 found.
class BottomSheetWidget extends StatefulWidget {
final String author; //updated
BottomSheetWidget({this.author}); //updated
#override
class _BottomSheetWidgetState createState() => _BottomSheetWidgetState();
}
class _BottomSheetWidgetState extends State<BottomSheetWidget> {
Widget build(BuildContext context) {
return Container(
new ElevatedButton(
child: Text('Send'),
onPressed: () {
requestTour(widget.author); //updated
},
),
.....
}
requestTour(String userName) async {
...
}
class BottomSheetWidget extends StatefulWidget {
final String author; //updated
BottomSheetWidget(this.author); //<-- remove {}
#override
class _BottomSheetWidgetState createState() => _BottomSheetWidgetState();
}
class _BottomSheetWidgetState extends State<BottomSheetWidget> {
Widget build(BuildContext context) {
return Container(
new ElevatedButton(
child: Text('Send'),
onPressed: () {
requestTour(widget.author); //updated
},
),
.....
}
requestTour(String userName) async {
...
}
Just remove curly braces for new arrived error:
replace BottomSheetWidget({this.author}); with BottomSheetWidget(this.author);

Undefined class 'AllCoursesSnapshot'

I am trying to retrieve data from firebase database and display it on my UI. This is the code written :
class AllCourses {
String courseName;
String teacher;
String category;
AllCourses(this.courseName, this.teacher, this.category);
}
import 'package:creators_club/firestore/courses.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
class BusinessPage extends StatefulWidget {
#override
_BusinessPageState createState() => _BusinessPageState();
}
class _BusinessPageState extends State<BusinessPage> {
List<AllCourses> coursesList = [];
#override
void initState(){
super.initState();
DatabaseReference referenceAllCourses = FirebaseDatabase.instance.reference().child('AllCourses');
referenceAllCourses.once().then(((AllCoursesSnapshot allCoursesSnapshot){
coursesList.clear();
var keys = allCoursesSnapshot.value.keys;
var values = allCoursesSnapshot.value;
for(var key in keys){
AllCourses allCourses = new AllCourses(
values [key]["courseName"],
values [key]["teacher"],
values [key]["category"],
);
coursesList.add(allCourses);
}
setState(() {
//HERE
});
}));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),),
title: Text("Creator's Club"),
backgroundColor: Color(0xff2657ce),
elevation: 0,),
body: coursesList.length == 0 ? Center(child: Text("No Data Avail", style: TextStyle(fontSize: 15),)): ListView.builder(
itemCount: coursesList.length,
itemBuilder: (_,index){
return CardUI(coursesList[index].courseName, coursesList[index].teacher, coursesList[index].category);}
)
);
}
}
}
Why isn't the AllCoursesSnapshot being recognized? It says that it is "Type: Null Function(dynamic)".
Here is a picture of the database table in Realtime Database: (https://imgur.com/a/xDZy1SW).
It is not recognized because there is no class called AllCoursesSnapshot. The once() method belongs to the firebase_database plugin, and it returns a Future<DataSnapshot>, therefore you have to do the following:
referenceAllCourses.once().then((DataSnapshot dataSnapshot){
Also replace allCoursesSnapshot with dataSnapshot in the other parts of your code.

Updating only the tapped ListTile color in a list

How do I update the color of only the ListTile that is tapped?
Whatever I tried, it just changes the color of all tiles when tap.
How can I retrieve the data and change the color?
class _DesignState extends State<Design> {
var status=0;
var score =0;
Color getContainerColor() {
if (status == 0) {
return Colors.white;
} else if (status == 1) {
return Colors.green;
} else {
return Colors.red;
}
Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
final record = Record.fromSnapshot(data);
final record1= Firestore.instance.collection('creds').document('123').get().then((DocumentSnapshot ds) {
var s =Record.fromSnapshot(ds);
score= s.score;
});
child: ListTile(
title: Text(record.name),
trailing: Text(record.score.toString()),
onTap: () { record.reference.updateData({'score': FieldValue.increment(score)}),
setState(){
status=1;
You're already on the right track, but it looks like you're managing the state of all of your list tile in the same StatefulWidget.
Instead you'll just need to split them up, so that every of your custom ListTile has it's on state. The loading of the data can happen in the parent component of your self build ListTile.
I'll provide you a short example application. The following example is without firebase, but it should be no problem to apply these changes to your application.
You'd simply have to do the data fetching inside the parent component and pass the score parameter of your example to MyListTile – just like the title in the example below.
This is runnablbe on it's own, you can simply copy it into a empty Flutter project:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
MyListTile(title: 'First'),
MyListTile(title: 'Second'),
MyListTile(title: 'Third'),
],
),
),
);
}
}
class MyListTile extends StatefulWidget {
final String title;
MyListTile({this.title});
#override
_MyListTileState createState() => _MyListTileState();
}
class _MyListTileState extends State<MyListTile> {
int status = 0;
get tileColor {
switch(status) {
case 0: {
return Colors.white;
}
case 1: {
return Colors.green;
}
default: {
return Colors.red;
}
}
}
#override
Widget build(BuildContext context) {
return Container(
color: tileColor,
child: ListTile(
title: Text(widget.title),
subtitle: Text('Status: $status'),
onTap: () => setState(() {
status++;
}),
),
);
}
}

not able to update list after http call ( flutter)

i'm new to flutter
i try to do an http call and then populate a list. The problem is that the http call works fine but the UI doesn't refresh.
i think that the problem is that the framework create ui with the list before the http call is finish. Than when the http call is finished i'm unable to update the ui.
i've search but i didn't find anything.
EDIT--FOUND SOLUTION IN Listview.Builder code here
http call
static Future<Map> getData() async {
try{
http.Response res = await http.get("http://....");
Map data = JSON.decode(res.body);
print(res.body);
return data;
}
catch(exception){
//todo
}
}
main
class _MyHomePageState extends State<MyHomePage> {
List<Widget> _items = new List<GithubCardItem>();
#override
void initState() {
super.initState();
print("start download");
_downloadData();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text(widget.title)),
body: new ListView.builder(
itemBuilder: (BuildContext context, int index) => _items[index],
itemExtent: 128.0,
itemCount: _items.length,
),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.add),
onPressed: (){
_downloadData();
},
)
);
}
GithubCard _extractDataFromJson(Map githubCard){
GithubCard card = new GithubCard(githubCard["name"], githubCard["avatar_url"], githubCard["description"], githubCard["stargazers_count"], githubCard["open_issued_count"]);
return card;
}
void _downloadData(){
MyHttpCall.getData().then((jsonData) {
//check if i have card to display
if(jsonData["items"] != null){
for(var githubCard in jsonData["items"]){
setState(() {
GithubCard card = _extractDataFromJson(githubCard);
this._items.add(new GithubCardItem(card));
});
print("adding elements");
}
}
});
}
}
the GithubCardItem is a simple stateless widget that return a text.
There are different ways to use ListView as well as get data from network
here is the sample code for your problem
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List list = new List();
void fetchData() {
getData().then((res) {
setState(() {
list.addAll(res);
});
});
}
#override
void initState() {
super.initState();
fetchData();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new ListView.builder(
itemCount: list.length,
itemBuilder: ((BuildContext _context, int position) {
return new ListTile(
title: new Text( list[position]['login'].toString()),
subtitle: new Text(list[position]['url']),
leading: new Image.network(list[position]['avatar_url']),
);
}),
),
),
floatingActionButton: new FloatingActionButton(
onPressed: fetchData,
tooltip: 'Increment',
child: new Icon(Icons.add),
),
);
}
Future<List> getData() async {
var url = "https://api.github.com/users";
List data = new List();
var httpClient = new HttpClient();
var request = await httpClient.getUrl(Uri.parse(url));
var response = await request.close();
if (response.statusCode == HttpStatus.OK) {
var jsonString = await response.transform(utf8.decoder).join();
data = json.decode(jsonString);
return data;
}else{
return data;
}
}
}
Try this:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {----------- }
class MyHomePage extends StatefulWidget {-----------}
class _MyHomePageState extends State<MyHomePage> {
List data;
Future<String> getData() async {
var response = await http.get(
Uri.encodeFull("https://api.github.com/users"),
headers: {"Accept": "application/json"});
this.setState(() {
data = json.decode(response.body);
});
return "Success!";
}
#override
void initState() {
this.getData();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Listviews"),
),
body: new ListView.builder(
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, int position) {
return new ListTile(
title: new Text(data[position]['login'].toString()),
subtitle: new Text(data[position]['url']),
leading: new Image.network(data[position]['avatar_url']),
);
},
),
);
}
}
Made bit more simple and it's working. Check the sample here

Resources