I hope this meet all flutter developers well.
i'm working on an app and there are several issues i've been going through. here is my question.
i want to switch between selectedLocations and it will bring out forms related to the location out for users to fill.
here are the locations below in pictures and the codes follows.
void switchSelectedCountry(selection) {
events = selection;
scoops = selection;
setState(() {
_selectedLocation = selection;
});
}
formField: FixDropdownButtonFormField(
value: _selectedLocation,
hint: Text('Select'),
items: <String>['Scoops', 'Events',].map((String value) {
return new FixDropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (newValue) {
setState(() {
_selectedLocation = newValue;
});
},
),
),
you can check which value has been selected in drop down and based on that you can show specific form,
for example,
if(dropdownValue == 'events') Column(
children: <Widget>[
TextFormField(
controller: yearController,
decoration: InputDecoration(
labelText: AppLocalizations.of(context).translate(
'year'),
hintStyle: TextStyle(fontSize: 10),
filled: true,
),
keyboardType: TextInputType.number,
),
],
),
if(dropdownValue == 'Scoops') Sizebox(RETURN YOU WIDGET)
Related
I am trying to implement a search function in my app for filtering between many entries in a list of map.
The data structure that I have is:
[{Entry: Accident , Definition: An unexpected event or circumstance without deliberate intent.}, {Entry: Accident Insurance , Definition: Insurance for unforeseen bodily injury.}, {Entry: Accident Only , Definition: An insurance contract that provides coverage, singly or in combination, for death, dismemberment, disability, or hospital and medical care caused by or necessitated as a result of accident or specified kinds of accident.}, {Entry: Accident Only or AD&D , Definition: Policies providing coverage, singly or in combination, for death, dismemberment, disability, or hospital and medical care caused by or necessitated as a result of accident or specified kinds of accidents. Types of coverage include student accident, sports accident, travel accident, blanket accident, specific accident or accidental death and dismemberment (ad&d).} ... etc, etc. ]
These are the contents of the .json file:
[
{
"Entry": "Accident ",
"Definition": "An unexpected event or circumstance without deliberate intent."
},
{
"Entry": "Accident Insurance ",
"Definition": "Insurance for unforeseen bodily injury."
},
[... and looooots of many other "Entry", "Definition" pairs like these]
{
"Entry": "Written Premium ",
"Definition": "The contractually determined amount charged by the reporting entity to the policyholder for the effective period of the contract based on the expectation of risk, policy benefits, and expenses associated with the coverage provided by the terms of the insurance contract."
}
]
Each map entry creates one button with an associated definition.
The user is queried for a search query to get only the button(s) that satisfy the query result.
I include the .dart file that I am trying to implement:
import 'package:flutter/material.dart';
import 'listentries.dart';
import 'destination.dart';
import 'dart:convert';
// ignore: must_be_immutable
class searchScreen extends StatefulWidget {
final String searchTerm;
searchScreen({this.searchTerm});
#override
_SearchScreenState createState() => new _SearchScreenState();
}
class _SearchScreenState extends State<searchScreen> {
#override
Widget build(BuildContext context) {
final widgetElements = new ListEntries(); // From listentries.dart
var searchedItems =
widgetElements; // Copy from widgetElements filter out from here
var query;
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
title: Text(
"Search your term",
style: TextStyle(fontSize: 20),
),
),
body: Container(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
onChanged: (query) {
//search is done here
// filterSearchResults(query);
},
decoration: InputDecoration(
labelText: 'Search',
hintText: 'Search your term',
suffixIcon: Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(25.0),
),
),
),
),
),
Expanded(
child: FutureBuilder(
future: DefaultAssetBundle.of(context)
.loadString('assets/data.json'),
builder: (context, snapshot) {
var entries = json.decode(snapshot.data.toString());
final item = entries.where((e) => e['Entry'] == 'Accident'); //Accident will be changed with query
print(item);
print(entries);
return ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
var entrada = entries[index];
//print(entrada);
return Container(
margin: EdgeInsets.symmetric(vertical: 2.0),
color: Colors.transparent,
width: MediaQuery.of(context).size.width,
height: 60,
child: RaisedButton(
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Destination(
entry: entrada['Entry'],
definition: entrada['Definition'],
),
),
);
},
color: Colors.blue[900],
child: Text(
entrada['Entry'],
style: TextStyle(
color: Colors.white,
fontFamily: 'Raleway',
fontSize: 18.0,
),
),
),
);
},
itemCount: entries == null ? 0 : entries.length,
);
},
),
//child: searchedItems,
),
],
),
),
);
}
}
The issue that I am seeing is that the filtered result (item) is empty and it should contain the entry related to "Accident".
Could you give a hand for the implementation of this search functionality?
Thanks in advance
add .toList() to create new list
final item = entries.where((e) => e['Entry'] == 'Accident').toList();
Here is a stripped down code sample describing how to filter the items:
final List<Map<String, String>> items = [
{'Entry': 'Accident', 'Definition': 'Accident description.'},
{'Entry': 'Accident Insurance', 'Definition': 'Insurance description.'},
];
void main() {
final results = items.where((item) => item['Entry'] == 'Accident');
print(results);
// Iterable<Map<String, String>> ({Entry: Accident, Definition: An unexpected event or circumstance without deliberate intent.})
final result = results.first;
print(result);
// Map<String, String> {Entry: Accident, Definition: An unexpected event or circumstance without deliberate intent.}
}
Note that where returns an Iterable. You can use toList() to get a List of Maps.
Here is a Flutter sample application closer to what you did before:
import 'dart:convert';
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: MyWidget()));
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future:
DefaultAssetBundle.of(context).loadString('assets/entries.json'),
builder: (context, snapshot) {
final items = json.decode(snapshot.data.toString());
final result =
items.where((item) => item['Entry'] == 'Accident').first;
return Column(
children: [
Text('Accident Definition:'),
Text(result['Definition']),
],
);
},
),
);
}
}
The JSON File I used is here:
[
{
"Entry": "Accident",
"Definition": "Accident description."
},
{
"Entry": "Accident Insurance",
"Definition": "Insurance description."
}
]
I created a widget which is sending data via an API in json format, built with controllers such as ;
final quantNumberController = TextEditingController();
And i am getting value from controller ;
String quant = quantNumberController.text;
And i store the data in json format such as ;
var data = {'quant': quant}
My current text widget container structure is like ;
Container(
width: 280,
padding: EdgeInsets.all(10.0),
child: TextField(
controller: quantNumberController,
autocorrect: true,
decoration: InputDecoration(hintText: 'Enter location'),
)
),
I would like to get this data within radio button structure. Is it possible to get the data with controller like before i did, or how should i get the data to my result json file ?
I tried like this ;
Container(
margin: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Column(
children: <Widget>[
Text('Location'),
ListTile(
title: const Text('First value'),
leading: Radio(
value: Cap.Cap33,
groupValue: _capp,
onChanged: (Capp value) {
setState(() {
_capp = value;
capp = 'Cap33';
});
},
),
),
ListTile(
title: const Text('Second value'),
leading: Radio(
value: Capp.Cap22,
groupValue: _capp,
onChanged: (Capp value) {
setState(() {
_capp = value;
capp = 'Cap22';
});
},
),
),
ListTile(
title: const Text('Third value'),
leading: Radio(
value: Capp.Cap44,
groupValue: _capp,
onChanged: (Capp value) {
setState(() {
_capp = value;
capp = 'Cap44';
});
},
),
),
],
) ,
),
Thanks.
you can define a function that takes a controller
widget myRadioButton(TextEditingController quantNumberController ){
return Radio(
value:quantNumberController.text
groupValue: _capp,
onChanged: (Capp value) {
setState(() {
_capp = value;
capp = 'Cap33';
});}
for using
Container(
child:myRadioButton (quantNumberController:quantNumberController)
)
You can use a variable like "Location Value"
Syntax -
late String LocationValue = '';
before #override
Widget build(BuildContext context)
And then assign LocationValue on radio button on change attribute
onChanged: ((value) {
LocationValue = 'cap33';
setState(() {
_value = value!;
});
}),
I am using Flutter table calendar plugin to make a calendar. In order to put events into the calendar, I have to add data to _events map. I want to get the data from Firestore document, and put the data into _events map. However, I don't know how to do it. I search everywhere but I can't get an answer.
This is my code
class _MemberEventsState extends State<MemberEvents>
with TickerProviderStateMixin {
Map<DateTime, List> _events;
List _selectedEvents;
AnimationController _animationController;
CalendarController _calendarController;
List<String> list = List();
#override
void initState() {
super.initState();
final _selectedDay = DateTime.now();
Firestore.instance
.collection('events')
.document('2019-07-30')
.get()
.then((DocumentSnapshot ds) {
list = List.from(ds['title']);
});
_events = {DateTime.parse("2019-08-01"): list};
_selectedEvents = _events[_selectedDay] ?? [];
_calendarController = CalendarController();
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 400),
);
_animationController.forward();
}
#override
void dispose() {
_animationController.dispose();
_calendarController.dispose();
super.dispose();
}
void _onDaySelected(DateTime day, List events) {
print('CALLBACK: _onDaySelected');
setState(() {
_selectedEvents = events;
});
}
void _onVisibleDaysChanged(
DateTime first, DateTime last, CalendarFormat format) {
print('CALLBACK: _onVisibleDaysChanged');
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
_buildTableCalendar(),
const SizedBox(height: 8.0),
const SizedBox(height: 8.0),
Expanded(child: _buildEventList()),
],
),
);
}
Widget _buildTableCalendar() {
return TableCalendar(
calendarController: _calendarController,
events: _events,
startingDayOfWeek: StartingDayOfWeek.sunday,
calendarStyle: CalendarStyle(
selectedColor: Colors.deepOrange[400],
todayColor: Colors.blueAccent[200],
markersColor: Colors.brown[700],
outsideDaysVisible: false,
),
headerStyle: HeaderStyle(
formatButtonTextStyle:
TextStyle().copyWith(color: Colors.white, fontSize: 15.0),
formatButtonDecoration: BoxDecoration(
color: Colors.deepOrange[400],
borderRadius: BorderRadius.circular(16.0),
),
),
onDaySelected: _onDaySelected,
onVisibleDaysChanged: _onVisibleDaysChanged,
);
}
Widget _buildEventList() {
return ListView(
children: _selectedEvents
.map((event) => Container(
decoration: BoxDecoration(
border: Border.all(width: 0.8),
borderRadius: BorderRadius.circular(12.0),
),
margin:
const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
child: ListTile(
title: Text(event.toString()),
),
))
.toList(),
);
}
}
So in the first step to achieve my goal, I made a document named 2019-07-30, then I made an array in it named title. Then I tried to get the values in the array to a List named list. However, list returned null.
I don't know where I went wrong.
I am new to Flutter, so the question might seem stupid.
Also, I am new to stackoverflow, so if I did any steps wrong on describing the question, please tell me so I can fix it.
Is it possible to write a unit test that verifies that the maxLines property of a TextFormField is set correctly. I can not find a way to access the property:
i create a TextFormField
final field = TextFormField(
initialValue: "hello",
key: Key('textformfield'),
maxLines: 2,
);
then in the test i get access to the form field with tester.widget
final formfield =
await tester.widget<TextFormField>(find.byKey(Key('textformfield')));
but since the maxLines property is passed to the Builder which returns a Textfield, how can i get access to the textfield.
Or is there an completely other ways to verify this?
I don't know if this is a good solution but as i set the value of my TextFormField i can find the EditableText widget directly.
of this widget i can find test the property maxLines.
final EditableText formfield =
tester.widget<EditableText>(find.text('testvalue'));
expect(formfield.maxLines, 2);
The reason you can't see properties such as maxLines or maxLength is because they belong to the TextField class.
Take a look at the documentation of the TextFormField constructor in the source file:
/// Creates a [FormField] that contains a [TextField].
///
/// When a [controller] is specified, [initialValue] must be null (the
/// default). If [controller] is null, then a [TextEditingController]
/// will be constructed automatically and its `text` will be initialized
/// to [initialValue] or the empty string.
///
/// For documentation about the various parameters, see the [TextField] class
/// and [new TextField], the constructor.
Unfortunately you can't retrieve the TextField object from a TextFormField, you'll have to find the TextField object through a finder instead.
Let's assume you have a form with 2 fields - first name and last name. What you need to do is find all widgets of type TextField, add them to a list and then you can loop through each element of the list and run your test. Here's an example:
testWidgets('Form fields have the correct maximum length and number of lines',
(WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: Form(
child: Column(
children: <Widget>[
TextFormField(
key: Key('first_name'),
decoration: InputDecoration(hintText: 'First name'),
maxLines: 1,
maxLength: 50,
obscureText: true,
),
TextFormField(
key: Key('last_name'),
decoration: InputDecoration(hintText: 'Last name'),
maxLines: 1,
maxLength: 25,
),
],
),
),
),
));
List<TextField> formFields = List<TextField>();
find.byType(TextField).evaluate().toList().forEach((element) {
formFields.add(element.widget);
});
formFields.forEach((element) {
expect(element.maxLines, 1);
switch (element.decoration.hintText) {
case 'First name':
expect(element.maxLength, 50);
break;
case 'Last name':
expect(element.maxLength, 25);
break;
}
});
});
If you only one field, you could do this instead:
TextField textField = find.byType(TextField).evaluate().first.widget as TextField;
expect(textField.maxLines, 1);
expect(textField.maxLength, 50);
You can test it with an Integration test. The logic would be to type more text into the TextFormField that the one it's expected.
So we can verify the TextFormField is only allowing 2 character, as follow.
e.g. component:
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: SingleChildScrollView(
child: MyLoginPage(title: 'Flutter Demo Home Page'),
),
),
);
}
}
class MyLoginPage extends StatefulWidget {
MyLoginPage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyLoginPageState createState() => _MyLoginPageState();
}
class _MyLoginPageState extends State<MyLoginPage> {
String _email;
String _password;
TextStyle style = TextStyle(fontSize: 25.0);
#override
Widget build(BuildContext context) {
final emailField = TextField(
key: Key('textformfield'),
obscureText: false,
maxLength: 2,
style: style,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
prefixIcon: Icon(FontAwesomeIcons.solidEnvelope),
hintText: "Email",
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red[300], width: 32.0),
borderRadius: BorderRadius.circular(97.0))),
onChanged: (value) {
setState(() {
_email = value;
});
},
);
final passwordField = TextField(
obscureText: true,
style: style,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
prefixIcon: Icon(FontAwesomeIcons.key),
hintText: "Password",
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red[300], width: 32.0),
borderRadius: BorderRadius.circular(25.0))),
onChanged: (value) {
setState(() {
_password = value;
});
},
);
return Center(
child: Column(
children: <Widget>[
Container(
color: Colors.yellow[300],
height: 300.0,
),
emailField,
passwordField,
],
),
);
}
}
The test:
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_textfields_up/main.dart';
void main() {
testWidgets('Email should be only 2 characters', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(MyApp());
var txtForm = find.byKey(Key('textformfield'));
await tester.enterText(txtForm, '123');
expect(find.text('123'), findsNothing); // 3 characters shouldn't be allowed
expect(find.text('12'), findsOneWidget); // 2 character are valid.
});
}
Please observe I'm sending 3 character, and the TextFormField should only allow 2.
Hope this help.
My function types() should return a unique list of ExpansionTiles.
In dart combining .toSet().toList() is really efficient in removing duplicates in List and I am trying to do the same here but I'm still rendering duplicates.
In the picture I don't want NISSAN to appear twice, just once as one category.
types() {
return snapshot.data.documents.map((doc) {
if(doc['car']['registryNumber'] != null && doc['car']['category'] ==
'car') {
return ExpansionTile(
title: new Row(
children: <Widget>[
new Text(
doc['car']['type'].split(' ')[0],
style: new TextStyle(
fontSize: 15.0
),
)
],
),
children: <Widget>[
],
);
} else {
return new Text('');
}
}).toSet().toList();
}
Don't forget to add a unique key: to ExpansionTile to avoid any duplicate issues!