I was building a DataTable from json call. Everything is going well but data is not showing.
//standing.dart
import '../modal/catelog_point_table_model.dart';
import '../services/category_point_table_services.dart';
import 'package:flutter/material.dart';
class DataTableWidget extends StatefulWidget {
#override
DataTableWidgetState createState() => DataTableWidgetState();
}
class DataTableWidgetState extends State<DataTableWidget> {
final List<String> cityColumns = [
'Team',
'M',
'W',
'NRR',
'Pts'
];
List<City> cities;
bool ascending;
#override
void initState() {
super.initState();
ascending = false;
}
#override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SizedBox(
width: width*1.5,
child: ListView(
children: <Widget>[
buildDataTable(),
],
),
),
);
}
Widget buildDataTable() => DataTable(
sortAscending: ascending,
columns: cityColumns
.map(
(String column) => DataColumn(
label: Text(column),
onSort: (int columnIndex, bool ascending) => onSortColumn(
columnIndex: columnIndex, ascending: ascending),
),
)
.toList(),
rows: cities.map((City city) => DataRow(
cells: [
DataCell(Text('${city.title}')),
DataCell(Text('${city.price}')),
DataCell(Text('${city.description}')),
DataCell(Text('${city.nrr}')),
DataCell(Text('${city.pts}')),
],
))
.toList(),
);
void onSortColumn({int columnIndex, bool ascending}) {
if (columnIndex == 0) {
setState(() {
if (ascending) {
cities.sort((a, b) => a.title.compareTo(b.title));
} else {
cities.sort((a, b) => b.title.compareTo(a.title));
}
this.ascending = ascending;
});
}
}
}
//catelog_point_table_model.dart
import 'dart:async' show Future;
import '../modal/catelog_point_table_model.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
Future<List<City>> loadCatelog(String id) async {
String url = 'https://icc-point-table.nittodigital.now.sh/api/Catelogs/category/5ce1a425eda9891fa8b51430';
final response = await http.get(url);
print(response.body);
return cities(response.body);
}
//catelog_point_table_model.dart
import 'dart:convert';
class City {
final int imgcount;
final String id;
final String title;
final String price;
final String description;
final String nrr;
final String pts;
final List<String> gallery;
City({
this.imgcount,
this.id,
this.title,
this.price,
this.description,
this.nrr,
this.pts,
this.gallery
});
factory City.fromJson(Map<String, dynamic> parsedJson) {
var streetsFromJson = parsedJson['gallery'];
//print(streetsFromJson.runtimeType);
// List<String> streetsList = new List<String>.from(streetsFromJson);
List<String> galleryList = streetsFromJson.cast<String>();
return new City(
imgcount: parsedJson['img_v'],
id: parsedJson['_id'],
title: parsedJson['title'],
price: parsedJson['price'],
description: parsedJson['description'],
nrr: parsedJson['nrr'],
pts: parsedJson['pts'],
gallery: galleryList,
);
}
}
List<City> cities(str) {
final jsonData = json.decode(str);
return List<City>.from(jsonData.map((x) => City.fromJson(x)));
}
NoSuchMethodError: The method 'map' was called on null
This is what I am getting. Maybe I am not getting data because List is not static type.
it would be really nice if someone told me how to fetch the data correctly and make a bond with DataRow.
*sorry for my poor English.
You have to call your loadCatelog from inside your initState function. Since your call is async and initState does not allow async calls, you have to put the code in a seperate method:
#override
void initState() {
super.initState();
ascending = false;
_getData();
}
void _getData() async{
cities = await loadCatelog();
}
Also, you are asking for an id as a parameter for your function, but never use it. So either remove that parameter or pass it accordingly.
There would be an even more elegant way by using FutureBuilder if you only need to retreive the data from the API once, or StreamBuilder if you want to get live updates from said API.
Related
i want to add hashtags to the list in state, but i can't add value to list using Bloc Flutter
When i add the data to the list in file bloc, it doesn't work.
Here i send the event by onPressed method.
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: Text(
'Save',
style: Theme.of(context).textTheme.subtitle2?.copyWith(
fontSize: 15, color: colorBlue, letterSpacing: 1),
),
onPressed: () {
if (_hashtagController.value.text.isNotEmpty) {
context
.read<DealsBloc>()
.add(AddHashtag(hashtag: _hashtagController.value.text));
Navigator.of(context).pop();
}
},
),
Event File
Here i describe the event "Add Hashtag".
part of 'deals_bloc.dart';
abstract class DealsEvent extends Equatable {
const DealsEvent();
#override
List<Object> get props => [];
}
class AddHashtag extends DealsEvent {
final String hashtag;
const AddHashtag({
required this.hashtag
});
#override
List<Object> get props => [ hashtag ];
}
State File
part of 'deals_bloc.dart';
class DealsState extends Equatable {
final List<String> hashtags;
final List<Deal> deals;
final List<String> imagePaths;
const DealsState({
this.deals = const <Deal>[],
this.imagePaths = const <String>[],
this.hashtags = const <String>['Add a new hashtag']
});
#override
List<Object?> get props => [hashtags, deals, imagePaths];
Map<String, dynamic> toMap() {
return {
'hashtags': this.hashtags,
'deals': this.deals,
'imagePaths': this.imagePaths,
};
}
factory DealsState.fromMap(Map<String, dynamic> map) {
return DealsState(
hashtags: map['hashtags'] as List<String>,
deals: map['deals'] as List<Deal>,
imagePaths: map['imagePaths'] as List<String>,
);
}
}
Bloc File
import 'package:equatable/equatable.dart';
import 'package:trade_stat/blocs/bloc_exports.dart';
part 'deals_event.dart';
part 'deals_state.dart';
class DealsBloc extends HydratedBloc<DealsEvent, DealsState> {
final DealsRepository dealsRepository;
DealsBloc({required this.dealsRepository}) : super(const DealsState()) {
on<AddHashtag>(_onAddHashtag);
}
void _onAddHashtag(AddHashtag event, Emitter<DealsState> emit) {
final state = this.state;
List<String> hashtags = state.hashtags;
hashtags.add(event.hashtag);
emit(DealsState(hashtags: hashtags));
print(state.hashtags);
}
#override
DealsState? fromJson(Map<String, dynamic> json) {
return DealsState.fromMap(json);
}
#override
Map<String, dynamic>? toJson(DealsState state) {
return state.toMap();
}
}
I try to add the data to the list, but it doesn't work.
When I add data to the list I get an error.
E/flutter (10932): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Unsupported operation: Cannot add to an unmodifiable list
Few things you could do:
List<String> hashtags = List.from(state.hashtags);
hashtags.add(event.hashtag);
or
Remove const from DealerState
const DealsState({
this.deals,
this.imagePaths,
this.hashtags,
});
i want to add hashtags to the list in state, but i can't add value to list using Bloc Flutter
When i add the data to the list in file bloc, it doesn't work.
Here i send the event by onPressed method.
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: Text(
'Save',
style: Theme.of(context).textTheme.subtitle2?.copyWith(
fontSize: 15, color: colorBlue, letterSpacing: 1),
),
onPressed: () {
var hashtag;
setState(() {
hashtag = _hashtagController.value.text;
});
print(hashtag);
if (_hashtagController.value.text.isNotEmpty) {
context
.read<DealsBloc>()
.add(AddHashtag(hashtag: _hashtagController.value.text));
Navigator.of(context).pop();
}
},
),
Event File
Here i describe the event "Add Hashtag".
part of 'deals_bloc.dart';
abstract class DealsEvent extends Equatable {
const DealsEvent();
#override
List<Object> get props => [];
}
class AddHashtag extends DealsEvent {
final String hashtag;
const AddHashtag({
required this.hashtag
});
#override
List<Object> get props => [ hashtag ];
}
State File
part of 'deals_bloc.dart';
class DealsState extends Equatable {
final List<String> hashtags;
final List<Deal> deals;
final List<String> imagePaths;
const DealsState({
this.deals = const <Deal>[],
this.imagePaths = const <String>[],
this.hashtags = const <String>['Add a new hashtag']
});
#override
List<Object?> get props => [hashtags, deals, imagePaths];
Map<String, dynamic> toMap() {
return {
'hashtags': this.hashtags,
'deals': this.deals,
'imagePaths': this.imagePaths,
};
}
factory DealsState.fromMap(Map<String, dynamic> map) {
return DealsState(
hashtags: map['hashtags'] as List<String>,
deals: map['deals'] as List<Deal>,
imagePaths: map['imagePaths'] as List<String>,
);
}
}
Bloc File
import 'package:equatable/equatable.dart';
import 'package:trade_stat/blocs/bloc_exports.dart';
part 'deals_event.dart';
part 'deals_state.dart';
class DealsBloc extends HydratedBloc<DealsEvent, DealsState> {
final DealsRepository dealsRepository;
DealsBloc({required this.dealsRepository}) : super(const DealsState()) {
on<AddHashtag>(_onAddHashtag);
}
void _onAddHashtag(AddHashtag event, Emitter<DealsState> emit) {
final state = this.state;
List<String> hashtags = List.from(state.hashtags);
hashtags.add(event.hashtag);
emit(DealsState(hashtags: hashtags));
print(state.hashtags);
}
#override
DealsState? fromJson(Map<String, dynamic> json) {
return DealsState.fromMap(json);
}
#override
Map<String, dynamic>? toJson(DealsState state) {
return state.toMap();
}
}
What i get as a result
I/flutter (11934): trend
I/flutter (11934): [Add a new hashtag]
Value was not added to the list.
The list remains the same.
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.
Hello I'm new to flutter, and I'm trying to do a simple user profile screen for a user who logged in but I stumbled in some errors, the first one was for when I tried to use the StreamBuilder() where the stream didn't get any data from the getter in the UserProvider()(that's where I putted my BL) it kept saying getCurrentUserData() was called on null, so i just connected it directly to the UserService() and it worked, but then when I tried to edit the user info and have the TextFormField() be filled with the user data, via the initState() and have the fullNameController get the data from the UserModel() the error returned it keeps saying fullName was called on null! how do I resolve this can anyone point on where I'm going wrong about here?
P.S I'm following this tutorial to build this.
My StreamBuilder() connected to UserProvider:
return StreamBuilder<UserModel>(
stream: userProviderData.getCurrentUserData(),
builder: (context, snapshot) {})
My StreamBuilder() directly connected to UserService:
Directly connected to UserService
return StreamBuilder<UserModel>(
stream: userService.getCurrentUser(),
builder: (context, snapshot) {})
UserService() class:
// Get User
Stream<UserModel> getCurrentUser() {
return _db.collection('users').doc(_auth.currentUser.uid).snapshots().map(
(user) => UserModel.fromJson(user.data()),
);
}
// Add or Update User info
Future<void> saveUser(UserModel user) {
final _options = SetOptions(merge: true);
return _db.collection('users').doc(user.userId).set(user.toMap(), _options);
}
UserProvider() class:
final userProvider = ChangeNotifierProvider<UserProvider>((ref) {
return;
});
class UserProvider with ChangeNotifier {
final userService = UserService();
String _userId;
String _fullName;
// Getters
String get userId => _userId;
String get fullName => _fullName;
Stream<UserModel> get getCurrentUserData => userService.getCurrentUser();
// Setters
set changeFullName(String fullName) {
_fullName = fullName;
notifyListeners();
}
// Functions
void loadUser(UserModel userModel) {
_userId = userModel.userId;
_fullName = userModel.fullName;
}
void updateUser() {
final _currentUser = UserModel(
userId: _userId,
fullName: _fullName,
);
userService.saveUser(_currentUser);
}
}
EditProfileScreen():
class EditProfileScreen extends StatefulWidget {
const EditProfileScreen({this.userModel});
final UserModel userModel;
#override
_EditProfileScreenState createState() => _EditProfileScreenState();
}
class _EditProfileScreenState extends State<EditProfileScreen> {
final _fullNameController = TextEditingController();
final _validator = Validator();
#override
void dispose() {
_fullNameController.dispose();
super.dispose();
}
#override
void initState() {
super.initState();
final userStream = context.read(userProvider);
if (widget.userModel != null) {
// Edit
_fullNameController.text = widget.userModel.fullName;
userStream.loadUser(widget.userModel);
}
}
#override
Widget build(BuildContext context) {
final userData = context.read(userProvider);
return Scaffold(
body: Column(
children: [
TextFormFiled(
hintText: ‘Full name’,
keyboardType: TextInputType.name,
controller: _fullNameController,
validator: (value) => _validator.validateFullName(
value,
),
onChanged: (value) {
userData.changeFullName = value;
debugPrint(value);
}
),
ElevatedButton(
onPressed: () {
userData.updateUser();
Navigator.of(context).pop();
},
child: const Text(‘Save’),
),
],
),
);
}
}
Did you forget to return something?
final userProvider = ChangeNotifierProvider<UserProvider>((ref) {
return; //return a UserProvider()
});
[ 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.