Reputation: 296
both files have same problem **The getter 'length' was called on null. Receiver: null Tried calling: length ** file name product.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import './product_list.dart';
import '../../../api/api_conf.dart' as ApiBase;
import '../../../size_config.dart';
import './section_title.dart';
class PopularProducts extends StatefulWidget {
@override
_PopularProductsState createState() => _PopularProductsState();
}
class _PopularProductsState extends State<PopularProducts> {
var url = ApiBase.baseURL + "menus.php";
var menus;
void initState() {
super.initState();
fetchData();
}
fetchData() async {
var res = await http.get(url);
menus = jsonDecode(res.body)["menu"];
print(menus);
setState(() {});
}
@override
Widget build(BuildContext context) {
return Column(
children: List.generate(menus.length, (index) {
return Column(children: [
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(20),
vertical: getProportionateScreenHeight(0)),
child: SectionTitle(title: menus[index]["name"], press: () {}),
),
SizedBox(height: getProportionateScreenWidth(20)),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ProductList(menuid: menus[index]["id"]),
),
]);
}),
);
}
}
please check res.body print of product.dart file
[{id: 1, name: Electronics }, {id: 2, name: New Cloths }, {id: 3, name: T-Shirt }, {id: 4, name: Pak }, {id: 5, name: Shoes } ]
next custom widget product_list.dart both page have same problem
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shop_app/components/product_card.dart';
import '../../../api/api_conf.dart' as ApiBase;
import 'package:http/http.dart' as http;
class ProductList extends StatefulWidget {
final String menuid;
const ProductList({Key key, @required this.menuid}) : super(key: key);
@override
_ProductListState createState() => _ProductListState();
}
class _ProductListState extends State<ProductList> {
var products;
void initState() {
super.initState();
var url = ApiBase.baseURL + "products.php?menu_id=" + widget.menuid;
fetchdata(url);
}
fetchdata(url) async {
var res = await http.get(url);
products = jsonDecode(res.body);
print(products);
setState(() {});
}
@override
Widget build(BuildContext context) {
return Row(
children: List.generate(
products.length,
(index) {
return ProductCard(product: products[index]);
},
),
);
}
}
please check res.body print of product_list.dart file
[{id: 1, name: IPhone 12, price: 300000, image: 1.jpg }, {id: 2, name: Nokia, price: 20000, image: 2.jpg }, {id: 3, name: OPPO, price: 50000, image: 3.jpg }, {id: 4, name: MI, price: 40000, image: 4.jpg }, {id: 5, name: Samsung, price: 34000, image: 5.jpg } ]
file name product_card.dart
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:shop_app/screens/details/details_screen.dart';
import '../api/api_conf.dart' as ApiBase;
import '../constants.dart';
import '../size_config.dart';
class ProductCard extends StatefulWidget {
const ProductCard(
{Key key,
this.width = 140,
this.aspectRetio = 1.02,
@required this.product})
: super(key: key);
final double width, aspectRetio;
final product;
@override
_ProductCardState createState() => _ProductCardState();
static ProductCard fromJson(i) {}
}
class _ProductCardState extends State<ProductCard> {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(left: getProportionateScreenWidth(20)),
child: SizedBox(
width: getProportionateScreenWidth(widget.width),
child: GestureDetector(
onTap: () => Navigator.pushNamed(
context,
DetailsScreen.routeName,
arguments: ProductDetailsArguments(product: widget.product),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AspectRatio(
aspectRatio: 1.02,
child: Container(
padding: EdgeInsets.all(getProportionateScreenWidth(20)),
decoration: BoxDecoration(
color: kSecondaryColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(15),
),
child: Hero(
tag: widget.product["id"].toString(),
child: FadeInImage(
image: NetworkImage(
ApiBase.productURL + widget.product["file_name"]),
placeholder: AssetImage('assets/images/1.jpg'),
),
),
),
),
const SizedBox(height: 10),
Text(
widget.product["name"],
style: TextStyle(color: Colors.black),
maxLines: 2,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
widget.product["price"].toString(),
style: TextStyle(
fontSize: getProportionateScreenWidth(18),
fontWeight: FontWeight.w600,
color: kPrimaryColor,
),
),
InkWell(
borderRadius: BorderRadius.circular(50),
onTap: () {},
child: Container(
padding: EdgeInsets.all(getProportionateScreenWidth(8)),
height: getProportionateScreenWidth(28),
width: getProportionateScreenWidth(28),
decoration: BoxDecoration(
color: widget.product["id"] == 1
? kPrimaryColor.withOpacity(0.15)
: kSecondaryColor.withOpacity(0.1),
shape: BoxShape.circle,
),
child: SvgPicture.asset(
"assets/icons/Heart Icon_2.svg",
color: widget.product["id"] == 1
? Color(0xFFFF4848)
: Color(0xFFDBDEE4),
),
),
),
],
)
],
),
),
),
);
}
}
application working and error showing on console *The getter 'length' was called on null. Receiver: null Tried calling: length *
Upvotes: 0
Views: 605
Reputation: 12803
The problem is because Widget build
will be called first and you are not initialize both of your list in the first page.
You should initialize your List as below:
var products = List<ProductsCard>();
Upvotes: 0
Reputation: 8393
Your fetchData
is async does not finish before initState
finishes. Hence, menus
is still null when the build
method runs.
You could use a FutureBuilder
instead:
class PopularProducts extends StatelessWidget {
var url = ApiBase.baseURL + "menus.php";
Future<Map<String, dynamic>> fetchData() async {
var res = await http.get(url);
return jsonDecode(res.body)["menu"];
}
@override
Widget build(BuildContext context) {
return FutureBuilder<Object>(
future: fetchData(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting: return Text('Loading....');
default:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
else
return Text('Result: ${snapshot.data}');
}
},
);
}
}
Upvotes: 1