how to show api call data in mention in flutter - flutter

String string = "";
Map<String, dynamic> jsonMap = {};
List<Map<String, dynamic>> data = [];
class Mentions extends StatefulWidget {
const Mentions({
Key? key,
this.width,
this.height,
}) : super(key: key);
final double? width;
final double? height;
#override
_MentionsState createState() => _MentionsState();
}
class _MentionsState extends State<Mentions> {
GlobalKey<FlutterMentionsState> key = GlobalKey<FlutterMentionsState>();
Future apicall() async {
http.Response response;
var url = "https://7J8Y54OD18-dsn.algolia.net/1/indexes/users";
response = await http.get(Uri.parse(url), headers: {
'X-Algolia-API-Key': '841e31106f80e21b89b0d2b9ec7cd561',
'X-Algolia-Application-Id': '7J8Y54OD18'
});
if (response.statusCode == 200) {
setState(() {
jsonMap = json.decode(response.body);
(jsonMap['hits'] as List).forEach((x) => {data.add(Map.from(x))});
});
} else {
string = "failed";
}
}
#override
void initState() {
apicall();
super.initState();
}
#override
Widget build(BuildContext context) {
return Portal(
child: Scaffold(
appBar: AppBar(
title: Text("flutter mention"),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(
child: FlutterMentions(
key: key,
suggestionPosition: SuggestionPosition.Top,
maxLines: 5,
minLines: 3,
decoration: InputDecoration(hintText: 'hello'),
mentions: [
Mention(
trigger: '#',
style: TextStyle(
color: Colors.amber,
),
data: data,
matchAll: false,
suggestionBuilder: (data) {
return Container(
padding: EdgeInsets.all(10.0),
child: Row(
children: <Widget>[
SizedBox(
width: 20.0,
),
Column(
children: <Widget>[
Text(data['objectID']),
Text('#${data['username']}'),
],
)
],
),
);
}),
Mention(
trigger: '#',
disableMarkup: true,
style: TextStyle(
color: Colors.blue,
),
data: [
{'id': 'reactjs', 'display': 'reactjs'},
{'id': 'javascript', 'display': 'javascript'},
],
matchAll: true,
)
],
),
),
],
),
),
);
}
}
i build this custom widget of mention which should show a list of users on tapping # and show another list on tapping #, the # trigger is working fine but # trigger is giving following error please help
Nosuchmethoderror : 'toLowerCase'
Dynamic call of null
receiver : null
Arguments : []
how to remove this error and get the list of users from the api call above mentioned , please help api call result is not null i checked it
widget i am using : https://pub.dev/packages/flutter_mentions

Related

Flutter Null check operator used on a null value even after checking conditionally for null values

I have a Flutter + Riverpod project in which I am fetching some data when a screen loads. Getting the Null check operator error but I am checking if the value is null or not beforehand. State has a nullable field currentlyReading which is null at the beginning. Function to fetch data is being called in the constructor of the controller. The state is being updated correctly after fetching.
Trying to render UI conditionally based on the result of fetch but getting the error.
Controller that fetches data and manages state:
final bookControllerProvider = StateNotifierProvider<BookController, BookState>(
(ref) => BookController(ref.read(bookRepositoryProvider), ref));
class BookState {
final Book? currentlyReading;
final List<Book>? books;
final bool isLoading;
final String? error;
BookState(
{this.currentlyReading,
this.books = const [],
this.isLoading = true,
this.error});
BookState copyWith({
Book? currentlyReading,
List<Book>? books,
bool? isLoading,
String? error,
}) {
return BookState(
currentlyReading: currentlyReading ?? this.currentlyReading,
books: books ?? this.books,
isLoading: isLoading ?? this.isLoading,
error: error ?? this.error,
);
}
}
class BookController extends StateNotifier<BookState> {
final BookRepository _bookRepository;
final Ref _ref;
BookController(this._bookRepository, this._ref) : super(BookState()) {
getCurrentlyReading();
}
void getCurrentlyReading() async {
state = state.copyWith(isLoading: true);
final user = _ref.read(userProvider);
final book = await _bookRepository.getBook(user!.readingBook!);
book.fold((l) {
state = state.copyWith(error: l.message, isLoading: false);
}, (userBook) {
state = state.copyWith(currentlyReading: userBook, isLoading: false);
});
}
}
Using in UI:
final user = ref.watch(userProvider)!;
final bookData = ref.watch(bookControllerProvider);
return Scaffold(
body: SafeArea(
child: Padding(
padding:
const EdgeInsets.only(top: 16.0, right: 16, bottom: 8, left: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 16),
Text(
'Currently Reading',
style: AppStyles.bodyText.copyWith(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Pallete.textGrey),
),
const SizedBox(height: 16),
bookData.isLoading
? const Expanded(child: Center(child: Loader()))
: bookData.currentlyReading == null
? const Text('Some error occurred')
: BookInfo(
book: bookData.currentlyReading!, height: deviceHeight)
],
),
),
));
BookInfo:
class BookInfo extends StatelessWidget {
final Book book;
final double height;
const BookInfo({
Key? key,
required this.book,
required this.height,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image(
image: NetworkImage(book.thumbnail!),
),
SizedBox(
height: height * 0.01,
),
Text(book.title,
style: AppStyles.subtext.copyWith(
color: Pallete.primaryBlue, fontWeight: FontWeight.w500)),
Text('by ${book.authors.join(', ')}', style: AppStyles.bodyText),
],
);
}
}
However, a simple Text widget like below works when used in place of BookInfo
Text(bookData.currentlyReading!.title)
Your problem is not because of bookData.currentlyReading its happened in BookInfo widget when try to build Image widget, book.thumbnail may be null and you use ! on it:
book.thumbnail == null ? SizedBox() : Image(
image: NetworkImage(book.thumbnail!),
),

How can I map a JSON map to single key multiple values

This might be a bit of broad question.
I have an JSON Map Array which i can parse normally. But i would like to MAP multiple Values to a Single key. I am stuck and unsure how to proceed.
My JSON output. I cannot change this.
{
"pos":"1",
"element":"37542",
"title":"Easy On Me",
"inter":"Adele",
"isnew":"0"
},
{
"pos":"66",
"element":"37183",
"title":"Send My Love",
"inter":"Adele",
"isnew":"0"
}
this is just a snippet of the actual JSON objects
what I would like to do is something like Map<String,List<String,String>>
Adele
Easy On Me, 37542
Send My Love, 37183
Searching online I find a lot of examples how to parse JSON normally, but never found a version where you can iterate through a JSON version like above and pull parts of the map out and add it to another.
any help would be appreciated. Thank you in advance
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'dart:async';
class SongList {
final List<Song> songs;
SongList({
required this.songs,
});
factory SongList.fromJson(List<dynamic> parsedJson) {
List<Song> songs = <Song>[];
songs = parsedJson.map((i) => Song.fromJson(i)).toList();
return SongList(songs: songs);
}
}
class Song {
final String? pos;
final String? element;
final String? title;
final String? inter;
final String? isnew;
const Song(
{required this.pos,
required this.element,
required this.title,
required this.inter,
required this.isnew});
factory Song.fromJson(Map<String, dynamic> data) {
return Song(
pos: data['pos'] as String?,
element: data['element'] as String?,
title: data['title'] as String?,
inter: data['inter'] as String?,
isnew: data['isnew'] as String?,
);
}
}
import 'package:flutter/material.dart';
import 'package:just_audio/just_audio.dart';
class Songs extends StatefulWidget {
final String pos;
final String element;
final String title;
final String inter;
final String isnew;
const Songs(
{super.key,
required this.pos,
required this.element,
required this.title,
required this.inter,
required this.isnew});
#override
State<Songs> createState() => _SongsState();
}
class _SongsState extends State<Songs> {
late AudioPlayer player;
#override
void initState() {
super.initState();
player = AudioPlayer();
}
#override
void dispose() {
player.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
var titles = Row(
mainAxisSize: MainAxisSize.min,
children: [
Column(children: [
SizedBox(
height: 25,
width: 200,
child: Text(
widget.title,
style: const TextStyle(fontSize: 14),
textAlign: TextAlign.center,
),
),
SizedBox(
height: 25,
width: 200,
child: Text(
widget.inter,
style: const TextStyle(fontSize: 10),
textAlign: TextAlign.center,
),
),
]),
],
);
return FittedBox(
fit: BoxFit.contain,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
Center(
child: SizedBox(
height: 50,
width: 50,
child: Align(
alignment: Alignment.center,
child: widget.isnew != "1"
? Text(
widget.pos.toString(),
textAlign: TextAlign.center,
)
: const Text(
"new",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.red),
)))),
],
),
Column(
children: [
SizedBox(
height: 50,
width: 50,
child: Image.network(
'${'http://www.example.com/${widget.element}'}.jpg'),
),
],
),
Column(
children: [
titles,
],
),
Column(
children: [
SizedBox(
height: 50,
width: 50,
child: TextButton(
onPressed: () async {
final url =
'${'http://www.example.com/${widget.element}'}.mp3';
await player.setUrl(url);
player.play();
},
child: Image.asset('assets/images/btn_play.png'),
),
),
],
),
Column(
children: [
SizedBox(
height: 50,
width: 50,
child: TextButton(
// ignore: avoid_print
onPressed: () =>
print('pressed button download!! ${widget.element}'),
child: Image.asset('assets/images/btn_download.png'),
),
),
],
),
],
)));
}
}
Future<SongList> fetchSong() async {
final response = await http
.get(Uri.parse('http://example.com'));
if (response.statusCode == 200) {
return SongList.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to Load Songs');
}
}
//snippet from class that instatiates
late Future<SongList> futureSong;
#override
void initState() {
super.initState();
futureSong = fetchSong();
}
//snippet from class that builds the list
FutureBuilder<SongList>(
future: futureSong,
builder: (context, AsyncSnapshot<SongList> snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.songs.length,
itemBuilder: (context, index) {
if (snapshot.data!.songs[index].element.toString() !=
"null") {
return Songs(
element:
snapshot.data!.songs[index].element.toString(),
inter: snapshot.data!.songs[index].inter.toString(),
isnew: snapshot.data!.songs[index].isnew.toString(),
pos: snapshot.data!.songs[index].pos.toString(),
title: snapshot.data!.songs[index].title.toString());
} else {
return const SizedBox(height: 0);
}
});
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
}
This might work:
void main() {
var data=[
{
"pos":"1",
"element":"37542",
"title":"Easy On Me",
"inter":"Adele",
"isnew":"0"
},
{
"pos":"66",
"element":"37183",
"title":"Send My Love",
"inter":"Adele",
"isnew":"0"
},
{
"pos":"80",
"element":"5000",
"title":"Enjoy the silence",
"inter":"Depeche Mode",
"isnew":"0"
},
{
"pos":"100",
"element":"6000",
"title":"In your room",
"inter":"Depeche Mode",
"isnew":"0"
}
];
var result = <String,List<Map<String,String>>>{};
for (var d in data) {
print(d);
var e={"element":d["element"]!, "title": d["title"]!};
var key=d["inter"]!;
if (result.containsKey(key)) {
result[key]!.add(e);
} else {
result[key]=[e];
}
}
print(result);
}
You can achieve this by creating a subclass.
Interpret interpretFromJson(String st) => Interpret.fromJson(json.decode(st));
class Interpret{
Interpret({
required this.name,
required this.titles,
});
final String name;
final List<Title> titles;
factory Interpret.fromJson(Map<String, dynamic> json) => Title(
name: json["inter"],
titles: List<Title>.from(json.map((x) => Title.fromJson(x))),
);
}
class Title {
Title({
required this.name,
required this.element,
});
final String name;
final double element;
factory Title.fromJson(Map<String, dynamic> json) => Title(
name: json["name"],
element: json["element"],
);
Then you can just call it like.
InterpretFromJson(json);

Dropdown not working with List of strings flutter

I am having some trouble when setting up my dropdown functionality. I do not understand why is this since the widget itself accepts String: DropdownMenuItem
I get the error:
type string is not a subtype of type DropdownMenuItem<dynamic>
I tried either to cast my value to String or dynamic like this:
value: map["breed"].cast() or
value: map["breed"].cast()
but nothing seems to work.
class DogForm extends StatefulWidget {
#override
_DogFormState createState() => _DogFormState();
}
class _DogFormState extends State<DogForm> {
final todoController = TextEditingController();
final List<DropdownMenuItem> breeds = [];
String? _mySelection = '';
final List<Map> _mybreedJson = [
{
"breed": "Cavalier King Charles Spaniel",
"img":
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/5f/CarterBIS.Tiki.13.6.09.jpg/220px-CarterBIS.Tiki.13.6.09.jpg"
},
{
"breed": "Curly-Coated Retriever",
"img":
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Curly_Coated_Retriever.jpg/220px-Curly_Coated_Retriever.jpg"
},
];
void addToDo() async {
if (todoController.text.trim().isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text("Empty title"),
duration: Duration(seconds: 2),
));
return;
}
await saveTodo(todoController.text);
setState(() {
todoController.clear();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Parse Todo List"),
backgroundColor: Colors.blueAccent,
centerTitle: true,
),
body: Column(
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(17.0, 1.0, 7.0, 1.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: DropdownButtonHideUnderline(
child: ButtonTheme(
alignedDropdown: true,
child: DropdownButton<String>(
isDense: true,
hint: Text('Select Breed'),
value: _mySelection,
onChanged: (String? newValue) {
setState(() {
_mySelection = newValue;
});
},
items: _mybreedJson.map((Map map) {
return DropdownMenuItem<String>(
value: map["breed"],
// value: _mySelection,
child: Row(
children: <Widget>[
Image.asset(
map["img"],
width: 25,
),
Container(
margin: EdgeInsets.only(left: 10),
child: Text(map["breed"])),
],
),
);
}).toList(),
),
),
),
),
]),
)
],
));
}
}
Future<void> saveTodo(String title) async {
await Future.delayed(Duration(seconds: 1), () {});
final todo = ParseObject('Todo')
..set('title', title)
..set('done', false);
await todo.save();
}
Please! can somebody tell me how to make it work with a list like this?
_mybreedJson = [
{
"breed": "Cavalier King Charles Spaniel",
"img":
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/5f/CarterBIS.Tiki.13.6.09.jpg/220px-CarterBIS.Tiki.13.6.09.jpg"
},
{
"breed": "Curly-Coated Retriever",
"img":
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Curly_Coated_Retriever.jpg/220px-Curly_Coated_Retriever.jpg"
},
];
This is what you want ?, please run codes. I changed .asset => .network and , I put real value as default value
import 'package:flutter/material.dart';
import 'package:parse_server_sdk_flutter/parse_server_sdk.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
theme: ThemeData.dark(),
home: DogForm(),
);
}
}
class DogForm extends StatefulWidget {
#override
_DogFormState createState() => _DogFormState();
}
class _DogFormState extends State<DogForm> {
final todoController = TextEditingController();
final List<DropdownMenuItem> breeds = [];
String? _mySelection = 'Cavalier King Charles Spaniel';
final List<Map> _mybreedJson = [
{
"breed": "Cavalier King Charles Spaniel",
"img":
"https://images.pexels.com/photos/45201/kitty-cat-kitten-pet-45201.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"
},
{
"breed": "Curly-Coated Retriever",
"img":
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSjiLOiEP-qSR6OgMrPELypnHToVToGPEc_qTkuLq5mMKwCCMoQ4x6Fsn19uvBoDO0qZaQ&usqp=CAU"
},
];
void addToDo() async {
if (todoController.text.trim().isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text("Empty title"),
duration: Duration(seconds: 2),
));
return;
}
await saveTodo(todoController.text);
setState(() {
todoController.clear();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Parse Todo List"),
backgroundColor: Colors.blueAccent,
centerTitle: true,
),
body: Column(
children: <Widget>[
Container(
padding: const EdgeInsets.fromLTRB(17.0, 1.0, 7.0, 1.0),
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
Expanded(
child: DropdownButtonHideUnderline(
child: ButtonTheme(
alignedDropdown: true,
child: DropdownButton<String>(
isDense: true,
hint: const Text('Select Breed'),
value: _mySelection,
onChanged: (String? newValue) {
setState(() {
_mySelection = newValue;
});
},
items: _mybreedJson.map((Map map) {
return DropdownMenuItem<String>(
value: map["breed"],
// value: _mySelection,
child: Row(
children: <Widget>[
Image.network(
map["img"],
width: 25,
),
Container(margin: const EdgeInsets.only(left: 10), child: Text(map["breed"])),
],
),
);
}).toList(),
),
),
),
),
]),
)
],
));
}
}
Future<void> saveTodo(String title) async {
await Future.delayed(const Duration(seconds: 1), () {});
final todo = ParseObject('Todo')
..set('title', title)
..set('done', false);
await todo.save();
}
If you make Map map --> Map<String,String> map, maybe flutter show you where error is.

The method 'getProducts' was called on null

i am trying to retrieve data using rest api from woocommerce website using flutter
this is the api for retrieve json data
Future<List<Product>> getProducts(String tagId) async {
List<Product> data = new List<Product>();
try {
String url = Config.url +
Config.productsURL +
"?consumer_key=${Config.key}&consumer_secret=${Config.secret}&tag=$tagId";
var response = await Dio().get(url,
options: new Options(
headers: {HttpHeaders.contentTypeHeader: "application/json"}));
if (response.statusCode == 200) {
data = (response.data as List).map((i) => Product.fromJson(i),).toList();
}
} on DioError catch (e) {
print(e.response);
}
return data;
}
this is the widget to handle the data to the mobile app
class WidgetHomeProducts extends StatefulWidget {
WidgetHomeProducts({Key key, this.labelName, this.tagId}) : super(key : key);
String labelName;
String tagId;
#override
_WidgetHomeProductsState createState() => _WidgetHomeProductsState();
}
class _WidgetHomeProductsState extends State<WidgetHomeProducts> {
APIServices apiServices;
#override
void initState() {
apiServices = new APIServices();
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
color: const Color(0xffF4F7FA),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 16, top: 4),
child: Text(
this.widget.labelName,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
),
Padding(
padding: EdgeInsets.only(left: 16, top: 4),
child: FlatButton(
onPressed: () {},
child: Text(
'View All',
style: TextStyle(color: Colors.blueAccent),
),
),
),
],
),
_productList(),
],
),
);
}
Widget _productList(){
return new FutureBuilder(
future: apiServices.getProducts(this.widget.tagId),
builder: (BuildContext context, AsyncSnapshot<List<Product>> model){
if(model.hasData){
return _buildList(model.data);
}if(model.hasError){
print("error");
}
return Center(child: CircularProgressIndicator(),);
});
}
i got The method error message that says
'getProducts' was called on null.
Receiver: null
Tried calling: getProducts("971")
can anyone help me to fix this?

Flutter Argument passing - Getting a null from routeArgs

I have the following setup of my flutter app:
HomeScreen.Dart
Widget build(BuildContext context) {
return Scaffold(
appBar: homeAppBar(context),
bottomNavigationBar: BottomNavBar(),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
CategoryList(),
ItemList(),
],
),
));
}
}
The CategoryList class contains a list view of category items. When a category item is clicked, the associated products should be displayed for that item. The way I do that is by passing the category name to the product item list class. Please see below:
CategoryItem.dart
class CategoryItemN extends StatelessWidget {
final String title;
const CategoryItemNew({
#required this.title,
});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => selectCategory(context),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
child: Column(
children: <Widget>[
Text(
title,
style: isActive
? TextStyle(
color: kTextColor,
fontWeight: FontWeight.bold,
)
: TextStyle(fontSize: 12),
),
if (isActive)
Container(
margin: EdgeInsets.symmetric(vertical: 5),
height: 3,
width: 22,
decoration: BoxDecoration(
color: kPrimaryColor,
borderRadius: BorderRadius.circular(10),
),
),
],
),
),
);
}
void selectCategory(BuildContext ctx) {
Navigator.of(ctx).pushNamed(
ItemList.routeName,
arguments: {
'title': title ==== > This is the category name
},
);
}
}
ItemList.dart
class _ItemListState extends State<ItemList> {
var _isInit = true;
var _isLoading = false;
var title = '';
void didChangeDependencies() {
if (_isInit) {
setState(() {
_isLoading = true;
});
final routeArgs =
ModalRoute.of(context).settings.arguments as Map<String, String>;
title = routeArgs['title']; ===================> This is where the error occurs!
Provider.of<Products>(context).fetchProducts(title, true).then((_) {
setState(() {
_isLoading = false;
});
});
}
_isInit = false;
super.didChangeDependencies();
}
Here's the error message:
The following NoSuchMethodError was thrown building Listener: The method '[]' was called on null. Receiver: null Tried calling []("title")
You can get arguments through 'ModalRoute.of(context).settings.arguments' in the build().
final routeArgs =
ModalRoute.of(context).settings.arguments as Map<String, String>;
There is a official example about 'Pass arguments to a named route'.
https://flutter.dev/docs/cookbook/navigation/navigate-with-arguments