I tried for the first time using Stream builder with HTTP requests. it is not updating data.
find below my code. Thanks for helping me!
///////////////////////////////////////// ////////////////////////////////// /////////////// //////////////////// ///////////////////// //////////////////// ///////////////////////////
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner:false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({ Key? key }) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: listMarkers,
builder: (BuildContext context,AsyncSnapshot<List<Coordonnees>> snapshot){
switch (snapshot.connectionState){
case ConnectionState.none:
// TODO: Handle this case.
// break;
case ConnectionState.waiting:
// TODO: Handle this case.
// break;
case ConnectionState.active:
return Center(child:CircularProgressIndicator());
// break;
case ConnectionState.done:
List<Coordonnees>? mark=snapshot.data;
return Center(
child:Text('latitude: ${mark![0].latitude}',
style: TextStyle(
fontSize: 30,
)
),
);
// break;
}
},
),
);
}
List<Coordonnees> marqueurs=[];
Future<List<Coordonnees>> UpdateMarkers(String id) async{
Map data = {
'idligne': id,
};
final response = await http.post(
Uri.parse("https://www.sirius-iot.eu/Dev/ESI/qitari2021/sarah.php?lignegps"),
body: data);
Map<String,dynamic> map=json.decode(response.body);
List<dynamic> dataa = map['lignegps'];
marqueurs.clear();
for(var i in dataa)
{
Coordonnees crd=Coordonnees(double.parse(i['latitude']),double.parse(i['longitude']),double.parse(i['vitesse']));
marqueurs.add(crd);
}
return marqueurs;
}
Stream<List<Coordonnees>> get listMarkers async*{
String id='1';
yield await UpdateMarkers(id) ;
}
}
class Coordonnees{
double latitude;
double longitude;
double vitesse;
Coordonnees(this.latitude,this.longitude,this.vitesse);
}
You can try .asStream() instead of manually yielding data which is awaited.
void main() {
listMarkers.listen((coordinates) {
print(coordinates);
});
}
class Coordinates {
int x;
int y;
Coordinates(this.x, this.y);
}
Future<List<Coordinates>> updateMarkers(String id) async{
await Future.delayed(Duration(seconds: 2));
return [
Coordinates(1,2)
];
}
Stream<List<Coordinates>> get listMarkers => updateMarkers('1').asStream();
Notice how elegant Stream<List<Coordinates>> get listMarkers => updateMarkers('1').asStream(); is as compared to what you are doing. And hopefully it will solve your issue too.
Related
I have a serious problem with my Riverpod. Specifically, I am using StateProvider in Riverpod package. But when I update state, the widget tree does not rebuild. I checked the new state whether is updated by printing out state to see, I see that they are actually updated.
I have some same situations but when I click hot restart/reload page/scroll up,down mouse to change size chrome window, the widget tree rebuild one time.
Please help me and explain everything the most detail and easy to understand. Thank you very much
new state print out but UI not update
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:math';
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class Data {
final String data;
Data({required this.data});
}
final helloWorldProvider = StateProvider<Data?>((ref) => Data(data: 'No data'));
class MyApp extends ConsumerStatefulWidget {
const MyApp({super.key});
#override
ConsumerState<MyApp> createState() => _MyAppState();
}
class _MyAppState extends ConsumerState<MyApp> {
#override
void initState() {
// TODO: implement initState4
print("Init state");
super.initState();
// getData();
}
// getData() async {
// // http.Response response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/todos/1'));
// // final title = jsonDecode(response.body)["title"];;
// // ref.read(helloWorldProvider.notifier).update((state) => title);
// SharedPreferences prefs = await SharedPreferences.getInstance();
// prefs.setString('valueTemp', 'newValue');
// String? valueTemp = prefs.getString('valueTemp');
// String value = valueTemp ?? '';
// Data data = Data(data: value);
// ref.read(helloWorldProvider.notifier).update((state) => data);
// print("Đã thực hiện xong");
// }
void _change() {
print("change");
final rawString = generateRandomString(5);
Data data = new Data(data: rawString);
ref.watch(helloWorldProvider.notifier).update((state) => data);
print(ref.read(helloWorldProvider.notifier).state?.data);
}
String generateRandomString(int len) {
var r = Random();
return String.fromCharCodes(List.generate(len, (index) => r.nextInt(33) + 89));
}
#override
Widget build(BuildContext context) {
print('Rebuild');
final data = ref.watch(helloWorldProvider.notifier).state;
final dataText = data?.data ?? 'No text';
print(dataText);
return MaterialApp(
title: 'Google Docs Clone',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: Center(
child: Column(children: [
Text(dataText)
]
)
),
floatingActionButton: FloatingActionButton(
onPressed: _change,
tooltip: 'Change',
child: const Icon(Icons.add),
),
));
}
}
I don't want to use other pattern as Provider, Bloc, StateNotifierProvider, ChangeNotifierProvider... I only want to run StateProvider successfully. I have refered to many articles and stackoverflows answer but I did't found any useful helps to my case.
final data = ref.watch(helloWorldProvider.notifier).state;
is watching the notifier, which rarely changes. You want to watch the state change, as in:
final data = ref.watch(helloWorldProvider);
Fixed, Tested your code.
I recommend this article Flutter Riverpod 2.0: The Ultimate Guide to Advanced Riverpod 😀
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'dart:math';
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class Data {
final String data;
Data({required this.data});
}
final helloWorldProvider = StateProvider<Data?>((ref) => Data(data: 'No data'));
class MyApp extends ConsumerStatefulWidget {
const MyApp({super.key});
#override
ConsumerState<MyApp> createState() => _MyAppState();
}
class _MyAppState extends ConsumerState<MyApp> {
#override
void initState() {
// TODO: implement initState4
print("Init state");
super.initState();
// getData();
}
// getData() async {
// // http.Response response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/todos/1'));
// // final title = jsonDecode(response.body)["title"];;
// // ref.read(helloWorldProvider.notifier).update((state) => title);
// SharedPreferences prefs = await SharedPreferences.getInstance();
// prefs.setString('valueTemp', 'newValue');
// String? valueTemp = prefs.getString('valueTemp');
// String value = valueTemp ?? '';
// Data data = Data(data: value);
// ref.read(helloWorldProvider.notifier).update((state) => data);
// print("Đã thực hiện xong");
// }
void _change() {
print("change");
final rawString = generateRandomString(5);
Data data = Data(data: rawString);
ref.read(helloWorldProvider.notifier).update((state) => data);
print(ref.read(helloWorldProvider.notifier).state?.data);
}
String generateRandomString(int len) {
var r = Random();
return String.fromCharCodes(
List.generate(len, (index) => r.nextInt(33) + 89));
}
#override
Widget build(BuildContext context) {
print('Rebuild');
final data = ref.watch(helloWorldProvider)?.data;
final dataText = data ?? 'No text';
print(dataText);
return MaterialApp(
title: 'Google Docs Clone',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: Center(
child: Column(children: [Text(dataText)]),
),
floatingActionButton: FloatingActionButton(
onPressed: _change,
tooltip: 'Change',
child: const Icon(Icons.add),
),
),
);
}
}
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'dart:developer' as devtools;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: BlocProvider(
create: (context) => PersonsBloc(),
child: const MyHomePage(),
),
);
}
}
#immutable
abstract class LoadAction {
const LoadAction();
}
#immutable
class LoadPersonsAction implements LoadAction {
final PersonsUrl url;
const LoadPersonsAction({required this.url}) : super();
}
enum PersonsUrl {
persons1,
persons2,
}
extension Subscript<T> on Iterable<T> {
T? operator [](int index) => length > index ? elementAt(index) : null;
}
extension UrlString on PersonsUrl {
String get getUrl {
switch (this) {
case PersonsUrl.persons1:
devtools.log("Getting person1 url");
return "http://127.0.0.1:5500/app_2/api/persons1.json";
case PersonsUrl.persons2:
devtools.log("Getting person2 url");
return "http://127.0.0.1:5500/app_2/api/persons2.json";
}
}
}
#immutable
class Person {
final String name;
final int age;
const Person({required this.name, required this.age});
Person.fromJson(Map<String, dynamic> json)
: name = json['name'] as String,
age = json['age'] as int;
}
Future<Iterable<Person>> getPersons(String url) => HttpClient()
.getUrl(Uri.parse(url))
.then((req) => req.close())
.then((resp) => resp.transform(utf8.decoder).join())
.then((str) => json.decode(str) as List<dynamic>)
.then((value) => value.map((e) => Person.fromJson(e)));
#immutable
class FetchResult {
final Iterable<Person> persons;
final bool isRetrievedFromCache;
const FetchResult(
{required this.persons, required this.isRetrievedFromCache});
#override
String toString() =>
'FetchResult (isRetrievedFromCache = $isRetrievedFromCache, persons = $persons';
}
class PersonsBloc extends Bloc<LoadAction, FetchResult?> {
final Map<PersonsUrl, Iterable<Person>> _cache = {};
PersonsBloc() : super(null) {
on<LoadPersonsAction>((event, emit) async {
final url = event.url;
devtools.log("In bloc :$url");
if (_cache.containsKey(url)) {
devtools.log("Present in cache");
final cachedPersons = _cache[url]!;
final result = FetchResult(
persons: cachedPersons,
isRetrievedFromCache: true,
);
emit(result);
} else {
devtools.log("Not present in cache");
final persons = await getPersons(url.getUrl);
if (persons.isNotEmpty) {
print("Persons is there");
} else {
print("Persons is not there");
}
_cache[url] = persons;
final result =
FetchResult(persons: persons, isRetrievedFromCache: false);
emit(result);
}
});
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({
Key? key,
}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BLoC App 2'),
),
body: Column(
children: [
Row(
children: [
TextButton(
onPressed: () {
devtools.log("Clicked to get person1");
context.read<PersonsBloc>().add(
const LoadPersonsAction(url: PersonsUrl.persons1));
},
child: const Text('Load Json #1')),
TextButton(
onPressed: () {
devtools.log("Clicked to get person2");
context.read<PersonsBloc>().add(
const LoadPersonsAction(url: PersonsUrl.persons2));
},
child: const Text('Load Json #2')),
],
),
BlocBuilder<PersonsBloc, FetchResult?>(
buildWhen: ((previous, current) {
return previous?.persons != current?.persons;
}),
builder: ((context, state) {
final persons = state?.persons;
if (persons == null) {
return const SizedBox();
}
return ListView.builder(
itemCount: persons.length,
itemBuilder: ((context, index) {
devtools.log('rendering list tiles');
final person = persons[index]!;
return ListTile(
leading: Text(person.age.toString()),
title: Text(person.name),
);
}));
}),
)
],
));
}
}
I am learning BLoC State Management from Vandad Nahavandipoor's State Management Playlist, when I click on the Load Json #1 button, it goes until the getPersons() function is called, but then doesn't fetch any data to return. Instead, it shows me some errors with no description whatsoever.
ERROR:
enter image description here
Here is the error I get after I Hot Restart:
E/flutter ( 2894): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: SocketException: Connection timed out (OS Error:
Connection timed out, errno = 110), address = 192.168.0.1, port =
51180
I am new to Flutter, and bloc too. I got the idea, how bloc works. But When I create a simple app as the first step of my note app. The bloc doesn't give the data. This simple app has two screens. list screen and Notedetailscreen. Button in NoteDetailScreen tapped, data does not print to the text widget.
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:note_demo_bloc/bloc/note_bloc.dart';
import 'package:note_demo_bloc/list_screen.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocProvider<NoteBloc>(
create: (context) => NoteBloc(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ListScreen(),
),
);
}
}
note_bloc.dart
import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:meta/meta.dart';
part 'note_event.dart';
part 'note_state.dart';
class NoteBloc extends Bloc<NoteblocEvent, NoteblocState> {
NoteBloc() : super(NoteblocInitial());
#override
Stream<NoteblocState> mapEventToState(
NoteblocEvent event,
) async* {
if (event == NoteSaveEvent) {
yield NoteSaveState(state);
}
}
}
part of 'note_bloc.dart';
#immutable
abstract class NoteblocEvent {}
class NoteSaveEvent extends NoteblocEvent {
NoteSaveEvent(this.text);
final text;
}
note_state.dart
part of 'note_bloc.dart';
#immutable
abstract class NoteblocState {}
class NoteblocInitial extends NoteblocState {}
class NoteSaveState extends NoteblocState {
NoteSaveState(this.text);
final text;
}
list_screen.dart
import 'package:flutter/material.dart';
import 'package:note_demo_bloc/note_detail_screen.dart';
class ListScreen extends StatefulWidget {
const ListScreen({Key? key}) : super(key: key);
#override
_ListScreenState createState() => _ListScreenState();
}
class _ListScreenState extends State<ListScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Text('hi'),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => NoteDetailScreen(),
),
);
},
),
);
}
}
Note_detailscreen.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:note_demo_bloc/bloc/note_bloc.dart';
class NoteDetailScreen extends StatefulWidget {
const NoteDetailScreen({Key? key}) : super(key: key);
#override
_NoteDetailScreenState createState() => _NoteDetailScreenState();
}
class _NoteDetailScreenState extends State<NoteDetailScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
ElevatedButton(
onPressed: () {
BlocProvider.of<NoteBloc>(context).add(NoteSaveEvent('hi'));
},
child: Text('click'),
),
BlocBuilder<NoteBloc, NoteblocState>(
builder: (context, state) {
return Text(state.toString());
},
)
],
),
);
}
}
Your bloc, state, and event looks fine. When you push screen you might need to use BlocProvider again. So try this:
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:note_demo_bloc/bloc/note_bloc.dart';
import 'package:note_demo_bloc/list_screen.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
NoteBloc _noteBloc = NoteBloc();
#override
Widget build(BuildContext context) {
return BlocProvider<NoteBloc>(
create: (context) => _noteBloc(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ListScreen(),
),
);
}
}
list_screen.dart
import 'package:flutter/material.dart';
import 'package:note_demo_bloc/note_detail_screen.dart';
class ListScreen extends StatefulWidget {
const ListScreen({Key? key}) : super(key: key);
#override
_ListScreenState createState() => _ListScreenState();
}
class _ListScreenState extends State<ListScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Text('hi'),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => BlocProvider.value(value: BlocProvider.of<NoteBloc>(context), child: NoteDetailScreen()),
),
);
},
),
);
}
}
Note_detailscreen.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:note_demo_bloc/bloc/note_bloc.dart';
class NoteDetailScreen extends StatefulWidget {
const NoteDetailScreen({Key? key}) : super(key: key);
#override
_NoteDetailScreenState createState() => _NoteDetailScreenState();
}
class _NoteDetailScreenState extends State<NoteDetailScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
ElevatedButton(
onPressed: () {
BlocProvider.of<NoteBloc>(context).add(NoteSaveEvent('hi'));
},
child: Text('click'),
),
BlocBuilder<NoteBloc, NoteblocState>(
bloc: BlocProvider.of<NoteBloc>(context),
builder: (context, state) {
return Text(state.toString());
},
)
],
),
);
}
}
So, this is not an answer of your question but consider that as alternative (for future users of SO).
As state management is a free choice, and everyone could manage that as it’s “modus operandi“ this helper class “home made” could be a good choice.
import 'dart:async';
import 'dart:core';
class Method {
Method(this.name, this.params);
final String name;
final Map<String, Object> params;
}
class _Controller {
_Controller._();
static final Map<String, _Controller> _this = new Map<String, _Controller>();
final Map<String, Function(Method)> _funcs = new Map<String, Function(Method)>();
factory _Controller(String identifier) => _this.putIfAbsent(identifier, () => _Controller._());
Future<void> activateListener(String listenerId, Function(Method) function) async {
if (function != null)
_funcs.containsKey(listenerId) ? _funcs[listenerId] = function : _funcs.putIfAbsent(listenerId, () => function);
}
Future<void> deactivateListener(String listenerId) async =>
_funcs.removeWhere((String key, Function(Method) func) => key == listenerId);
Future<void> removeListener(String identifier) async =>
_this.removeWhere((String key, _Controller mClass) => key == identifier);
Future<void> callMethod(String methodName, {Map<String, Object> params}) async =>
Future.forEach(_funcs.values.where((v) => v != null), (func) async => func.call(Method(methodName, params)));
}
mixin MethodListener on Object {
_Controller _getController(String identifier) => _Controller(identifier ?? this.runtimeType.toString());
Future<void> activateListener({String identifier, List<String> identifiers}) async {
if (identifiers != null && identifiers.length > 0)
identifiers.forEach(
(String currentId) => _getController(currentId).activateListener(this.hashCode.toString(), onMethodListener));
else
_getController(identifier).activateListener(this.hashCode.toString(), onMethodListener);
}
Future<void> deactivateListener({String identifier, List<String> identifiers}) async {
if (identifiers != null && identifiers.length > 0)
identifiers.forEach((String currentId) => _getController(currentId).deactivateListener(this.hashCode.toString()));
else
_getController(identifier).deactivateListener(this.hashCode.toString());
}
Future<void> removeListener({String identifier}) async => _getController(identifier).removeListener(identifier);
void onMethodListener(Method method) async => null;
Future<void> callMethodOn(String identifier, String methodName, {Map<String, Object> params}) async =>
_getController(identifier).callMethod(methodName, params: params);
}
class MethodManager with MethodListener {
MethodManager._();
static MethodManager _this;
factory MethodManager() {
if (_this == null) _this = MethodManager._();
return _this;
}
Future<void> callMethodOnWidgets(List<String> identifiers, String methodName, {Map<String, Object> params}) async =>
identifiers.forEach((String currentId) => callMethodOn(currentId, methodName, params: params));
#override
Future<void> callMethodOn(String identifier, String methodName, {Map<String, Object> params}) async =>
super.callMethodOn(identifier, methodName, params: params);
}
then you can implements classes with “with MethodListener” as follows:
import 'package:flutter/material.dart';
import 'package:yourpackagehere/utils/XMethods.dart';
class Test extends StatefulWidget {
static const String NAME = "Test";
#override
createState() => _TestState();
}
class _TestState extends State<Test> with MethodListener {
String _ciao;
#override
void initState() {
super.initState();
this.activateListener(identifier: Test.NAME);
}
#override
void dispose() {
this.deactivateListener(identifier: Test.NAME);
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(child: Text(_ciao));
}
#override
void onMethodListener(Method method) {
switch (method.name) {
case "say_hello":
if (mounted) {
setState(() {
_ciao = method.params["my_string"];
});
}
break;
}
}
}
Usage:
From everywhere (from widgets or classes):
MethodManager().callMethodOn(Test.NAME, "say_hello", params: {"my_string": "SIAMO CAMPIONI DI EUROPA!!!"});
i m in a situation where i have to implement country city state dropdown list somehow i manage things with normal flutter dropdown button and that's work ,but the issue is i can't search data in that dropdown button so user have to scroll and find there country or city which is a very bad user experience , so i found this package https://pub.dev/packages/searchable_dropdown whic is working but i m not sure how to implement that search in my code here is my code
data from fututre
import 'package:flutter/material.dart';
// import 'package:foodfromforeign1/models/country.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:flutter_typeahead/flutter_typeahead.dart';
void main() => runApp( MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.red,
),
home: MyHomePage(title: 'Users'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final String url = "http://10.0.2.2/fff/api/allcountries/";
List data = List(); //line
Future<String> getSWData() async {
var res = await http .get(Uri.encodeFull(url), headers: {"Accept": "application/json"});
var resBody = json.decode(res.body);
setState(() {
data = resBody.;
});
return "Sucess";
}
#override
void initState() {
this.getSWData();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body:Container(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 30),
child:Column(
children: <Widget>[
TypeAheadField<data>(
onSuggestionSelected: (data) => print('selected: ${data.name} ${data.id}'),
suggestionsCallback: (s) => data.where((c) => c.name.toLowerCase().contains(s.toLowerCase())),
itemBuilder: (ctx, data) => Text(data.name, textScaleFactor: 2,),
)
],
),
),
);
}
}
Another option here aside from using plugins is with the use of the Autocomplete widget. This should inflate an autocomplete list over other widgets. If you're using a List<Object> from an API response, you can map the keywords that you need to filter from to a List<String> to be used in the Autocomplete widget. The index can be used as a reference on the List<Object> to fetch the Object.
var fruits = ['Apple', 'Banana', 'Mango', 'Orange'];
_autoCompleteTextField() {
return Autocomplete(
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') {
return const Iterable<String>.empty();
}
return fruits.where((String option) {
return option
.toLowerCase()
.contains(textEditingValue.text.toLowerCase());
});
},
onSelected: (String selection) {
debugPrint('You just selected $selection');
},
);
}
I am new to flutter and I am trying to perform signOut() function on sidenavbar. I got stuck in a code segment. After a couple of attempts, I got errors like:
type Future is not a subtype of type Widget
I have the following code. How should I call _logOutUser() function in my case 0: statement?
Any help would be highly appreciated
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
class Homepage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
routes: {
'/login': (context) => Login(),
},
title: 'NavigationDrawer Demo',
theme: new ThemeData(
primarySwatch: Colors.red,
),
home: new HomePage(),
);
}
}
class DrawerItem {
String title;
IconData icon;
DrawerItem(this.title, this.icon);
}
class HomePage extends StatefulWidget {
HomePage({
this.auth,
this.onSignedOut,
});
final AuthImplementation auth;
final VoidCallback onSignedOut;
final drawerItems = [
new DrawerItem("Logout", Icons.exit_to_app),
];
#override
State<StatefulWidget> createState() {
return new HomePageState();
}
}
class HomePageState extends State<HomePage> {
void _logOutUser() async {
try {
await widget.auth.signOut();
widget.onSignedOut();
} catch (e) {
print(e.toString());
}
}
int _selectedDrawerIndex = 0;
_getDrawerItemWidget(int pos) {
switch (pos) {
case 0:
return HomePageState()._logOutUser();
default:
return new Text("Error");
}
}
_onSelectItem(int index) {
setState(() => _selectedDrawerIndex = index);
Navigator.of(context).pop();
}
#override
Widget build(BuildContext context) {
var drawerOptions = <Widget>[];
for (var i = 0; i < widget.drawerItems.length; i++) {
var d = widget.drawerItems[i];
drawerOptions.add(
new ListTile(
leading: new Icon(d.icon),
title: new Text(d.title),
selected: i == _selectedDrawerIndex,
onTap: () => _onSelectItem(i),
)
);
}
}
}
I'm a little confused by your question, but if I'm not mistaken why don't you just do this:
switch (pos) {
case 0:
HomePageState()._logOutUser();
return Text("Logged Out");
// or if you don't want to show anything you could just return a blank Container, or
// if you wanted to navigate to login screen just use Navigator.push() and return the Container
default:
return new Text("Error");
}
The reason you are getting the error type Future<dynamic> is not a subtype of Widget is because your Function _logOutUser() isn't returning a Widget. Comment below if I didn't answer your question.