pass data over the tree flutter - variables

I search a simple solution to pass simple string variable over the tree widget, inherite function is to complicated to me.
to resume :
I tried to pass data to page 1 to body of page 2
class page1 extends StatefulWidget
string textvariable
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new page2(
textvariable: this,
)),
);
},
in my next page I have a StatelessWidget
class page2 extends StatelessWidget {
var textvariable;
page2({this.textvariable});
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(title: const Text("Localisation")),
body: testwidget (textvariable),
);
}
}
I try to passe textvariable in the widget 3 who is a stateful
class testwidget extends StatefulWidget
...
new Text(
"$textvariable",
),

Related

Dart-Flutter autoformat vscode is not accordance with indent convention

I have setup dart autoformatting to flutter, but unfortunately when I press CTRL+S
It was formatting in one line
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _judul = 'Private Chat';
#override
Widget build(BuildContext context) {
return const MaterialApp(title: _judul, home: MyHomePage());
}
}
While I expect dart format like this
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _judul = 'Private Chat';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _judul,
home: MyHomePage()
);
}
}
Solved, It was because flutter format command which default of maximum col in a line is 80. Since my case is not reached 80 col, dart didn't autoformat make new line.

Unable to fetch PDF file from Asset in Flutter, how can I fetch the PDF directly

I have attached the code. How can I fetch the PDF from assets? I think calling the init function could solve, but I couldn't call it perfect. I want to fetch the pdf without using any button or else something.
So, I need to fetch it directly as soon as the Class InformationTechnology call.
class InformationTechnology extends StatefulWidget {
#override
_InformationTechnologyState createState() => _InformationTechnologyState();
}
class InformationTechnology extends StatefulWidget {
#override
_InformationTechnologyState createState() => _InformationTechnologyState();
}
class _InformationTechnologyState extends State<InformationTechnology> {
String pdfasset = "assets/IT.pdf";
PDFDocument _doc;
bool _loading = false;
#override
void initState() {
super.initState();
}
_initPDF()async{
setState(() {
_loading = true;
});
final doc = await PDFDocument.fromAsset(pdfasset);
setState(() {
_doc = doc;
_loading = false;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Introduction to Information Technology"),
centerTitle: true,
backgroundColor: Colors.blueAccent,
),
body: _loading?
Center(
child: CircularProgressIndicator(),
):PDFViewer(document: _doc),
);
}
}

How passing widget dynamically in class constructor parameter

This is my first question in Stackoverflow.
I'm trying to call a widget in another StatefulWidget when we passing it as class constuctor parameter.
So i have this custom widget :
class MyTextWidget extends StatelessWidget {
final String text;
MyTextWidget({ #required this.text });
#override
Widget build(BuildContext context) {
return Text(this.text);
}
}
i want to use in another widget like this (with pass in class constructor parameter)
import 'package:myproject/MyTextWidget.dart';
.
.
.
// Passing widget like this
child: Example(display: MyTextWidget,text: this.widget.text);
.
.
.
// And use this widget like this
this.widget.display(text: this.widget.text);
this is my first code :
class Example extends StatefulWidget {
final Widget display;
final String text;
Example({ #required this.display, #required this.text });
#override
State<StatefulWidget> createState() {
return ExampleState();
}
}
class ExampleState extends State<Example> {
#override
Widget build(BuildContext context) {
return this.widget.display(text: this.widget.text); // here we have error
}
}
but i have this error
The expression doesn't evaluate to a function, so it can't be invoked.dart(invocation_of_non_function_expression)
I realize i need to make a typedef for this problem so i improve code like this:
typedef Widget DisplayType({ #required String text });
class Example extends StatefulWidget {
final DisplayType display;
final String text;
Example({ #required this.display, #required this.text });
#override
State<StatefulWidget> createState() {
return ExampleState();
}
}
class ExampleState extends State<Example> {
#override
Widget build(BuildContext context) {
return this.widget.display(text: this.widget.text);
}
}
Our error is fixed but when i want to pass MyTextWidget in another widget:
child: Example(display: MyTextWidget,text: this.widget.text);
Finally i get this error:
The argument type 'Type' can't be assigned to the parameter type 'Widget Function({String text})'.dart(argument_type_not_assignable)
how can i fix this problem?
I think you want display to be a builder function that returns a MyTextWidget.
import 'package:flutter/material.dart';
Future<void> main() async {
return runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(final BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(final BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Home")),
body: Center(
child: Example(
display: ({#required final String text}) {
assert(text != null);
return MyTextWidget(text: text);
},
text: "some text",
),
),
);
}
}
class MyTextWidget extends StatelessWidget {
final String text;
MyTextWidget({#required this.text}) : assert(text != null);
#override
Widget build(final BuildContext context) {
return Text(this.text);
}
}
typedef Widget DisplayType({#required final String text});
class Example extends StatefulWidget {
final DisplayType display;
final String text;
Example({
#required this.display,
#required this.text,
}) : assert(display != null),
assert(text != null);
#override
State<StatefulWidget> createState() {
return ExampleState();
}
}
class ExampleState extends State<Example> {
#override
Widget build(final BuildContext context) {
return this.widget.display(text: this.widget.text);
}
}
You don't need to pass the down the widget, just import it in the class that you want to use it.
When you want to instantiate it, you need to use parenthesis MyTextWidget().
You don't need to use this when calling the parameters passed to a Stateful Widget, just widget.text will work.
You seem to be having some misunderstandings about Flutter. There are very rare occasions where you need to use this.

How to test widgets which relies on data which was set by other widget through provider?

a novice programmer here who just started in flutter and trying to explore flutter testing. The following is my userInfoProvider code;
import 'package:flutter/cupertino.dart';
class UserInfoProvider with ChangeNotifier{
String _username;
String _userRole;
getUsername() => _username;
getUserRole() => _userRole;
setUsername(String username){
_username = username;
notifyListeners();
}
setUserRole(String userRole){
_userRole = userRole;
notifyListeners();
}
getCurrentUserInformation(String uid) async {
Query q = await Firestore.instance
.collection('users')
.document(uid)
.get()
.then((DocumentSnapshot ds) {
setUsername(ds.data['userName']);
setUserRole(ds.data['userRole']);
return;
});
}
}
I have a homepage widget which has an Uid property. This widget uses this uid to identify from the "users" collection in firestore to set the username and userRole my UserInfoProvider.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'UserInfoProvider.dart';
class HomePage extends StatefulWidget {
final String uid;
HomePage(this.uid);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
void afterFirstLayout(BuildContext context) async {
var user = Provider.of<UserInfoProvider>(context);
await user.getCurrentUserInformation(widget.uid);
}
#override
Widget build(BuildContext context) {
return Container();
}
}
SecondPage widget has 2 text widget which displays the username and userRole from UserInfoProvider get methods.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'UserInfoProvider.dart';
class SecondPage extends StatefulWidget {
#override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
#override
Widget build(BuildContext context) {
final user = Provider.of<UserInfoProvider>(context);
return Column(
children: <Widget>[
Text(user.getUsername()),
Text(user.getUserRole())
],
);
}
}
In such scenarios how would one write the widget test whereby i would like to test the SecondPage Widget to ensure that the text displayed (e.g. the userRole) is the same as the one the mock Uid which i have built in HomePage widget? Following is my test code which fails the test;
testWidgets("Test secondpage widget to display correct userRole", (WidgetTester tester) async{
final uid = "ekkMH1sKW1dN0r3ZTQGCngJS1cV2";
await tester.pumpWidget(ChangeNotifierProvider(
builder: (_) => UserInfoProvider(),
child: MaterialApp(
home: HomePage(uid)
)
));
await tester.pumpWidget(ChangeNotifierProvider(
builder: (_) => UserInfoProvider(),
child: MaterialApp(
home: SecondPage()
)
));
final UserRoleTextFinder = find.text("someUserRole");
expect(UserRoleTextFinder, findsOneWidget);
});
I would guess is that i have build two instances of userInfoProvider which the state in Homepage is not the same state as the SecondPage based on my test code? Anyways appreciate any advice for my case.

Flutter - Create dynamic number of texteditingcontrollers

I am recreating an app I have previously made in Swift, and on one of my pages we call an API and based on the results, we present the user a dynamic number of textfields to search by different search parameters.
Is there any good way to do this in Dart/Flutter? Since dart doesn't support generating code at runtime, is this even a possibility?
I just modified #Felix's answer with using Map to store TextEditingControllers instead of list. I think its easy to call textEditingControllers with key value pairs.
Modified code block;
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "MyHomePage",
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(
title: "MyHomePage",
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
var stringListReturnedFromApiCall = ["first", "second", "third", "fourth", "..."];
// This list of controllers can be used to set and get the text from/to the TextFields
Map<String,TextEditingController> textEditingControllers = {};
var textFields = <TextField>[];
stringListReturnedFromApiCall.forEach((str) {
var textEditingController = new TextEditingController(text: str);
textEditingControllers.putIfAbsent(str, ()=>textEditingController);
return textFields.add( TextField(controller: textEditingController));
});
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SingleChildScrollView(
child: new Column(
children:[
Column(children: textFields),
RaisedButton(
child: Text("Print Values"),
onPressed: (){
stringListReturnedFromApiCall.forEach((str){
print(textEditingControllers[str].text);
});
})
]
)));
}
}
when you write something to textfields and hit to print button results ;
flutter: first controller text
flutter: second controller text
flutter: third controller text
flutter: fourth controller text
flutter: so on .......
More or less as #Günter Zöchbauer mentioned, you can just build a list of widgets which are nested then in a container.
Here's a simple example:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "MyHomePage",
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(
title: "MyHomePage",
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
var stringListReturnedFromApiCall = ["first", "second", "third", "fourth", "..."];
// This list of controllers can be used to set and get the text from/to the TextFields
var textEditingControllers = <TextEditingController>[];
var textFields = <TextField>[];
stringListReturnedFromApiCall.forEach((str) {
var textEditingController = new TextEditingController(text: str);
textEditingControllers.add(textEditingController);
return textFields.add(new TextField(controller: textEditingController));
});
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SingleChildScrollView(
child: new Column(
children: textFields,
)));
}
}
Edit: Added list for TextEditingControllers to interact with all the TextFields
Using list of textEditingControllers instead of map
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var stringListReturnedFromApiCall = ["first", "second", "third", "fourth", "..."];
List<TextEditingController> textEditingControllers = [];
#override
void initState() {
super.initState();
stringListReturnedFromApiCall.forEach((String str) {
var textEditingController = TextEditingController(text: str);
textEditingControllers.add(textEditingController);
});
}
#override
void dispose() {
super.dispose();
// dispose textEditingControllers to prevent memory leaks
for (TextEditingController textEditingController in textEditingControllers) {
textEditingController?.dispose();
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('title'),
),
body: ListView.builder(
itemCount: stringListReturnedFromApiCall.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: TextField(
controller: textEditingControllers[index],
),
);
},
),
);
}
}
list that contains your controllers
var myControllers = [];
function called in order to populate myControllers
createControllers() {
myControllers = [];
for (var i = 0; i < your_items.length; i++) {
myControllers.add(TextEditingController());
}
}
init createKeys in your statefullwidget
use it like this, for example in listview builder ;
TextField(
controller: myControllers[index],
),
May be this can help you or other's as well.
createFieldsList(context) {
thirdStepUserRegistration.value.forEach((key, value) { //// This line will loop all your data [ValueNotifier<Map<String, dynamic>> thirdStepUserRegistration]
if (!fieldsController.containsKey(key)) {
fieldsController[key] = TextEditingController(); //// This one will create you a list of controllers that u need for your fiels [Map<String, TextEditingController> fieldsController]
fieldsList.add( ////You will be creating a list of widget which is textfields [List<Widget> fieldsList]
Container(
height: 40.0,
margin: EdgeInsets.only(bottom: 10),
width: MediaQuery.of(context).size.width - 100,
child: PrimaryTextFormField( //This is my customize textfield you can create yours
controller: fieldsController[key],
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.words,
inputFormatters: textFormatter(),
hintText: value,
),
)
);
}
});
}
Column additionalDetails(BuildContext context) {
createFieldsList(context);
return Column( children: fieldsList );
}