I'm using the Dart feature Collection-if introduced in Dart 2.3. My model class is
class Calendar {
Calendar(
{this.headerDate, this.releaseDate, this.period,this.title});
final DateTime headerDate;
final DateTime releaseDate;
final String title;
final String period;
factory Calendar.fromMap(Map<String, dynamic> value) {
final int releaseDateMilliseconds = value['releaseDate'];
final int headerDateMilliseconds= value['headerDate'];
return Calendar(
releaseDate: DateTime.fromMillisecondsSinceEpoch(releaseDateMilliseconds),
headerDate: DateTime.fromMillisecondsSinceEpoch(headerDateMilliseconds),
title: value['title'],
period: value['period'],
);
}
}
The feature works fine when I'm dealing with Strings but doesn't work when I check for null for for the DateTime objects. The dates are stored as numbers in firestore and converted in to DateTime objects. Here is my build method:
#override
Widget build(BuildContext context) {
return Column(children: [
if(calendar.title!=null) /// Works
Text(calendar.title),
if(calendar.period!=null) ///Works
Text(calendar.period),
if(calendar.headerDate!=null) /// Doesn't work
Text(Format.date(calendar.headerDate)),
Text(Format.date(calendar.releaseDate)),
]);
}
Related
In the tutorial, String categoryTitle; and List displayedMeals; were working fine. In the current version of flutter it won't allow me to just declare as it is. What should I initialize them to? It would be nice to know what is the equivalent in declaring String and List now since thre is a null safety. Also, when I put String? and ListMeal? as declaration and put [!], i get an error of null check operator used on a null value. I can't put late also because I don't what should I initialize these declarations.
import 'package:flutter/material.dart';
import '../widgets/meal_item.dart';
import '../dummy_data.dart';
import '../models/meal.dart';
class CategoryMealsScreen extends StatefulWidget {
static const routeName = '/category-meals';
#override
State<CategoryMealsScreen> createState() => _CategoryMealsScreenState();
}
class _CategoryMealsScreenState extends State<CategoryMealsScreen> {
// final String categoryId;
String categoryTitle;
List<Meal> displayedMeals;
var _loadedInitData = false;
#override
void initState() {
super.initState();
}
#override
void didChangeDependecies() {
if (!_loadedInitData) {
final routeArgs =
ModalRoute.of(context)!.settings.arguments as Map<String, String>;
categoryTitle = routeArgs['title']!;
final categoryId = routeArgs['id'];
displayedMeals = DUMMY_MEALS.where((meal) {
return meal.categories.contains(categoryId);
}).toList();
}
_loadedInitData = true;
super.didChangeDependencies();
}
void _removeMeal(String mealId) {
setState(() {
displayedMeals!.removeWhere((meal) => meal.id == mealId);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(categoryTitle!),
),
body: ListView.builder(
itemBuilder: (ctx, index) {
return MealItem(
id: displayedMeals[index].id,
title: displayedMeals[index].title,
imageUrl: displayedMeals[index].imageUrl,
duration: displayedMeals[index].duration,
affordability: displayedMeals[index].affordability,
complexity: displayedMeals[index].complexity,
removedItem: _removeMeal,
);
},
itemCount: displayedMeals.length,
),
);
}
}
It happens because of null safety. Either you declare your variables as nullable, so they can be null or you use the keyword late in front of the variable like this:
late String categoryTitle;
late List<Meal> displayedMeals;
But then you should also declare the variables in the initState or before you use them, otherwise an exception will be thrown.
Write like that :
String? categoryTitle;
its nullsafety
So i have my dart call to my api get method. Btw the way am just learning flutter and dart and trying out basic crud operations I would use to be doing in .net and c#
import 'dart:convert';
import 'package:theapp/models/Players.dart';
import 'package:http/http.dart';
class ApiService {
final String apiUrl = "https://apiurlhidden.com/api";
final String getAllPlayersEndPoint = "/GetAllPlayers/";
Future<List<Player>> getAllPlayers() async {
final getallPlayersUrl = Uri.parse(apiUrl + getAllPlayersEndPoint);
Response res = await get(getallPlayersUrl);
if (res.statusCode == 200) {
List<dynamic> body = jsonDecode(res.body);
List<Player> players =
body.map((dynamic item) => Player.fromJson(item)).toList();
return players;
} else {
throw "Failed to load cases list";
}
}
}
And I have my listview here but it complaining saying key and players do not exist
import 'package:flutter/material.dart';
import 'package:theapp/models/Players.dart';
class PlayerList extends StatelessWidget {
List<Player> players = [];
PlayerList({Key key, this.players}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: players == null ? 0 : players.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: InkWell(
onTap: () {},
child: ListTile(
leading: Icon(Icons.person),
title: Text(players[index].firstName),
subtitle: Text(players[index].surname.toString()),
),
));
});
}
}
My Model
class Player {
final int id;
final int type;
final String playerLevel;
final String firstName;
final String surname;
Player(this.id, this.type, this.playerLevel, this.firstName, this.surname);
factory Player.fromJson(Map<String, dynamic> json) {
return Player(
json['id'],
json['type'],
json['playerlevel'],
json['firstname'],
json['surname'],
);
}
#override
String toString() =>
'Players{id: $id, firstName: $firstName, lastName: $surname}';
}
Is there any reason why it should not recognize players and key in my list view page also how do I get the items to appear in the listview.
Picture only added to show the context in the items I mentioned above. Also coming from a .net background I would normally use an observable collection so it gets any changes in data in real-time am I using the correct approach for that.
Use required keyword to make parameters mandatory.
PlayerList({required Key key, required this.players}) : super(key: key);
Named parameters are optional unless they’re explicitly marked as required.
See Parameters for details.
I want to map my data in a custom widget, but I am not sure how to parse them in that widget.
Here is a type of data:
Here is Widget who need to serve that data:
The problem is how to prepare a custom widget in the constructor class? And how to display data in a tree? e.g this.module['title], or object notation this.module.title :)
Help!
I am a newbie in Flutter.
Thanks!
First create a class to handle your data.
class Module {
String title;
int id;
String excerpt; // I'm not sure about types... Since i can't see the values
String thumbnail;
String content;
Module.fromJson(data){
this.title = data["title"];
this.id = data["id"];
this.excerpt = data["excerpt"];
this.thumbnail = data["thumbnail"];
this.content = data["content"];
}
}
Then you use it where you fetch your data (obviously in onInit()).
List<Module> modules = List.empty();
yourMethode(){
YourApi.route().then((result){
setState((){
modules = result.map((module){return Module.fromJson(module);});
});
});
}
}
Then in your custom widget
class ModuleList extends StatelessWidget{
final List<Module> modules;
/// The constructor
const ModuleList(this.modules);
#override
Widget build(BuildContext context) {
return ListView.builder(itemBuilder: (BuildContext context, int index) {
Module myModule = modules[index];
return Column(
children: [
Text(myModule.title)
// other elements here
],
);
});
}
}
Finally use the widget in the same widget you made your API cals
//...
child: ModuleList(modules)
//...
how can I use groupBy function which is in collection.dart to group items by two fields and return a model class with them not one field like int?
If I group by one field, It works fine and there is no problem:
Map<int, List<FooterItem>> _getGroups(List<FooterItem> items) {
return groupBy(items, (FooterItem i) {
return i.groupId;
});
}
But when I wan to return a model class from result ,groupBy is not grouping values .
here I have a list of FooterItem which has It's group data and how can I use groupBy to group a List<FooterItem> by groupId and titleGroup and return FooterGroup not int :
class FooterItem {
final int id;//item id
final int groupId;
final String title;//item title
final String titleGroup;
...
}
Map<FooterGroup, List<FooterItem>> _getGroups(List<FooterItem> items) {
return groupBy(items, (FooterItem i) {
return FooterGroup(id: i.groupId, title: i.titleGroup);
});
}
I could solve problem by extending Equatable in the model class which I wanted to use as grouped values and overriding props :
import 'package:equatable/equatable.dart';
class FooterGroup extends Equatable{
final int id;
final String title;
FooterGroup({
#required this.id,
#required this.title,
});
#override
List<Object> get props => [id,title];
}
so duplicate values of Groups where not seen any more. so
Map<FooterGroup, List<FooterItem>> _getGroups(List<FooterItem> items) {
return groupBy(items, (FooterItem i) {
return FooterGroup(id: i.groupId, title: i.titleGroup);
});
}
works fine now.
A quick way to achieve this:
groupBy(footers, (FooterItem f) {
return '${f.groupId}+${f.titleGroup}';
});
Source: https://coflutter.com/dart-how-to-group-items-in-a-list/
[ Sorry for my bad English ]
In this project I'm viewing events lists in some pages from JSON API and in
CloudEvents page I'm viewing another list from Firebase Database, using Event model ...
Now when I run CloudEvents page I get null for itemsEvent[i].startDate
with this Error: A non-null String must be provided to a Text widget.
Open: Error Snapshot
Open: Firebase Database Snapshot
I used this Method for my model
This is my Event model
class Event {
String key;
String sectionID;
String sectionTitle;
String title;
String startDate;
String endDate;
String startDateAr;
String endDateAr;
String city;
String detail;
String location;
String more;
String link;
// for generalevent.json
String eventDate;
String eventDateAr;
Event(
{this.sectionID,
this.sectionTitle,
this.title,
this.startDate,
this.endDate,
this.startDateAr,
this.endDateAr,
this.city,
this.detail,
this.location,
this.more,
this.link,
this.eventDate,
this.eventDateAr});
factory Event.fromJson(Map<String, dynamic> json) {
return Event(
sectionID: json['section-id'],
sectionTitle: json['section-title'],
title: json['title'],
startDate: json['start-event-date'],
endDate: json['end-event-date'],
startDateAr: json['start-event-date-ar'],
endDateAr: json['end-event-date-ar'],
city: json['city'],
detail: json['detail'],
location: json['location'],
more: json['more'],
link: json['link'],
// for generalevent.json
eventDate: json['event-date'],
eventDateAr: json['event-date-ar'],
);
}
Event.fromSnapshot(DataSnapshot snapshot)
: key = snapshot.key,
title = snapshot.value['title'],
startDate = snapshot.value['startDate'];
toJson() {
return {
"title": title,
"startDate": startDate,
};
}
}
And this is my CloudEvents page
import 'package:events/UI/styleguide.dart';
import 'package:events/models/event.dart' as e;
import 'package:events/pages/account.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:firebase_database/ui/firebase_animated_list.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:intl/intl.dart' as intl;
final FirebaseAuth mAuth = FirebaseAuth.instance;
final db = FirebaseDatabase.instance.reference();
FirebaseUser mCurrentUser;
List<e.Event> itemsEvent = List();
e.Event itemEvent;
DatabaseReference dbEvent;
class CloudEvents extends StatefulWidget {
final GlobalKey<ScaffoldState> scaffoldKey;
const CloudEvents({Key key, #required this.scaffoldKey}) : super(key: key);
#override
_CloudEventsState createState() => _CloudEventsState();
}
class _CloudEventsState extends State<CloudEvents> {
ScrollController _hideButtonController;
var _isVisible;
#override
initState() {
super.initState();
...
itemEvent = e.Event();
final FirebaseDatabase database = FirebaseDatabase.instance;
dbEvent = database.reference().child('events');
dbEvent.onChildAdded.listen(_onEntryAddedEvent);
dbEvent.onChildChanged.listen(_onEntryChangedEvent);
...
}
_onEntryAddedEvent(Event event) {
setState(() {
itemsEvent.add(e.Event.fromSnapshot(event.snapshot));
});
}
_onEntryChangedEvent(Event event) {
var old = itemsEvent.singleWhere((entry) {
return entry.key == event.snapshot.key;
});
setState(() {
itemsEvent[e.Event.indexOf(old)] = e.Event.fromSnapshot(event.snapshot);
});
}
#override
Widget build(BuildContext context) {
return showEvents();
}
Widget showEvents(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height,
child: Stack(
children: <Widget>[
FirebaseAnimatedList(
query: dbEvent.child(mCurrentUser.uid),
itemBuilder: (_, DataSnapshot snapshot,
Animation<double> animation, int i) {
return new ListTile(
title: new Text(snapshot.value['title']), //snapshot works well
subtitle: new Text(itemsEvent[i].startDate), // this returns null
);
}),
...
],
),
);
}
...
}
I just realized the problem here, according to u/Cholojuanito's comment on reddit
I did his number 1 possible solution, and then I edited:
Text(itemsEvent[i].startDate) to
Text(e.Event.fromSnapshot(snapshot).startDate)
and it worked so well, thank you for everyone who commented on reddit.