This the first UI in there when user enter channel name and after click join then should it pass "loadData" method in there that channel name should pass to "API" and get channelname and appId from that url.
join button code
Future<void> onJoin() async {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => loadData(myController.text)),
);
}
loadData method
import 'dart:convert';
import 'package:http/http.dart';
import '../model/appIdModel.dart';
class ApiService {
loadData(String myController) async {
final String url ='https://jsonplaceholder.typicode.com/posts/1=$myController';
Future<List<Data>> getData() async {
Response response = await get(Uri.parse(url));
if (response.statusCode == 2000) {
Map<String, dynamic> json = jsonDecode(response.body);
List<dynamic> body = json['data'];
List<Data> datas = body.map((dynamic item) => Data.fromJson(item).toList();
return datas;
} else {
throw ('cannot fetch data');
}
}
}
}
Data model code
class Data {
String appId;
String channelName;
Data({
required this.appId,
required this.channelName,
});
factory Data.fromJson(Map<String, dynamic> json) {
return Data(
appId: json['appId'] == null ? null : json['appId'],
channelName: json['channelName'] == null ? null : json['channelName']);
}
}
then appId and channelName should fetch
FutureBuilder widget code show channelId and channelName (Home page code)
class _MyHomePageState extends State<MyHomePage> {
final myController = TextEditingController();
bool _validateError = false;
ApiService client = ApiService();
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: SingleChildScrollView(
clipBehavior: Clip.antiAliasWithSaveLayer,
physics: BouncingScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(padding: EdgeInsets.only(top: 20)),
Padding(padding: EdgeInsets.symmetric(vertical: 20)),
Container(
width: MediaQuery.of(context).size.width * 0.8,
child: TextFormField(
controller: myController,
decoration: InputDecoration(
labelText: 'Channel Name',
labelStyle: TextStyle(color: Colors.blue),
hintText: 'test',
hintStyle: TextStyle(color: Colors.black45),
errorText:
_validateError ? 'Channel name is mandatory' : null,
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue),
borderRadius: BorderRadius.circular(20),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue),
borderRadius: BorderRadius.circular(20),
),
disabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue),
borderRadius: BorderRadius.circular(20),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.blue),
borderRadius: BorderRadius.circular(20),
),
),
),
),
Padding(padding: EdgeInsets.symmetric(vertical: 30)),
Container(
width: MediaQuery.of(context).size.width * 0.25,
child: MaterialButton(
onPressed: onJoin,
height: 40,
color: Colors.blueAccent,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Text(
'Join',
style: TextStyle(color: Colors.white),
),
Icon(
Icons.arrow_forward,
color: Colors.white,
),
],
),
),
),
Center(
child: FutureBuilder(
future: client.getData(),
builder: (BuildContext context,
AsyncSnapshot<List<Data>> snapshot) {
if (snapshot.hasData) {
List<Data>? data = snapshot.data;
return ListView.builder(
itemBuilder: (context, index) => Column(
children: [
Text(
data![index].channelName.toString(),
),
Text(
data[index].appId.toString(),
),
],
));
}
return const Center(
child: CircularProgressIndicator(),
);
}),
)
],
),
),
),
),
);
}
Future<void> onJoin() async {
setState(() {
myController.text.isEmpty
? _validateError = true
: _validateError = false;
});
// await _handleCameraAndMic(Permission.camera);
// await _handleCameraAndMic(Permission.microphone);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => loadData(myController.text)),
);
}
this is the my code to fetch data.when I run the url with channel name then data show nicely. I tired to fetch "channelName" and "appId" using this url.
CodePudding user response:
You are doing wrong when you call onJoin
, change it to this:
Future<void> onJoin() async {
future = client.getData(myController.text);
}
then define new variable like this:
Future<List<Data>>? future;
then change ApiService to this:
class ApiService {
final String url =
'https://jsonplaceholder.typicode.com/posts/1';
Future<List<Data>> getData(String myController) async {
Response response = await get(Uri.parse(url myController));
if (response.statusCode == 200) { // <--- change this
Map<String, dynamic> json = jsonDecode(response.body);
List<dynamic> body = json['data'];
List<Data> datas = body.map((dynamic item) => Data.fromJson(item).toList();
return datas;
} else {
throw ('cannot fetch data');
}
}
}
then change your FutureBuilder
to this
future != null ? FutureBuilder(//<--- add this
future: future,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return const Center(
child: CircularProgressIndicator(),
);
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
future = null; //<--- add this
List<Data> data = snapshot.data ?? []; //<-- change this
return ListView.builder(
itemCount: data.length, //<-- add this
itemBuilder: (context, index) => Column(
children: [
Text(
data[index].channelName.toString(),
),
Text(
data[index].appId.toString(),
),
],
));
}
}
},
)
: SizedBox(),//<--- add this
also as you can see in your postman result the data
contain a map
, not list of map, so if you expect a list
you need to contact to your backend but if not you can parse it like this:
Map<String, dynamic> body = json['data'];
List<Data> datas = [Data.fromJson(body)];
also for ui issue you can't use listview
inside SingleChildScrollView
, for that you need set shrinkWrap
to true
, also set its physics to NeverScrollableScrollPhysics
too:
return ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: ...
)