How to pass arguments to a function in flutter? - flutter

I am having the following function:
Future<List<expense>> getExpenseDateWise(DateTime FromDate, DateTime ToDate) async {
final db = await database;
var expenses = await db
.rawQuery('SELECT * FROM EXPENSES WHERE DATE(DATETIME) >= ? AND DATE(DATETIME) <= ?',
['$FromDate','$ToDate']);
List<expense> expensesList = List<expense>();
expenses.forEach((currentExpense) {
expense expenses = expense.fromMap(currentExpense);
expensesList.add(expenses);
});
return expensesList;
}
And the above function requires 2 arguments.
I am calling the above function in a following way:
class dateWiseList extends StatefulWidget {
final DateTime fromDate;
final DateTime toDate;
dateWiseList({this.fromDate, this.toDate});
#override
_dateWiseListState createState() => _dateWiseListState();
}
class _dateWiseListState extends State<dateWiseList> {
#override
void initState() {
super.initState();
DatabaseProvider.db.getExpenseDateWise(// <----------1----------> //).then(
(expenseList) {
BlocProvider.of<ExpenseBloc>(context).add(SetDates(expenseList));
},
);
}
In <----------1----------> I need to pass the two arguments. I don't know how to do it please help me.
The function getExpenseDateWise is used for fetching data records between two dates selected by the user in a different form. That's why I have called those values using dateWiseList({this.fromDate, this.toDate});.
Thanks for your replies

Try widget.fromDate and widget.toDate. Coz I'm seeing you're using a stateful widget.
If your function takes positional arguments, eg
Future doSomething(String name, Bool jerk) {
Lots of code
}
Then when calling it inside a stateful widget, while using some arguments you passed to that widget, do tgis
blah blah = doSomething(widget.argument1, widget.argument2)
If it's not positional arguments, eg
Future doSomething({String name, Bool jerk} ) {
Lots of code
}
, then it's gonna be
blah blah = doSomething(
name: widget.argument1, jerk: widget.argument2)

You just need to pass the starting date and the end date to filter your data
DateTime now = DateTime.now();
DtaeTime yesterday = DateTime.now().subtract(Duration(days:1));
DatabaseProvider.db.getExpenseDateWise(yesterday, now).then(.........)
you can treat flutter functions just like any other functions

Related

Flutter: Realtime database appends list when listens changes

I'm using flutter and firebase realtime database.I'm trying to read data from a specific node.I'm saving the data that I am collecting in the Orderlist class and then I return a Future List of Ordelist.This Future function I am trying to use on another widget.I want to display on screen every time data is updated.
Future<List<Orderlist>> order() async{
String business =await businessname();
List table = await tables();
List<Orderlist> list = [];
table.forEach((element) async{
String payment_method = '';
String payment_state ='';
var snapshot = ref.child(business).child(element.toString()).onValue.listen((event) {
event.snapshot.children.forEach((method) {
if(method.key=='payment_method') payment_method=method.value.toString();
if(method.key=='payment_state') payment_state = method.value.toString();
});
final order = Orderlist(payment_method: payment_method,payment_state: payment_state);
list.add(order);
});
});
return list;
}
The problem is that at first place the data are loaded on screen but when I am trying to update the data for some reason the list is appended whereas I just want to replace the previous data with the updated data.To be more specific if I want to listen to 2 nodes to be updated I will have a list with 2 Orderlist items.But the problem is when I update one of them the list is expanded to 3 Orderlist items.
Here is the widget where I am trying to use the Future function
first data loaded Updated da
class TempSettings extends StatefulWidget {
const TempSettings({super.key});
#override
State<TempSettings> createState() => _TempSettingsState();
}
class _TempSettingsState extends State<TempSettings> {
String? business;
List<Orderlist> list=[];
final user = FirebaseAuth.instance.currentUser;
#override
void initState() {
// TODO: implement initState
g();
super.initState();
}
void g() async{
list = await DatabaseManager(user_uid: user!.uid).order();[![[![enter image description here](https://i.stack.imgur.com/hn2NQ.png)](https://i.stack.imgur.com/hn2NQ.png)](https://i.stack.imgur.com/SJ4M1.png)](https://i.stack.imgur.com/SJ4M1.png)
}
#override
Widget build(BuildContext context) {
return Column(children: list.map((e) => ListTile(title: Text(e.payment_method!),)).toList(),);
}
}
When you listen to data in Firebase with onValue, the event you get contains a snapshot of all data. Even when only one child node was added/changed/removed, the snapshot will contain all data. So when you add the data from the snapshot to list, you are initially adding all child nodes once - but then on an update, you're adding most of them again.
The easiest way to fix this is to empty the list every time onValue fires an event by calling list.clear().

What does " int? get priority => 1;" do?

I was reading a flutter code as below:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:test_get_app/user_controller.dart';
class AuthMiddleware extends GetMiddleware {
final authService = UserController.findOrInitialize; // Here is error, this line can't find UserController
#override
int? get priority => 1;
bool isAuthenticated = false;
#override
RouteSettings? redirect(String? route) {
isAuthenticated = true;
if (isAuthenticated == false) {
return const RouteSettings(name: '/login');
}
return null;
}
}
When I reached to the following line, I couldn't understand it's syntax and how does it work?
int? get priority => 1;
int? Means it is an int but the int can be null
=> 1 Means () {return 1;}
This is a so-called getter. Getters can be used to provide read access to class properties.
They can also return values directly, like in your case.
They are accessed like properties of the class they are declared in:
final middleWare = AuthMiddleware();
final priority = middleWare.priority;
In your case the getter probably must or can be implemented (see the #override annotation), since all implementations of a middleware must declare their priority, I guess. Since the declared type is int? it may also return null instead of an integer.
Getters can be declared using an expression. Like in your case. Using a block body does also work:
int? get priority {
return 1;
}

How to pass data in a stateful widget with constructor?

I am new to flutter and I think I miss a little piece of information about constructor and stateful widget. I tried many ways but always have an error. I just want to pass data into my stateful widget to manipulate from there.
Here is my Error
The instance member 'widget' can't be accessed in an initializer.
Try replacing the reference to the instance member with a different expression
Here is my code
class CreateEducatorEventForm extends StatefulWidget {
final DateTime day = DateTime.now();
final String favoriteId = '';
CreateEducatorEventForm(DateTime day, String favoriteId);
#override
_CreateEducatorEventFormState createState() =>
_CreateEducatorEventFormState();
}
class _CreateEducatorEventFormState extends State<CreateEducatorEventForm> {
final _formKey = GlobalKey<FormState>();
bool _isLoading = false;
String _eventName = '';
String _eventDescription = '';
DateTime _eventDateStart = widget.day;
DateTime _eventDateFinish = widget.day;
You can just move it into initState
class _CreateEducatorEventFormState extends State<CreateEducatorEventForm> {
final _formKey = GlobalKey<FormState>();
bool _isLoading = false;
String _eventName = '';
String _eventDescription = '';
DateTime _eventDateStart;
DateTime _eventDateFinish;
#override
void initState() {
super.initState();
_eventDateStart = widget.day;
_eventDateFinish = widget.day;
}
}
To be fair, unless you really need to store this into your state (say, if it really participates in the lifecycle of your widget), you should just refer to it via widget.day whenever you need it.

Dart, override many getters and setters in a DRY or synthetic way in a Proxy Pattern

Lets take this dart class:
class Subject {
String a;
String b;
String c;
}
Now I want to use it trough a Proxy, to manage lazy loading and synchronization.
I want as well to have default values to use as placeholders while I'm loading the real data from the net. To keep thighs neat and isolated I added another class:
class Fallback implements Subject {
#override String a = 'a';
#override String b = 'b';
#override String c = 'c';
}
Now I have all the bricks I need to write down the "proxy with fallback" class:
class Proxy implements Subject {
Subject model;
Subject fallback = Fallback();
Future<void> slowlyPopulateModel() async => if (model == null) ... // do some async stuff that valorize model
#override
String get a {
slowlyPopulateModel();
return model?.a ?? fallback.a;
}
#override
set a(String _a) {
model?.a = a;
notifyListener();
}
// same getters and setters for b and c
}
By overriding get a I can call the slow I/O method if needed and return the placeholder value of my Fallback class. Once the new value is set my overridden set a(String _a) will call notifyListener() that will update my interface.
It is working fine, but I have manually override getter and setter for each field of my class (and they are many).
Does Dart have any trick to do this in a more DRY way?
E.g. some way to inject code to be executed before or after each getter or setter?
I would suggest to have a look at Streams for this.
This code example will return an initial value, fetch a new value and notify the listener of it through a stream.
import 'dart:async';
class Subject {
// Current value, initially at "a"
String _a = "a";
StreamController<String> _aController = StreamController<String>();
String get a {
_updateA();
return _a;
}
Stream<String> get aStream => _aController.stream;
void _updateA() async {
String newValue = await _fetchA();
_a = newValue; // update the current value
_aController.add(newValue); // push the new value onto the stream for listeners
}
// return a String after two seconds
Future<String> _fetchA() async {
return Future.delayed(
Duration(seconds: 2),
() => "New value for _a",
);
}
// This closes the stream
void dispose() {
_aController.close();
}
}
main(args) {
final subject = Subject();
// listen to changes
subject.aStream.listen((value) {
print("new value of a: $value");
});
// get current value
final currentValue = subject.a;
print("current value of a: $currentValue");
}
Output of this example
current value of a: a
(after two seconds) new value of a: New value for _a
Use it in Flutter with a StreamBuilder
StreamBuilder<String>(
stream: subject.aStream,
initialData: subject.a,
builder: (context, snapshot) {
final valueOfA = snapshot.data;
return Text("value is $valueOfA");
}
)
Some of the boilerplate code could be replaced by the BehaviorSubject in RxDart. But this would require another dependency to be imported into the project.

Flutter object is not initialized after initState

I'm new to flutter, and i bumped into a problem.
I have a Feed model in my app that looks like this:
import 'package:uuid/uuid.dart';
class Feed {
// Static Members
var uuid = new Uuid();
// Members
String id;
bool isScheduled;
DateTime createdTime;
DateTime feedingTime;
String deviceId;
// Constructors
Feed({this.feedingTime, this.deviceId, this.isScheduled}) {
id = uuid.v4();
createdTime = DateTime.now();
}
Feed.fromDevice(deviceId) {
Feed(deviceId: deviceId, feedingTime: DateTime.now(), isScheduled: false);
}
}
Now i have my AddFeedForm that i'm trying to initialize with default values, in the InitState:
class _AddFeedFormState extends State<AddFeedForm> {
// Final Members
final _formKey = GlobalKey<FormState>();
final List<Machine> _devices = machinesFromServer;
// Members
Feed _feed;
#override
void initState() {
_feed = Feed.fromDevice(_devices.first.id);
super.initState();
}
But somehow after the initState the _feed parameter stays null!
Any ideas?
But somehow after the initState the _feed parameter stays null!
Are you sure this is the case, and not that you're getting a Feed instance that has null fields?
It looks like your named constructor is incorrect:
Feed.fromDevice(deviceId) {
Feed(deviceId: deviceId, feedingTime: DateTime.now(), isScheduled: false);
}
Here you're calling the default Feed constructor inside a named constructor, but not doing anything with the result - this is creating another Feed and then throwing it away. The one returned by the named constructor has not been initialised.
What you probably wanted was this:
Feed.fromDevice(deviceId):
this(deviceId: deviceId, feedingTime: DateTime.now(), isScheduled: false);
This makes the fromDevice constructor call the default constructor for initialisation of the instance, rather than creating another copy that goes unused.
Another option would be to make it a static method:
static fromDevice(deviceId) {
return Feed(deviceId: deviceId, feedingTime: DateTime.now(), isScheduled: false);
}
There wouldn't be much difference in this case.. Constructors seem nicer, but sometimes you might find that you want to a) make initialisation async (static methods can return a Future<Feed> but constructors cannot or b) do more processing of the arguments before they're passed to the real constructor that might not fit nicely in the initialiser call.