I am passing value between 2 screens I need to know how can I simply print value?
This is how I am sending value
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => ViewPostScreen(
id: id,
),
),
);
},
This is my second page
class ViewPostScreen extends StatefulWidget {
final int id;
ViewPostScreen({Key key, #required this.id}) : super(key: key);
#override
_ViewPostScreenState createState() => _ViewPostScreenState();
}
class _ViewPostScreenState extends State<ViewPostScreen> {
}
I need to print the value of id in _ViewPostScreenState I try with simple print but showing error anyone can help?
The problem is you are not using print inside a method rather at the class level. Create a method and then use print inside it.
void method() {
print(...);
}
Full solution:
class ViewPostScreen extends StatefulWidget {
final int id;
ViewPostScreen({Key key, #required this.id}) : super(key: key);
#override
_ViewPostScreenState createState() => _ViewPostScreenState();
}
class _ViewPostScreenState extends State<ViewPostScreen> {
void method() {
print(widget.id);
}
}
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) {
print(id); // print here
return ViewPostScreen(
id: id,
);
}
),
);
},
You can access the widget's attributes from the State using widget
print(widget.id.toString());
You cannot call the print function in the class body. It needs to be within a function. You can use initState as it is the first function that runs.
void initState() {
super.initState();
print(widget.id.toString());
}
Note that you will also need a build method in your State class
Related
I have two page and I want to use the variable 'id' in the second screen to fetch data from API.
What should I do?
Screen one: it's the product screen where user click on profile image and after that I get all information about user owner in the second screen.
Screen two: I display data for this user by id
NB: I get all the data by API
id is always Null
Screen one:
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UserProfile(
id: id,
)),
);
// do something here
},
),
Screen two:
class UserProfile extends StatefulWidget {
final int id;
const UserProfile({Key key, #required this.id}) : super(key: key);
#override
_UserProfileState createState() => _UserProfileState();
}
class _UserProfileState extends State<UserProfile> {
#override
void initState() {
getprofile(id);
super.initState();
}
Future<List<dynamic>> getprofile(int id) async {
var response = await Network().getData('/auth/user/$id');
data = json.decode(response.body);
return data;
}
When you want to use a property from the StatefulWidget you need to use widget.propertyName. In your case it's widget.id
class _UserProfileState extends State<UserProfile> {
#override
void initState() {
getprofile(widget.id);
super.initState();
}
Future<List<dynamic>> getprofile(int id) async {
var response = await Network().getData('/auth/user/$id');
data = json.decode(response.body);
return data;
}
Either do the same that you did before,so pass the id as a parameter to the _UserProfileState class, so just call:
_UserProfileState(#required this.id) : super();
Another option to make variables available is to use the Provider widget
I've a question:
In my Widget build(BuildContext context), I want to store a certain value,
final userName = book.owner
(book is the reference to the certain value from Firestore)
But it's done not in the right way to my lack of knowledge. I'd appreciate if someone could guide through that.
Thank you in advance!
Snippet of my code
class BookView extends StatefulWidget {
final Book book;
BookView({Key key, #required this.book}) : super(key: key);
DatabaseMethods databaseMethods = new DatabaseMethods();
var userName;
#override
_BookViewState createState() => _BookViewState(book);
}
class _BookViewState extends State<BookView> {
Book book;
_BookViewState(this.book);
String userName;
#override
void initState() {
userName = book.owner;
super.initState();
}
// final Book book;
createChatroomAndStartConversation({var userName}) {
if (userName != Constants.myName) {
String roomId = getChatRoomId(userName, Constants.myName);
List<String> users = [userName, Constants.myName];
Map<String, dynamic> chatRoomMap = {
"Users": users,
"roomId": roomId,
};
DatabaseMethods().createChatRoom(roomId, chatRoomMap);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConversationScreen(roomId, userName)),
);
} else {
print("You cannot send msg to your self");
}
}
#override
Widget build(BuildContext context) {
//widget.book;
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
...
FlatButton(
child: Text(
"Get contact with",
style: TextStyle(color: Colors.white),
),
color: Colors.blue,
onPressed: () {
createChatroomAndStartConversation(
userName: userName);
...
}
Snippet of Value not in range: 1
getChatRoomId(String a, String b) {
if (a.substring(0, 1).codeUnitAt(0) > b.substring(0, 1).codeUnitAt(0)) {
return "$b\_$a";
} else {
return "$a\_$b";
}
}
It's not a good practice to store any data in build() method, because this method is invoked too many times to do the such kind of move. Consider using StatefulWidget to store any state you have in the widget, for the very beginning. When you use this widget, you can define this all in such way:
class YourWidget extends StatefulWidget {
#override
_YourWidgetState createState() => _YourWidgetState();
}
class _YourWidgetState extends State<YourWidget> {
String userName;
#override
void initState() {
userName = book.owner;
super.initState()
}
#override
Widget build(BuildContext context) {
return Container(child: Text(userName),);
}
}
Here, in initState() you can retrieve value from book and set it to userName. But for more complex and bigger applications, consider using StateManagement solutions and some kind of architectural patterns i.e. Riverpod, Provider, MobX, BLoC.. Because changing the state via setState() method will cause rebuilding whole child widget tree, which could freeze whole UI in complex app.
UPD to 'Snippet of my code':
According to your code, if you are using a 'book' from Widget, not its state - use widget.book, in such way you have access to widget members, because of this you don't need a constructor of state. So, due to these changes, your code might looks like:
class BookView extends StatefulWidget {
final Book book;
BookView({Key key, #required this.book}) : super(key: key);
// You DON'T need this here, because you are retrieving these methods
// inside your state via DatabaseMethods constructor
DatabaseMethods databaseMethods = DatabaseMethods();
#override
_BookViewState createState() => _BookViewState(book);
}
class _BookViewState extends State<BookView> {
String userName;
#override
void initState() {
// Using widget.book to retrieve Book object from state's widget
userName = widget.book.owner;
super.initState();
}
createChatroomAndStartConversation({var userName}) {
if (userName != Constants.myName) {
String roomId = getChatRoomId(userName, Constants.myName);
// Also, it's just a recommendation, try to omit local variables types
// because they are already known with List type (String). Also, this
// all is about chatRoomMap
var users = <String>[userName, Constants.myName];
final chatRoomMap = <String, dynamic>{
"Users": users,
"roomId": roomId,
};
DatabaseMethods().createChatRoom(roomId, chatRoomMap);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConversationScreen(roomId, userName)),
);
} else {
print("You cannot send msg to your self");
}
}
#override
Widget build(BuildContext context) {
// your widgets here
}
}
UPD 2:
Second trouble and issue with 'Snippet of Value not in range: 1'. I could to reproduce it with given value of 'a' as empty string. So, your function invocation is like getChatRoomId('', 'user123'), because of empty 'userName', substring function can't take values from range [0, 1), so exception is raised.
I'm trying to access the information I've passed over from a previous class before the build method begins. But it's saying only static members can be accessed in initializers. I don't really want to use the static property, partially because I wouldn't know how to use it, but also because I think it seems unnecessary. In previous pages I've been able to access the data but only after the build method, does anyone know how I can access it before? Thanks all
class FirstPage extends StatefulWidget {
#override
_FirstPageState createState() => _FirstPageState();
}
class _FirstPageState extends State<FirstPage> {
List<MyProvider> myList;
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: myList.length,
itemBuilder: (context, index) {
String imgPath = myList[index].image;
String myTextPath = myList[index].name;
String locationNamePath = myList[index].location;
double distancePath = myList[index].distance;
String myName = '${myTextPath} ''${locationNamePath}';
return MyCard(
locationText: locationNamePath,
myText: myTextPath,
assetImage: Image.network(imgPath),
function: (){
Provider.of<Data>(context, listen: false).addLogo(Image.network(imgPath));
Navigator.push(context, MaterialPageRoute(builder: (context) => SecondPage(myName: myName,)));
},
);
}),
);
}
}
My next page accesses the data using a key but it seems not to be able to use it before the build method, and that's what I need to get around!
class SecondPage extends StatefulWidget {
final String myName;
const SecondPage({Key key, this.myName})
: super(key: key);
#override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> with TickerProviderStateMixin {
final CollectionReference myItemsReference = Firestore.instance.collection('${widget.myName}');
// This is where the error is
#override
Widget build(BuildContext context) {
return Scaffold();
}
}
Use the initState method for anything related to initialization of State. See this for more on initState.
Example:
CollectionReference myItemsReference;
#override
void initState() {
myItemsReference = Firestore.instance.collection('${widget.myName}');
}
Using Flutter, I am trying to pass data via the constructor to a new screen.
However, this is somewhat of a special case because the screen is a Stateful widget and I am using the Navigation Routes method of navigation.
The data also happens to be of type int, if that matters.
The named route navigation is set up like so:
void main() => runApp(Main());
class Main extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: PreLoadScreen.id,
//initialRoute: TemporaryScreen.id,
routes: {
TemporaryScreen.id: (context) => TemporaryScreen(),
InfoScreen.id: (context) => InfoScreen(),
PreLoadScreen.id: (context) => PreLoadScreen(),
StatsScreen.id: (context) => StatsScreen(),
RideScreen.id: (context) => RideScreen(),
AudioScreen.id: (context) => AudioScreen(),
},
);
}
}
The screen that I'm passing the data to has the following constructor code:
class StatsScreen extends StatefulWidget {
static const String id = 'stats_screen';
int tableID; // current shift table ID being passed in from super
// Constructor required for having data passed in
StatsScreen({Key key, #required this.tableID}) : super(key: key);
#override
_StatsScreenState createState() {
print('statsscreen DEBUG: $tableID'); // <-- this shows the data passed was NULL! :(
return _StatsScreenState();
}
}
The screen that I'm passing the data FROM contains the following code:
void _checkShiftStatus() async {
bool userClockedIn = await ShiftManager().isUserClockedIn();
int tableName = await ShiftManager().getActiveRideTableName();
print('preload DEBUG: tablename: $tableName'); // <-- this verifies the data is NOT null here.
if (userClockedIn) {
Navigator.pushNamed(context, StatsScreen.id,
arguments: {'tableID': tableName}); // <--- something is wrong here, presumably
} else {
shouldDisplayStartShift = !userClockedIn;
showProgressSpinner = false;
}
}
I've tried changing the suspect line to:
Navigator.pushNamed(context, StatsScreen.id,
arguments: tableName);
and...
Navigator.pushNamed(context, StatsScreen.id,
arguments: {tableName});
But get the same result in the target screen (data passed is null). It's sort of like baseball... the batter is the initial screen... and the catcher is the screen we're navigating to. The ball is the data. Except in my case, the batter seems to be Sammy Sosa and the ball is out of the park someplace... which is great for the Cubs but not for me.
I've also tried googling, docs, stackoverflow (even this specific answer... but I can't seem to extract the pertinent meaning from it), and Bacardi... and I'm getting very annoyed. Please someone point out my syntax error and what line it's on. Thank you!
You have to access data using ModalRoute.
class Delete2 extends StatefulWidget {
Delete2({Key key}) : super(key: key);
#override
_Delete2State createState() => _Delete2State();
}
class _Delete2State extends State<Delete2> {
#override
Widget build(BuildContext context) {
final int args = ModalRoute.of(context).settings.arguments;
return Container(
child: Text(args.toString()),
);
}
}
(Full Documentation)
I'm using MaterialApp with router to navigate to the next screen, i'm Using this for navigate to another screen with passing the Arguments :
onTap: () => Navigator.of(context).pushNamed(
DetailDebt.routedName,
arguments: {
'receiverName': debtListView.receiverName,
'amount': debtListView.amount,
'dateReturn': debtListView.dateReturn,
'pathImage': debtListView.imageReceiver,
'signatureImage': debtListView.imageSignature,
},
),
In the next screen i'm make variable to store the argument like this :
final Map arguments = ModalRoute.of(context).settings.arguments as Map;
return Scaffold(
body: Container(
child: Text(
arguments['receiverName'],
),
),
);
My question is , How to store the Argument in variable then i can call it something like this :
// I want Store the Arguments in the variable , so i can call it something like this :
final Map arguments = ModalRoute.of(context).settings.arguments as Map;
final loadedArguments = arguments; // <= ???
return Scaffold(
body: Container(
child: Text(
loadedArguments.receiverName,
),
),
);
And It's My Model if you need it :
import 'dart:typed_data';
import 'package:hive/hive.dart';
part 'debt_model_hive.g.dart';
#HiveType()
class DebtModelHive extends HiveObject {
#HiveField(0)
String receiverName;
#HiveField(1)
int amount;
#HiveField(2)
DateTime dateReturn;
#HiveField(3)
String imageReceiver;
#HiveField(4)
Uint8List imageSignature;
DebtModelHive({
this.receiverName,
this.amount,
this.dateReturn,
this.imageReceiver,
this.imageSignature,
});
// Hive fields go here
}
Thank's
I'll show you a simple example how to pass arguments to your page. Here I push a new named route with int value in arguments:
onPressed: () {
Navigator.of(context).pushNamed('my_route', arguments: 100);
},
In my MaterialApp I set onGenerateRoute parameter to generate a new route with given arguments:
onGenerateRoute: (settings) {
switch (settings.name) {
case 'my_route': return MaterialPageRoute(
builder: (context) => HomePage(settings.arguments as int), // passing arguments
settings: settings,
);
default: throw Exception('Unknown route');
}
},
Now I can access the value inside of build method:
class HomePage extends StatefulWidget {
final int arguments;
HomePage(this.arguments, {Key key}) : super(key: key);
#override
State<StatefulWidget> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int value;
#override
void initState() {
super.initState();
value = widget.arguments;
}
#override
Widget build(BuildContext context) {
return Text('Value from arguments: ${widget.arguments}');
}
}
Alternatively, you can set the value from route's arguments inside of initState like this:
int value;
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
value = ModalRoute.of(this.context).settings?.arguments;
});
print('setting value from route arguments');
});
}
Though, it's pretty dirty and I don't recommend doing this.