flutter radiovalue not changing - flutter

I'm trying to get a very simple set of radiobuttons up, which is why it's so frustrating that they aren't working. I've tried setting this up in a similar class, and it's worked. I know for a fact that setstate is being called, but for some reason it's not updating the individual radio button. Which makes me think that this is some weird issue related to state.
Anyways, all help would be appreciated. My main class is the second part of the code below.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../bloc/thembloc.dart';
import './components/textfield.dart';
class SignUp extends StatefulWidget {
#override
_SignUpState createState() => _SignUpState();
}
class _SignUpState extends State<SignUp> {
/*
ui for signup
includes multiple textfields.
includes all of the information that we'll need
to collect for an user to register an account.
todo: wrap everything in a form, encrypt it and send it to a private server.
*/
#override
Widget build(BuildContext context) {
double _height = MediaQuery.of(context).size.height;
double _width = MediaQuery.of(context).size.width;
final double _margin = 16.0;
final double _promptWidth = _width - 32.0;
final double _promptHeight = _height - 32.0;
final double _textFieldWidth = _promptWidth - 32.0;
int subscriberValue;
void switchSubscriber(int value) {
setState(() {
subscriberValue = value;
});
}
return BlocBuilder(
bloc: BlocProvider.of<ThemeBloc>(context),
builder: (context, ThemeState state) {
return Scaffold(
resizeToAvoidBottomInset: false,
resizeToAvoidBottomPadding: false,
appBar: AppBar(
centerTitle: true,
title: Text(
"smartmoney",
style: BlocProvider.of<ThemeBloc>(context).currentState.themedata.primaryTextTheme.display2,
),
// appbar
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(8.0),
bottomRight: Radius.circular(8.0))),
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: BlocProvider.of<ThemeBloc>(context).currentState.themedata.buttonColor,
),
onPressed: () {
print("going back");
},
),
backgroundColor: BlocProvider.of<ThemeBloc>(context).currentState.themedata.canvasColor,
),
body: Container(
height: _height,
width: _width,
color: BlocProvider.of<ThemeBloc>(context).currentState.themedata.backgroundColor,
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: _margin),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(8.0)),
color: BlocProvider.of<ThemeBloc>(context).currentState.themedata.canvasColor,
boxShadow: [
BoxShadow(
spreadRadius: 0.0,
color: Colors.black38,
blurRadius: 6.0,
offset: Offset(0.0, 3.0)),
]),
width: _promptWidth,
height: _promptHeight - 48 - _margin,
child: Column(
children: <Widget>[
Text("Let's get started",
style: BlocProvider.of<ThemeBloc>(context).currentState.themedata.primaryTextTheme.display2,
),
Text("Enter your information to create an account",
style: BlocProvider.of<ThemeBloc>(context).currentState.themedata.primaryTextTheme.subtitle,
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: StyledTextField(
textFieldWidth: _textFieldWidth,
helperText: "First name",
),
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: StyledTextField(
textFieldWidth: _textFieldWidth,
helperText: "Last name",
),
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: StyledTextField(
textFieldWidth: _textFieldWidth,
helperText: "Email",
),
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: StyledTextField(
textFieldWidth: _textFieldWidth,
helperText: "Password",
),
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: StyledTextField(
textFieldWidth: _textFieldWidth,
helperText: "Phone number",
),
),
Text("Subscriber type",
style: BlocProvider.of<ThemeBloc>(context).currentState.themedata.primaryTextTheme.display1,
),
Radio(
groupValue: subscriberValue,
value: 0,
onChanged: (int value) => switchSubscriber(value),
),
Radio(
groupValue: subscriberValue,
value: 1,
onChanged: (int value) => switchSubscriber(value),
)
],
),
),
)
],
),
),
);
});
}
}
import 'package:flutter/material.dart';
import './bloc/thembloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'ui/signin.dart';
import 'ui/signup.dart';
import 'ui/onboarding.dart';
import './ui/testing/whatthefuck.dart';
void main() {
runApp(
MaterialApp(
home: SmartMoney(),
)
// SmartMoney()
);
}
class SmartMoney extends StatefulWidget {
#override
_SmartMoneyState createState() => _SmartMoneyState();
}
class _SmartMoneyState extends State<SmartMoney> {
final _themeBloc = ThemeBloc();
#override
Widget build(BuildContext context) {
return BlocProvider(
bloc: _themeBloc,
child: SignUp(),
);
}
}

The problem is because you defined your variable subscriberValue inside your build method. You're using setState calls that recall build method and in every recall of build you're losing the value of subscriberValue. I advise you to always use variables that will control the state of your widget as class members.
class _SignUpState extends State<SignUp> {
// HAS TO BE CLASS MEMBER AND IT'S GOOD AN INITIAL VALUE TOO..
int subscriberValue =1; // asuming that 1 is default radio button option
#override
Widget build(BuildContext context) {
//... some codes ...
//int subscriberValue; REMOVE THIS LINE. YOU'RE LOSING THE VALUE IN EVERY setState call
//You can define this method outside from build too.
void switchSubscriber(int value) {
setState(() {
subscriberValue = value;
});
}
}

Related

flutter problem:how to reflect changes in another page when i search from another page in flutter

This is my "TabTop" search ui code.
In this search page I have a search function which is stored data in
"eventsSearchLists" and I have a one more variable "eventsListData" In this variable I have previus data when i search anything then data will changed in variable but its not reflecting another page.
When search data does come in "eventsListData" then data that time is not changing but when i use "ctrl+s" then data is reflecting
This is eventsListData my global variable
import 'dart:async';
import 'package:cwc/ApiManager/api_magager.dart';
import 'package:flutter/material.dart';
import 'constants.dart';
class TabTop extends StatefulWidget {
const TabTop({Key? key}) : super(key: key);
#override
State<TabTop> createState() => _TabTopState();
}
class _TabTopState extends State<TabTop> {
ApiManager apiManager = ApiManager();
#override
void initState() {
super.initState();
}
String query = '';
Timer? debouncer;
void dispose() {
debouncer?.cancel();
super.dispose();
}
void debounce(
VoidCallback callback, {
Duration duration = const Duration(milliseconds: 10),
}) {
if (debouncer != null) {
debouncer!.cancel();
}
debouncer = Timer(duration, callback);
}
Future searchEvent(String query) async => debounce(() async {
// final breanchesLists = await apiManager.topBrancesList(query);
final eventsLists = await apiManager.eventsSearch(query);
if (!mounted) return;
setState(() {
this.query = query;
eventsSearchLists = eventsLists;
print("eventsSearchLists $eventsSearchLists");
setState(() {
eventsListData =[eventsSearchLists];
print("eventsSearchLists111 $eventsListData");
});
});
});
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 8),
height: 60,
child: TextField(
onChanged: searchEvent,
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide.none,
),
filled: true,
fillColor: const Color(0xFFFFFFFF),
hintText: 'Search for Events',
suffixIcon: const Icon(
Icons.search_outlined,
color: Color(0xFF444444),
),
),
),
);
}
}
This is my another page where I called "TabTop" and another things.
// ignore_for_file: prefer_const_constructors
import 'package:cwc/constants/card_top.dart';
import 'package:cwc/constants/top_card.dart';
import 'package:cwc/ui/Event/components/activities.dart';
import 'package:cwc/ui/Event/components/event_page_changer.dart';
import 'package:cwc/ui/Event/components/event_tab_view.dart';
import 'package:cwc/ui/Home/components/search_components.dart';
import 'package:cwc/ui/Home/home_page.dart';
import 'package:cwc/ui/footer/bottom_nav_bar.dart';
import 'package:cwc/ui/footer/bottom_nav_bar_event.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class Event extends StatefulWidget {
const Event({Key? key}) : super(key: key);
#override
_EventState createState() => _EventState();
}
class _EventState extends State<Event> {
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
// backgroundColor: Color(0xff80CAD7),
body: SafeArea(
child: Stack(
children: [
Container(
width: double.infinity,
height: 210,
decoration: const BoxDecoration(
color: Color(0xff80CAD7),
image: DecorationImage(
image: AssetImage('assets/bg_dummy.png'),
fit: BoxFit.cover,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(18, 12, 0, 0),
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: const CircleAvatar(
radius: 25,
backgroundColor: Colors.white,
child: Icon(Icons.arrow_back_ios_new, color: Colors.black),
),
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(18, 125, 18, 0),
child: TabTop(),
),
Padding(
padding: EdgeInsets.only(top: 190),
child: Container(
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topRight: Radius.circular(24.0),
topLeft: Radius.circular(24.0)),
),
child: Activities()), // here is my list of data in Activities page (Showing data in this page)
)
// EventPageChanger(),
// Expanded(child: Activities()),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => HomePage()));
},
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
child: Image.asset('assets/btnavico.png'),
elevation: 5.0,
highlightElevation: 10,
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: Container(
// height: MediaQuery.of(context).size.height * (10 / 100),
child: BottomNavBarEvent()),
);
}
}
The thing that’s happening here is that you are calling setState inside TabTop on loading new data that caused only TabTop to rebuild i.e. only the widget inside TabTop is rebuilt. But, the Activities() widget that shows the data is inside Event class which doesn’t get rebuilt.So we need a way to rebuild the entire Event class once the data is updated. You could achieve this by:
Define a callback function in TabTop class that can be called after data is updated as:
class TabTop extends StatefulWidget {
const TabTop({Key? key,required this.onDataUpdated}) : super(key: key);
final VoidCallback onDataUpdated;
#override
State<TabTop> createState() => _TabTopState();
}
And call this callback function once the data is updated as:
Future searchEvent(String query) async => debounce(() async {
// final breanchesLists = await apiManager.topBrancesList(query);
final eventsLists = await apiManager.eventsSearch(query);
if (!mounted) return;
///callback function has been called here
widget.onDataUpdated();
///avoid unnecessary setState
setState(() {
this.query = query;
eventsSearchLists = eventsLists;
eventsListData =[eventsSearchLists];
print("eventsSearchLists111 $eventsListData");
print("eventsSearchLists $eventsSearchLists”);
});
});
On Event class, while calling TabTop, send the callback function as a parameter as :
Padding(
padding: EdgeInsets.fromLTRB(18, 125, 18, 0),
child: TabTop(
onDataUpdated : () =>setState((){}),
),
),

"The declaration 'setState' isn't referenced." warning for DropdownButton within StatefulWidget

I have a stateful widget in which I put my DropdownButton. Inside DropdownButton's onChange event, I have a setState but it keeps warning me that the declaration 'setState' isn't referenced.
And it's actually not called whenever onChange event is fired.
Any suggestion would be highly appreciated.
Please see the code snippet below for more detailed.
class TypeSetup extends StatefulWidget {
const TypeSetup({Key? key}) : super(key: key);
#override
_TypeSetupState createState() => _TypeSetupState();
}
class _TypeSetupState extends State<TypeSetup> {
var _selectedType;
List<Type>? _types;
#override
void initState() {
super.initState();
loadTypeJson();
}
Future loadTypeJson() async {
String typeJson = await DefaultAssetBundle.of(context)
.loadString("assets/data/types.json");
Iterable typeIter = json.decode(typeJson)["accommodation-types"];
setState(() {
_types = List<Type>.from(typeIter.map((model) => Type.fromJson(model)));
});
}
#override
Widget build(BuildContext context) {
final typeList = _types?.map((model) {
return new DropdownMenuItem<String>(
value: model.type,`enter code here`
child: new Text(model.name),
);
}).toList();
return Container(
padding: EdgeInsets.all(DefaultPalette.defaultPadding),
decoration: BoxDecoration(
color: DefaultPalette.secondaryColor,
borderRadius: const BorderRadius.all(Radius.circular(10)),
),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(
"Set up",
style: Theme.of(context).textTheme.subtitle1,
),
SizedBox(
width: double.infinity,
child: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Container(
padding: EdgeInsets.only(left: 16, right: 16),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 1),
borderRadius: BorderRadius.circular(13)),
child: DropdownButton(
hint: Text('Select Type'),
dropdownColor: Colors.white,
icon: Icon(Icons.arrow_drop_down),
iconSize: 30,
isExpanded: true,
underline: SizedBox(),
style: TextStyle(color: Colors.black, fontSize: 22),
value: _selectedType,
onChanged: (newValue) {
setState() {
_selectedType = newValue;
print("Selected type changed.");
}
},
items: typeList,
),
)
)
)
)
]),
);
}
}
You need to call setState like this
setState(() {
_selectedType = newValue;
});

DragTarget doesnt call onWillAccept with custom Draggable (Flutter)

I am trying to make Tags which are draggable text so that I can drag them to one of 2 DragTarget I have (ideally being able to move them between 3 DragTarget). Unfortunately I can't make them interact with the DragTargets as they dont even call onWillAccept(). My draggables are DragabbleTag and extends Draggable and my dragTargets are in a Stateful Widget and should accept them.
import 'package:myApp/components/draggableTag.dart';
import 'package:flutter/material.dart';
class DraggableTagTarget extends StatefulWidget {
final String title;
final int maxTagAmount;
final Color backgroundColor;
final List<DraggableTag> tagsPool;
const DraggableTagTarget(
{Key key,
this.title,
this.backgroundColor,
this.tagsPool,
this.maxTagAmount})
: super(key: key);
#override
_DraggableTagTargetState createState() => _DraggableTagTargetState();
}
class _DraggableTagTargetState extends State<DraggableTagTarget> {
String test = "Test";
#override
Widget build(BuildContext context) {
return DragTarget<DraggableTag>(onAccept: (DraggableTag value) {
setState(() {
widget.tagsPool.add(value);
test = value.label;
});
}, onWillAccept: (DraggableTag data) {
bool result =
widget.tagsPool.length <= widget.maxTagAmount ? true : false;
debugPrint("ONWillAccept: " + data.label + " = " + result.toString());
return result;
}, builder: (context, candidateData, rejectedData) {
return Container(
decoration: new BoxDecoration(
color: widget.backgroundColor,
border: Border.all(
color: Colors.black,
),
),
child: Column(
children: <Widget>[
Text(test),
Text(widget.title),
SizedBox(
height: 60,
child: Wrap(
children: widget.tagsPool,
),
),
],
),
);
});
}
}
Custom DragTarget 'DraggableTagTarget'
import 'package:flutter/material.dart';
class DraggableTag extends Draggable<String> {
final String label;
DraggableTag({Key key, this.label})
: super(
key: key,
data: label,
child: idleTag(label),
feedback: feedbackTag(label),
childWhenDragging: ghostTag(label),
);
static Widget idleTag(String label) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 2.0),
child: Text(
label,
style: TextStyle(
fontSize: 16,
),
),
decoration: BoxDecoration(
color: Colors.blue,
border: Border.all(
color: Colors.black,
),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
);
}
Custom Draggable 'DraggableTag'
I excluded feedbackTag() and ghostTag which shouldnt be relevant
At first my draggableTag was extending a widget but seeing some similar problem I made it into extending directly a Draggable but it didnt help
EDIT:
I am assigning ma values to draggable in a custom DialogWidget (stateful widget) in a list
class _RatingDialogState extends State<RatingDialog> {
List<DraggableTag> tagsPool = [
DraggableTag(label: "Acting"),
DraggableTag(label: "Scenario"),
DraggableTag(label: "Pace"),
DraggableTag(label: "Length"),
DraggableTag(label: "Message"),
];
List<DraggableTag> negativeTagsPool = [];
List<DraggableTag> positiveTagsPool = [];
#override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
elevation: 0,
backgroundColor: Colors.transparent,
child: contentBox(context),
);
}
contentBox(context) {
return Stack(
...
Wrap(
children: tagsPool,
),
SizedBox(height: 22),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Flexible(
child: FractionallySizedBox(
widthFactor: 0.85,
child: DraggableTagTarget(
title: "Negative",
backgroundColor: Colors.red,
tagsPool: negativeTagsPool,
maxTagAmount: 3),
),
),
Flexible(
child: FractionallySizedBox(
widthFactor: 0.85,
child: DraggableTagTarget(
title: "Positive",
backgroundColor: Colors.green,
tagsPool: positiveTagsPool,
maxTagAmount: 3),
),
),
]),
...
SOLUTION: as ikerfah explained, I didnt put the right type into <> because I was confused to what my DraggableTag class was. I made another class to contains the data Tag so that both my DragTarget and DraggableTag use this class
Draggable and DragTarget must have the same generic type, but you have Draggable<String> and DragTarget<DraggableTag>

ViewModelBuilder returning variable null. Not retrieving state

I am refactor app to use stacked but have issue. State not seem to be pass correct between widget.
I added ViewModelBuilder at top of the widget tree that I want to affect.
return ViewModelBuilder<vehicleData>.reactive(
builder: (context, model, child){
return Container(
padding: EdgeInsets.symmetric(horizontal: 20.0),
child: InkWell(
splashColor: Colors.blueGrey,
child: Card(
//color: Colors.blueGrey,
child: ListTile(
leading: AspectRatio(
aspectRatio: 0.8,
child: Image.network(
//data.images,
snapshot.data.documents[index]['icon'],
height: 500,
//width: 300,
fit: BoxFit.contain,
)
),
title: Text(
//data.make,
snapshot.data.documents[index]['make'],
textAlign: TextAlign.start,
style: TextStyle(fontSize: 18.0,
fontWeight: FontWeight.bold,),
),
onTap: (){
Navigator.push(context, MaterialPageRoute(builder: (context) =>
//ProformaScreen(data.make),
ProformaScreen(snapshot.data.documents[index]['make']),
),
);
model.setModel(snapshot.data.documents[index]['model']);
} ,
),
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.blueGrey),
borderRadius: BorderRadius.circular(10),
),
),
),
);
},
viewModelBuilder: ()=> vehicleData(),
);
This calls model.setModel and assign the model based on the selected car.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:core';
import 'package:stacked/stacked.dart';
class vehicleData extends BaseViewModel{
String _make;
String _images;
var _model;
setModel(var model){
_model = model;
print ('This is the Model of the Car \n');
print (_model);
notifyListeners();
}
setMake(String make){
_make = make;
notifyListeners();
}
setImages(String images){
_images = images;
notifyListeners();
}
get getModel => print('This is within the Get ' + _model);
get getMake => _make;
get getImage => _images;
}
Both print statement return correct model I still can see them.
But when I try call using ViewModelBuilder in another page model return null:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:gerente_loja/core/services/vehicle_data.dart';
import 'package:stacked/stacked.dart';
class menuModel extends StatefulWidget {
#override
_menuModelState createState() => _menuModelState();
}
class _menuModelState extends State<menuModel> {
var carModel;
#override
Widget build(BuildContext context) {
String selectModel;
return ViewModelBuilder<vehicleData>.reactive(
builder: (context, modelView, child){
return Padding(
padding: const EdgeInsets.only(left: 16.0, right: 16.0),
child: Container(
decoration: BoxDecoration(border: Border.all(color: Colors.black),
borderRadius: BorderRadius.circular(25.0)
),
padding: EdgeInsets.only(left: 50.0, right: 16.0),
child: DropdownButton(
hint: Text('Ano'),
dropdownColor: Colors.transparent,
elevation: 5,
icon: Icon(Icons.arrow_drop_down),
isExpanded: true,
iconSize: 36.0,
value: selectModel,
onChanged: (value){
setState(() {
print (modelView.getModel);
selectModel = value;
});
},
items: carModel.map((value) {
return DropdownMenuItem (
value: value,
child: Text(value));
}).toList(),
),
),
);
},
viewModelBuilder: ()=> vehicleData(),
);
}
}
print (modelView.getModel); is null.
Anyone know why model return null? I have look hard to solve but no idea why.

How to pass data back from a widget?

I have a screen where users can add a location. Here, I have separated all my widgets into there own files as illustrated below;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:fluttershare/pages/location/location_help_screen.dart';
import 'package:fluttershare/widgets/common_widgets/customDivider.dart';
import 'package:uuid/uuid.dart';
import '../../widgets/camp_type_select.dart';
import '../../widgets/extra_location_notes.dart';
import '../../widgets/location_input.dart';
import '../../widgets/opening_times.dart';
import '../../widgets/post_media.dart';
import '../../widgets/space_avalibility.dart';
import '../../widgets/utility_type_select.dart';
import '../../widgets/width_restriction.dart';
import '../../widgets/height_restriction.dart';
import '../../models/locations.dart';
import '../../models/user.dart';
import '../home.dart';
class AddNewLocation extends StatefulWidget {
static const routeName = '/add-new-location';
final User currentUser;
AddNewLocation({this.currentUser});
_AddNewLocationState createState() => _AddNewLocationState();
}
class _AddNewLocationState extends State<AddNewLocation> {
String postId = Uuid().v4();
final _scaffoldKey = GlobalKey<ScaffoldState>();
PlaceLocation _pickedLocation;
int storyPostCount = 0;
bool isLoading = false;
void _selectPlace(double lat, double lng) {
_pickedLocation = PlaceLocation(lattitude: lat, longitude: lng);
}
getLocationPostCount() async {
setState(() {
isLoading = true;
});
QuerySnapshot snapshot = await locationPostRef
.document(currentUser.id)
.collection('user_location_posts')
.getDocuments();
setState(() {
storyPostCount = snapshot.documents.length;
});
}
createLocationPostInFirestore(
{String mediaUrl,
String description,
double heightRestriction,
double widthRestriction}) {
locationPostRef
.document(currentUser.id)
.collection("user_location_posts")
.document(postId)
.setData({
"postId": postId,
"ownerId": currentUser.id,
"username": currentUser.username,
"description": description,
"timestamp": timestamp,
"lattitude": _pickedLocation.lattitude,
"longitude": _pickedLocation.longitude,
"max_height": heightRestrictionValue.toStringAsFixed(0),
"max_width": widthRestrictionValue.toStringAsFixed(0),
});
}
handlePostSubmit() {
createLocationPostInFirestore(
heightRestriction: heightRestrictionValue,
widthRestriction: widthRestrictionValue,
);
SnackBar snackbar = SnackBar(
content: Text("Profile Updated"),
);
_scaffoldKey.currentState.showSnackBar(snackbar);
setState(() {
postId = Uuid().v4();
});
}
buildUploadUserHeader() {
return Container(
margin: EdgeInsets.only(bottom: 10),
height: 200,
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
color: Colors.blue,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage:
CachedNetworkImageProvider(currentUser.photoUrl)),
),
],
),
),
),
Expanded(
flex: 6,
child: Container(
color: Colors.pink,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Text(currentUser.displayName),
],
),
),
),
],
),
);
}
buildCampUploadForm() {
return Container(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
//buildUploadUserHeader(), //TODO: This is the profile header that is dissabled for now. Work on possibly a header in the future.
Container(
padding: EdgeInsets.all(15),
child: Column(
children: <Widget>[
CampTypeSelect(),
CustomDivider(),
LocationInput(_selectPlace),
CustomDivider(),
HeightRestriction(),
WidthRestriction(),
SpaceAvalibility(),
OpeningTimes(),
CustomDivider(),
PostMedia(),
CustomDivider(),
UtilityServices(),
CustomDivider(),
ExtraLocationNotes(),
Container(
height: 80,
margin: EdgeInsets.only(top: 10, bottom: 10),
child: Row(
children: <Widget>[
Expanded(
child: FlatButton(
color: Colors.black,
onPressed: () => handlePostSubmit(),
child: Text(
"SUBMIT",
style: Theme.of(context).textTheme.display2,
),
padding: EdgeInsets.all(20),
),
)
],
),
),
],
),
),
],
),
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
automaticallyImplyLeading: false,
title: const Text(
'Add New Location',
style: TextStyle(color: Colors.black),
),
actions: <Widget>[
// action button
IconButton(
icon: Icon(Icons.info_outline),
color: Colors.black,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) => LocationSubmitHelpScreen()),
);
},
),
// action button
IconButton(
icon: Icon(Icons.close),
color: Colors.black,
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
body: buildCampUploadForm(),
backgroundColor: Colors.white,
);
}
}
What I am trying to do is pass the data back from the widget ExtraLocationNotes()
to the function createLocationPostInFirestore().
For context, this is what my widget looks like;
import 'package:flutter/material.dart';
import 'common_widgets/custom_form_card.dart';
class ExtraLocationNotes extends StatefulWidget {
_ExtraLocationNotesState createState() => _ExtraLocationNotesState();
}
class _ExtraLocationNotesState extends State<ExtraLocationNotes> {
TextEditingController descriptionController = TextEditingController();
#override
Widget build(BuildContext context) {
return CustomFormCard(
child: Column(
children: <Widget>[
Container(
child: Row(
children: <Widget>[
Text(
"EXTRA INFORMATION",
style: TextStyle(
fontSize: 18.0,
color: Colors.black,
fontWeight: FontWeight.w400,
letterSpacing: 2.0,
),
),
],
),
),
SizedBox(height: 20),
TextFormField(
controller: descriptionController,
maxLines: 6,
maxLength: 250,
maxLengthEnforced: true,
style:
new TextStyle(fontSize: 18.0, height: 1.3, color: Colors.black),
decoration: const InputDecoration(
hintText:
"Please write a description of this location for fellow travellers.",
alignLabelWithHint: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.only(),
borderSide: BorderSide(color: Colors.black),
),
),
),
],
),
);
}
}
How do I pass the data back to the parent widget?
You need a callback, which will be triggered in the child widget then the value will be updated in the parent widget:
// 1- Define a pointers to executable code in memory, which is the callback.
typedef void MyCallback(String val);
class ExtraLocationNotes extends StatefulWidget {
// 2- You will pass it to this widget with the constructor.
final MyCallback cb;
// 3- ..pass it to this widget with the constructor
ExtraLocationNotes({this.cb});
_ExtraLocationNotesState createState() => _ExtraLocationNotesState();
}
class _ExtraLocationNotesState extends State<ExtraLocationNotes> {
//..
//...
RaisedButton(
//..
// 4- in any event inside the child you can call the callback with
// the data you want to send back to the parent widget:
onPressed: () {
widget.cb("Hello from the other side!");
}
),
}
Then inside the parent widget you need to catch the data which sent form the child:
class AddNewLocation extends StatefulWidget {
//...
_AddNewLocationState createState() => _AddNewLocationState();
}
class _AddNewLocationState extends State<AddNewLocation> {
// 1- Global var to store the data that we're waiting for.
String _dataFromMyChild = "";
buildCampUploadForm() {
return Container(
//...
//...
// 2- Pass the callback with the constructor of the child, this
// will update _dataFromMyChild's value:
ExtraLocationNotes(cb: (v) => setState(() => _dataFromMyChild = v)),
//..
}
// then
createLocationPostInFirestore() {
// Use _dataFromMyChild's value here
}
}
You can use the BuildContext object to get the context widget (might no be the parent!) couldn't read it all but as i understand that you need to pass the info from the child to the parent ,and you can do it with some like this :-
(context.widget as MyType).doStuff();
Note.
please check first with
print(context.widget.runtimeType);
but to make a better solution make a mutable data object that is passed from parent to the child so when changes happens it reflect's on the parent so you can separate business logic from ui logic.