Is it possible to listen for changes, and upon a change, get those new values from a separate class and update variable in current class? - flutter

So, I am in my home_screen dart file and I have a Text in it where I want it to display the live value from another class's properties value. When I update the class's properties value from another script I want my home_screen Text to update to that new value. My class in a separate file is the following (simplified) :
class MyClass {
static int myNumber = 10;
}
I want the following Text to update with the value of myNumber in another file:
Text('iWantThisToDisplayLiveMyNumber'),
When I change the value of myNumber from yet another random script how do I get the Text to update in live time to always be myNumber?

Look into Providers.
class MyClass with ChangeNotifier {
static int myNumber = 10;
void changeNumber(){
myNumber = 1;
notifyListeners();
}
}
In your Widget class you can set up a "listener" like this:
int updatedNumber = Provider.of<MyClass>(context, listen: true).myNumber;
This is a basic and bad way of doing this. Please check out the "ChangeNotifier" "ChangeNotifierProvider" and "Provider.of" Sections in the docs here.
https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple
Its pretty easy to get started with. Good luck

You can make use of the getter and setter functions.
In the example below we are printing happy birthday when the person's age changes:
class Person {
int _age;
Person(this._age);
int get age => _age;
set age(int newValue) {
print("Happy birthday! You have a new Age.");
//do some awsome things here when the age changes
_age = newValue;
}
}
The usage is exactly as you are used to:
final newPerson = Person(20);
print(newPerson.age); //20
newPerson.age = 21; //prints happy birthday
print(newPerson.age); //21

Related

What does the 'get' keyword do in a dart class? [duplicate]

I am struggling with the concept of getters and setters in Dart, and the more I read, the more I cannot grasp the underlying purpose. Take for example the following code:
main() {
Car car = new Car();
car.doors = 44;
print(car.doors); // 44
}
class Car {
int doors = 4;
}
Later, I decide to make “doors” a private variable, so I do the following:
main() {
Car car = new Car();
car.doors = 44;
print(car.doors); // 44
}
class Car {
int _doors = 4;
int get doors => _doors;
set doors(int numberOfDoors) => _doors = numberOfDoors;
}
According to the code, _doors is now a private variable, and so I cannot access it in main(). However, by manipulating doors, I can indirectly change the value of _doors, which is what I thought I wanted to prevent in the first place by making it a private variable. So what is the purpose of making a previously public variable into a private one, if you can still indirectly manipulate it? And, how are getters and setters even working to change the properties of these variables? I am trying to understand the fundamental concept, because without that, I don't understand how or why getters and setters are used.
Instance variables in Dart have implicit getters and setters. So for your example code, it will operate in exactly the same way, since all you have done is changed from an implicit getter and setter to an explicit getter and setter.
The value of explicit getters and setters is that you don't need to define both if you don't want. For instance we can change your example to only define a getter:
main() {
Car car = new Car();
print(car.doors); // 4
car.doors = 6; // Won't work since no doors setter is defined
}
class Car {
int _doors = 4;
int get doors => _doors;
}
Additionally, you can also add extra logic in a getter or setter that you don't get in an implicit getter or setter:
class Car {
int _doors = 4;
int get doors => _doors;
set doors(int numberOfDoors) {
if(numberOfDoors >= 2 && numberOfDoors <= 6) {
_doors = numberOfDoors;
}
}
}
The getter and setter functions allow us to make the class appear to have a property, without a explicit property being declared (_doors in your case). The property value may be calculated from other properties.
The getters and setters allow us to execute arbitrary code when the property is get or set.
Omitting a setter makes the property immutable.
An abstract class may declare getters and setters without bodies as part of a required class interface.

Why does this error occur: The instance member '*' can't be accessed in an initializer."?

I come from a python-background trying to learn java-like languages. This is written in dart for use with flutter.
I get an error when I try to run the following.
class _MyGameState extends State<MyGame> {
int _numberOfTeams = 4;
List<int> _teamPoints = List.filled(_numberOfTeams, 0);
The error message I get is:
The instance member '_numberOfTeams' can't be accessed in an initializer.
Try replacing the reference to the instance member with a different expression
Why is that, and how does one avoid it? (Obviously, this example is simplified and i could easily simply omit the variable _numberOfTeams and circumvent the problem, but that's not the point.)
(There are a lot of very similiar questions on here. All the answers to those questions offers ways to cicrumvent the specific problem, but not "why" the problem occurs or how to think when writing in languages where this is common. A few relevant search words that I could look into, or a link to a guide/tutorial/article would be very appreciated :)
As you are inside an object and not in a method the attributes _numberOfTeams and _teamPoints can't rely on other attributes to be created because they might not be initialized yet.
See the following example, yes it's a little silly but is the same situation for the compiler, it can't guarantee that one is created before the other.
List<int> _teamPoints = List.filled(_numberOfTeams, 0);
int _numberOfTeams = _teamPoints.length;
Workarounds
Make the attribute static
Make the dependant value static:
static int _numberOfTeams = 4;
If inside a class you could use an initializer list
class TeamList {
int _numberOfTeams;
List<int> _teamPoints;
TeamList(
this._numberOfTeams,
) : _teamPoints = List.filled(_numberOfTeams, 0);
}
If inside State you could #override initState
class _HomeState extends State<Home> {
int _numberOfTeams = 4;
late List<int> _teamPoints;
#override
void initState() {
super.initState();
_teamPoints = List.filled(_numberOfTeams, 0)
}
I would prefer approaches 2 or 3 because they are still instances of your objects internal state, you just defer a little bit its creation.
There is more info in dart.dev

instantiate object with *new* keyword and use property inside class with *this* keyword

i'm coming from mainly JS/TS world (NestJS/Angular) and recently i start to building Flutter apps..
i have 2 main questions
there is any difference when instantiate object with or without new keyword?
i saw examples in flutter when people use new Row(children: [Text('Foo'), Text('Bar'),],) instead of just Row(...)
if there is a difference which one is better to use?
inside of my Dart classes in flutter app, i can both use this.property and property again there is any difference and if so which one is better and why?
example:
class Person {
final String name;
final int age;
Person(this.name, this.age);
getNameAge() => '${this.name} is ${this.age}';
getNameAge2() => '$name is $age';
}
both looks the same to me
void main() {
final p = Person('dan', 22);
final p2 = new Person('ben', 20);
print(p.getNameAge()); // dan is 22
print(p2.getNameAge2()); // ben is 20
}
The new keyword is optional in Dart and I think the general consensus is, today, to not use it.
The use of this is useful if you have multiple variables with the same name but in different scope. E.g. (this is just an example. You would not make a setA method in Dart but use properties):
class A {
int a;
A(this.a);
void setA(int a) {
this.a = a;
}
}
Here we use this to distinguish between the argument a and the class variable a. But if you don't have variables with the same name (but in different scope), the use of this is optional. In some projects, you still use this to make it more clear that you are referring to a class variable even if it is not needed.

Using Setters with Constructors in Dart

How can I use the setter of a private instance variable from the default constructor in Dart?
Given the example class:
class A {
String name;
int _age;
int get age => _age;
set age(age) {
_age = age ?? 0;
}
A(this.name, this._age);
}
How can I use this constructor to go through the set age() function? Is there away aside from using a factory? I'd like to do something like this
A(this.name, newAge): age = newAge;
But I get an error forcing me to only set instance variables from the constructor, which has me just duplicating the setter:
A(this.name, newAge): _age = newAge ?? 0;
Am I missing something or is this just not possible with dart?
The initialization list of a constructor can be used only to initialize members (or call base class constructors). (Additionally, when the initialization list is executed, this isn't valid yet, so you can't access any members.)
If you want to do other kinds of initialization work, you can do it in the constructor body instead, at which point the object is considered to be sufficiently constructed for this to be valid:
A(this.name, int newAge) {
age = newAge;
}
Also see:
Difference between assigning the values in parameter list and initialiser list, which explains why this becomes valid only for the later stages of object initialization.
https://stackoverflow.com/a/64548861/ for various differences between the different ways to initialize members and for an example where the different ways matter.

How to observe field variable of other class in Mobx flutter?

I am using the flutter Mobx for state management.
I have a simple class:-
class A {
int x;
A(this.x);
}
How can I observe if x changes inside the class in another Mobx store:-
class MyStore extends _MyStore with _$MyStore {
Subs(A a) : super(a);
}
abstract class _MyStore with Store {
#observable
A a;
_Subs(this.a)
}
I want MyStore to observe the a.x.
Is it possible, if yes how?
I ran in to the same issue the other day using flutter mobx ^1.2.1+3 (dart) and
flutter_mobx ^1.1.0+2.
The first thing that comes to my mind is to annotate the field in question, I.e x with the #observable attribute. But it doesn't seem to be effective outside a store class.
So you have to observe the field using the Observable class.
To make it work your code should look something like this:
class A {
//replace with less verbose "var"
Observable<int> x = Observable(0);
A(this.x);
}
class MyStore extends _MyStore with _$MyStore {
Subs(A a) : super(a);
}
abstract class _MyStore with Store {
A a;
_Subs(this.a)
//Will be calculated whenever a change to a.x is observed.
#computed
int get xSquare => a.x.value * a.x.value;
}
As you can see I removed the observable attribute from a, since it does not need to be observed if you want to react to changes to a.x in your store. You probably noticed that you have to access the value of the observable using .value.
That should conclude how you observe a field of a class external to the store, inside your store.
I am not sure that this would be helpful since it is Javascript/Typescript, but that's what I would do :
class Foo {
#observable name = 'foo'
}
class Bar {
foo: Foo
constructor(instanceOfFoo) {
this.foo = instanceOfFoo
autorun(() => {
// Logs foo name when it changes
console.log(this.foo.name)
})
reaction(
() => this.foo.name,
() => {
// Logs foo name when it changes
console.log(this.foo.name)
}
)
}
#observable
name = 'bar'
#computed
get fooNamePlusBarName {
// recomputes automatically whenever foo or bar name changes
return this.foo.name + this.name
}
}
Basically you pass Foo instance to the Bar constructor (or just use imported singleton if it fits you), then you have 3 options: computed, reaction and autorun