Flutter - Translate oninit - flutter

Class 1
#override
void initState() {
super.initState();
text =DemoLocalizations.of(context).trans('connection');
}
Class 2 (DemoLocalizations)
Future<bool> load() async {
String data = await rootBundle.loadString('locale/i18n_${locale.languageCode}.json');
Map<String, dynamic> _result = json.decode(data);
this._sentences = new Map();
_result.forEach((String key, dynamic value) {
this._sentences[key] = value.toString();
});
return true;
}
Return
So the question is: How can i load custom string (internazionalization) when screen load (oninit)?

Use didChangeDependencies instead of initState.
It is called once after widget creation and again when the state of DemoLocalizations is changed.

Related

How to handle _Future<dynamic> value in flutter?

I am trying to get value from firebase in flutter. during that time, I am receiving _Flutter value returning from the Future<> type returning function. please help someone
I am having a code for fetching values from firebase.. the function gets a value from firebase by querying with an attribute
class FirebaseMethods {
Future<List> findEvents(dynamic attribute, dynamic value) async {
CollectionReference eventCollection =
FirebaseFirestore.instance.collection('events');
return eventCollection
.where(attribute, isEqualTo: value)
.get()
.then((QuerySnapshot querySnapshot) {
List events = [];
querySnapshot.docs.forEach((doc) {
events.add(doc.data());
});
return events;
}).catchError((error) {
print("Failed to retrieve events: $error");
});
}
Future<List> findUsers(dynamic attribute, dynamic value) async {
CollectionReference userCollection =
FirebaseFirestore.instance.collection('profile');
return userCollection
.where(attribute, isEqualTo: value)
.get()
.then((QuerySnapshot querySnapshot) {
List users = [];
querySnapshot.docs.forEach((doc) {
users.add(doc.data());
});
return users;
}).catchError((error) {
print("Failed to retrieve users: $error");
});
}
}
And I am calling the above function 'findUsers' in the following way:
dynamic database_functions = FirebaseMethods();
class RenderProfileView extends StatefulWidget {
String email;
RenderProfileView(this.email, {super.key});
#override
State<RenderProfileView> createState() => _RenderProfileViewState();
}
class _RenderProfileViewState extends State<RenderProfileView> {
TextEditingController name_controller = TextEditingController();
TextEditingController phone_number_controller = TextEditingController();
late dynamic user_json = database_functions.findUser('email', widget.email); // without late I am getting error and getting values with attribute 'email' = widget.email
dynamic get_name() {
print(user_json);
return 'some_value';
}
}
When the 'findUser' function is called, the printing message is -> Instance of '_Future'
Someone please help.. if any other way to solve the issue please mention it.
Future describes async operations in flutter. you must await all Futures results. Either by using the await keyword or .then property.
You could try adding initState to your stateful widget or go with a FutureBuilder depending on your use case.
Below is an edited version of your code.
dynamic database_functions = FirebaseMethods();
class RenderProfileView extends StatefulWidget {
String email;
RenderProfileView(this.email, {super.key});
#override
State<RenderProfileView> createState() => _RenderProfileViewState();
}
class _RenderProfileViewState extends State<RenderProfileView> {
TextEditingController name_controller = TextEditingController();
TextEditingController phone_number_controller = TextEditingController();
late dynamic user_json;
#override
void initState() {
super.initState();
database_functions.findUser('email', widget.email).then((data) {
user_json = data
});
}
String get name => 'some_value';
}

what should I do to async initial some data in flutter before the page load

I am writing a simeple todo list app, the todo item stored in sqlite
sqflite: ^2.0.0+3 right now. I want to load the sqlite todo data before loading the flutter page, this is my initial code looks like in flutter:
class _HomePageState extends State<HomePage> {
GlobalKey _inputViewKey = GlobalKey();
List<Todo> _todos = [];
#override
void initState() {
var _db = DBProvider.db;
_todos = await _db.getAllTodo();
super.initState();
}
}
and this is the function to load data from database:
Future<List<Todo>> getAllTodo() async {
final db = await database;
var result = await db.query('Todo');
return result.map((it) => Todo.fromJson(it)).toList();
}
the IDE told that I should add async in the initial function. When I add the async function, the initial function could not work. What should I do to make it work? how to initial the async data before the HomePage?
You cant mark async on inistate. You can try this
class _HomePageState extends State<HomePage> {
GlobalKey _inputViewKey = GlobalKey();
List<Todo> _todos = [];
#override
void initState() {
var _db = DBProvider.db;
getAllTodo();
super.initState();
}
}
And in the method
getAllTodo() async {
final db = await database;
var result = await db.query('Todo');
_todos = result.map((it) => Todo.fromJson(it)).toList();
setState((){});
}

why it is showing instance of future? how to get data

Future<void> setEmpId(String empId) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString(this.empId, empId);
}
Future<String> getEmpId() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String empId;
empId = await prefs.getString(this.empId) ?? '';
return empId;
}
Prefs().setEmpId(state.empVerifyEntity.employee.empId);//set empId from api
In Another Class:
class Page extends State<Page>{
Future<void> getEmpId() async {
String empId = await Prefs().getEmpId().toString();
print("----------->>>>>>>>$empId");
}
#override
void initState() {
super.initState();
getEmpId();
}
}
Here I'm getting instance of future, I tried every method like .then(value) Each and every method I'm getting instance of future. how to data correctly?
The problem you have is due to the fact that your initState method is synchronous and the method in which you are getting the value for EmpId isn't.
Therefore, it is not waiting for the result of the call.
You can accomplish this in several ways:
Add a then clause to the call of getEmpId
#override
void initState() {
super.initState();
getEmpId().then((result) {
//your logic here
)
}
Add a PostFrameCallback
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
getEmpId();
});
}

Load sharedprefrence data to Textfield on page load flutter

I have a shared data that contain mobile no of customer,in my profile,that need to be filled with in textfield when i open profile page,i'm getting the data from shard preference data,when i load data to textfield it's throws error
TextEditingController mobile = TextEditingController();
void initState() {
getMobile();
}
Get data From Sharedpreference
Future<String> getMobile() async {
Future notificatinstatus = SharedPrefrence().getUserMobile();
notificatinstatus.then((data) async {
var mobile_no=data;
mobile_no.text=mobile;
return mobile;
});
}
I think is better like this:
var mobileController = TextEditingController();
getMobile() async {
Future notificatinstatus = SharedPrefrence().getUserMobile();
notificatinstatus.then((data) async {
var mobile_no=data;
setState(() {
if(mobile_no.isNotEmpty){
mobileController.text = mobile_no;
}
});
});
}
#override
void initState() {
super.initState();
getMobile();
}

Correct way to call an api by provider in fflutter?

I have been trying to make a app in flutter where an api is called and data is updated in TextField
Used provider for state management, here is the code for it.
class ProfileProvider with ChangeNotifier {
var profileData;
String _url = "http://10.0.2.2:3000/api/v1/user/loggedin_user";
void getData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var token = prefs.getString('token');
var data = await http.get(
_url,
headers: {
"accept": "application/json",
"content-type": "application/json",
'Token': token,
},
);
var infoOfPerson = json.decode(data.body);
profileData = new ProfileObject(
name: infoOfPerson['name'],
mobile: infoOfPerson['mobile'],
email: infoOfPerson['email'],
role: infoOfPerson['role'],
);
notifyListeners();
}
ProfileObject get profileInfo {
return profileData;
}
}
I am getting the data fine, now i have to show it in the UI, but sometime data is populated, sometime its not. Can someone please point me the right direction why this is happening.
Here is the code for UI.
class Profile extends StatefulWidget {
#override
_ProfileState createState() => _ProfileState();
}
class _ProfileState extends State<Profile> {
final emailController = TextEditingController(text: '');
final nameController = TextEditingController(text: '');
final mobileController = TextEditingController(text: '');
var _isInit = true;
#override
void didChangeDependencies() {
if (_isInit) {
final profileData = Provider.of<ProfileProvider>(context);
profileData.getData();
if (profileData.profileInfo != null) {
emailController.text = profileData.profileInfo.name;
nameController.text = profileData.profileInfo.email;
mobileController.text = profileData.profileInfo.mobile;
}
_isInit = false;
super.didChangeDependencies();
}
}
#override
Widget build(BuildContext context) {
final profileData = Provider.of<ProfileProvider>(context);
return Scaffold(
drawer: NavigationDrawer(),
body: profileData.profileInfo == null
? Center(
child: CircularProgressIndicator(),
)
: Builder(
builder: (context) => SingleChildScrollView(
child: Padding(.....
Below the padding, there is normal TextField, can someone tell me why the data is being populated sometime and sometime its coming empty, even I wrapped it with CircularProgressIndicator() and a check the notifyListeners(); is not working there. The loader is not being shown and data is not being loaded.
Thanks
for StatelessWidget.
Inside the build method use:
Future.microtask(() async {
context.read<SomeProvider>().fetchSomething();
});
For StatefulWidgets if you want to call it once. Do this inside the initState() or didChangeDependencies (better if the latter). This will be called at the end of the frame which means after the build or rendering finishes..
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
context.read<SomeProvider>().fetchSomething();
});
}
EDIT: WidgetsBinding will also work on build. I forgot on why I used microtask lol
i've created a function which called nextTick, i call it in initState and it works for now, but want to see others method
void nextTick(Function callback, [int milliseconds = 0]) {
Future.delayed(Duration(milliseconds: 0)).then((_) {
callback();
});
}
then use it like below
#override
void initState() {
super.initState();
nextTick((){
ProfileProvider profileProvider = Provider.of<ProfileProvider>(context);
profileProvider.getProfile();
});
}
Edit: i store couple of variables to manage them on ui, like isLoading, hasError and errorMessage. Here is my provider class
class ProfileProvider extends ChangeNotifier {
bool _hasError = false;
bool _isLoading = true;
String _errorMsg = '';
Profile _profileResponse;
bool get hasError => _hasError;
bool get isLoading => _isLoading;
String get errorMsg => _errorMsg;
Profile get profileResponse => _profileResponse;
Future<void> getProfile() async {
this.setLoading = true;
this.setError = false;
this.setErrorMsg = '';
try {
await dio.post('$api/p/view', data: {}).then((res) {
print(res.data);
_profileResponse = Profile.fromJson(jsonDecode(res.data));
print(_profileResponse.data);
notifyListeners();
}).whenComplete(() {
this.setLoading = false;
});
} catch (e) {
this.setError = true;
this.setErrorMsg = '$e';
}
this.setLoading = false;
}
set setError(bool val) {
if (val != _hasError) {
_hasError = val;
notifyListeners();
}
}
set setErrorMsg(String val) {
if (val != null && val != '') {
_errorMsg = val;
notifyListeners();
}
}
set setLoading(bool val) {
_isLoading = val;
notifyListeners();
}
}