How can I pass variable id to second screen in flutter? - flutter

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

Related

"'key' is required, but there's no corresponding argument" flutter error

How to solve this error?
The named parameter 'key' is required, but there's no corresponding argument. (Documentation) Try adding the required argument.
error
Future<void> onJoin() async {
// update input validation
setState(() {
_channelController.text.isEmpty
? _validateError = true
: _validateError = false;
});
if (_channelController.text.isNotEmpty) {
await _handleCameraAndMic(Permission.camera);
await _handleCameraAndMic(Permission.microphone);
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => VideoCall(
channelName: _channelController.text,
role: _role,
),
),
);
}
}
class VideoCall
class VideoCall extends StatefulWidget {
final String channelName;
final ClientRole role;
const VideoCall({Key key, required this.channelName, required this.role})
: super(key: key);
#override
_VideoCallState createState() => _VideoCallState();
}
class _VideoCallState extends State<VideoCall> {
final _users = <int>[];
final _infoStrings = <String>[];
bool muted = false;
late RtcEngine _engine;
#override
void dispose() {
// clear users
_users.clear();
// destroy sdk
_engine.leaveChannel();
_engine.destroy();
super.dispose();
}
#override
void initState() {
super.initState();
// initialize agora sdk
initialize();
}
this is the videoCall class in there no any error shows.
when add "key" show this
When remove required property from key in video call class
show this error
In VideoCall class, key property set as a required, change it to optional:
class VideoCall extends StatefulWidget {
final String? channelName;
final ClientRole? role;
const VideoCall({Key? key, this.channelName, this.role})
: super(key: key);
#override
_VideoCallState createState() => _VideoCallState();
}

How to use GetX for data passing in Flutter?

My first Flutter development with GetX. Now encounter a problem.
I have a ListView where the items are all encapsulated Class.
The requirement now is to create an obs List as a data source. The elements in the List are all models.
I now want to pass the model in the List to the item, and click on the item to pass it to the next page for data modification. what should I do?
I am like this
`
Controller:
class FindQADetailController extends GetxController {
var detailEntity = QADetailEntity().obs;
}
Page:
class FindQAPage extends StatefulWidget {
const FindQAPage({Key key}) : super(key: key);
#override
State<FindQAPage> createState() => _FindQAPageState();
}
class _FindQAPageState extends BasePageMixin<FindQAPage, FindQAPresenter>
with SingleTickerProviderStateMixin
implements FindQAIView {
final findQAController = Get.put(FindQAController());
#override
void initState() {
super.initState();
_refresh();
}
#override
Widget build(BuildContext context) {
return RezaAppContainer(
childWidget: Obx(() => DeerListView(
itemCount: findQAController.listData.length,
onRefresh: _refresh,
loadMore: _loadMore,
hasMore: findQAController.hasMore,
itemBuilder: (_, index) {
var entity = findQAController.listData[index];
return FindItemQAPage(entity);
})),
);
}
Item:
class FindItemQAPage extends StatefulWidget {
FindItemQAPage(this.entity, {Key key}) : super(key: key);
QAEntity entity;
#override
State<FindItemQAPage> createState() => _FindItemQAPageState();
}
class _FindItemQAPageState
extends BasePageMixin<FindItemQAPage, FindItemQAPresenter>
with SingleTickerProviderStateMixin
implements FindItemQAIView {
FindItemQAController findItemQAController = Get.put(FindItemQAController());
#override
void initState() {
super.initState();
findItemQAController.entity.value = widget.entity;
}
}
`
I want the elements in the array in the first page to be passed to the item and the next page, and the data modifications made on the next page to be passed to the item in the first page.
Passing Data from 1st Screen to 2nd Screen
You can pass any data using arguments parameters in navigation methods
Get.to(ScreenName(),arguments: PASS_DATA);
If you are doing navigation with routes still you can pass data
Get.toNamed(RoutesName, arguments: PASS_DATA);
For navigate data back from 2nd screen to 1st screen you can user result property.
Get.back(result:PASS_DATA);
Pass data from 1st screen to 2nd screen & vice versa.
1st screen controller
import 'package:get/get.dart';
class FirstController extends GetxController {
/// Navigation method.
Future<void> btnNavigateTap() async {
//.... Using Get.toNamed method || use this if you are using routeName
//.... Pass Data from 1st screen to 2nd screen
Get.toNamed(
SeconScreenRouteName,
arguments: {
"user": "Jems",
"emails": ["abc#gmail.com", "pqr#gmail.com"],
},
);
//.... Using Get.to method
//.... Pass Data from 1st screen to 2nd screen
Get.to(
SecondScreen(),
arguments = {
"user": "Jems",
"emails": ["abc#gmail.com", "pqr#gmail.com"],
},
);
//.... Get Data from 2nd screen to 1st screen
final result = await Get.to(
SecondScreen(),
arguments = {
"user": "Jems",
"emails": ["abc#gmail.com", "pqr#gmail.com"],
},
);
}
}
2nd screen controller to access data.
import 'package:get/get.dart';
class SecondController extends GetxController {
late String user;
late List<String> emails;
dynamic argumentData;
#override
void onInit() {
super.onInit();
user = argumentData['user'];
emails = argumentData['emails'];
}
void btnBackTap(){
//... Passing data to previous screen.
Get.back(result:{
"user":"Jack",
});
}
}
For more details about navigation & parsing data using getX check this reference link

How can I use the argument value at the new page initState in Flutter?

If I pass some argument while rotating from one page to another page, how can I use the argument value at the new page initState in Flutter?
Assume I have two Flutter page, and I would like to navigate to another pages as following:
Navigator.pushNamed(
context,
'/page2',
arguments: {
'name': widget.name,
"id": widget.id,
},
);
Then I can display the argument at the page2 by replacing the following code inside the build function:
final Map<String, dynamic>? args =
ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>?;
var name= args!["name"];
var id = args["id"];
print("name:" + name);
print("id" + id);
Now, I would like to do some API call by passing the arguments to the initState.
#override
void initState() {
super.initState();
// how can I pass the argument id and argument name to the function?
callApi(id, name);
}
callApi(id, name) async {
var response = await api(id, name);
}
You should define the routes into your app main.dart file like this.
MaterialApp(
routes: {
"/page1": (context) => const Homepage(),
"/page2": (context) => SecondPage(
ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>),
},
initialRoute: "/page1",
)
And then define the parameters into the second page class
class SecondPage extends StatefulWidget {
final Map<String, dynamic>? args;
const SecondPage(this.args, {Key? key}) : super(key: key);
#override
SecondPageState createState() => SecondPageState();
}
And can use it into the init state like this.
class SecondPageState extends State<SecondPage> {
#override
void initState() {
callApi(widget.args["name"], widget.args["id"]);
super.initState();
}
}

Storing certain value in Widget build / Flutter

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.

Flutter how to print value pass through screen?

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