Working with flutter I'm straggling with notifying a model class parameters about changes coming from the firestore DB.
I'm trying to use plugin property_change_notifier
Using the example:
// ignore: mixin_inherits_from_not_object
class MyModel with PropertyChangeNotifier<String> {
int _foo = 0;
int _bar = 0;
int get foo => _foo;
int get bar => _bar;
set foo(int value) {
_foo = value;
notifyListeners('foo');
}
set bar(int value) {
_bar = value;
notifyListeners('bar');
}
}
I've added the ignore remark and even tried to set the analysis_option.yaml with this rule
I still get the message:
The class 'PropertyChangeNotifier' can't be used as a mixin because it extends a class other than Object.dart(mixin_inherits_from_not_object)
When I try to build the project it then shows the following error:
- 'BuildContext' is from 'package:flutter/src/widgets/framework.dart' ('/C:/ngplayground/flutter/packages/flutter/lib/src/widgets/framework.dart').
Try correcting the name to the name of an existing method, or defining a method named 'ancestorWidgetOfExactType'.
return nullCheck(context.ancestorWidgetOfExactType(type) as PropertyChangeModel);
^^^^^^^^^^^^^^^^^^^^^^^^^
2
FAILURE: Build failed with an exception.
* Where:
Script 'C:\ngplayground\flutter\packages\flutter_tools\gradle\flutter.gradle' line: 991
* What went wrong:
Execution failed for task ':app:compileFlutterBuildDebug'.
What is wrong here?
you just need to change
class MyModel with PropertyChangeNotifier<String>
to
class MyModel extends PropertyChangeNotifier<String>
and it should work
Related
I'd like to have a property which is settable only once and then ignores further attempts to set it, so noone can accidentally set or reset the value.
I know that late can "kinda" do this, but when using late, neither the compiler, nor the IDE tell me that calling doOther() after calling doOnce() will cause an exception.
class Foo {
bool? _bar;
void doOnce() {
if (_bar == null) {
_bar = true;
print('done this once');
}
}
void doOther() {
_bar = false; // this should not be possible when doOnce() is done
print('done other');
}
}
void main() {
Foo foo = Foo();
foo.doOnce();
}
Using late final is as close as it gets:
class Foo {
late final int a;
Foo();
void doThing() {
a = 5;
}
void doAnotherThing() {
a = 3;
}
}
...
void main() {
final foo = Foo();
// Uncaught Error: LateInitializationError: Field 'a' has not been initialized.
// print(foo.a);
foo.doThing();
// Prints: 5
print(foo.a);
// Uncaught Error: LateInitializationError: Field 'a' has already been initialized.
// foo.doAnotherThing();
}
This gives you the runtime behavior you are looking for, but there is no solution that gives you static compile-time checking for assigning to a late (or late-ish) variable twice. That's because in order to know that your program is attempting to do so, the compiler would have to inspect every path of your program that could possibly assign to the late variable which could take a really long time.
In short, you are going to have to practice your own due diligence instead on relying on the compiler or static analyzer to inform you of your mistakes.
what I want is an annotation like #required but I want to do some logic based on the type of parameter and show the use a warning like what #required does.
(if type is ParamTuple shows the warning)
abstract class Tuple {
const Tuple();
}
abstract class NullTuple extends Tuple {
const NullTuple();
}
abstract class ParamTuple extends Tuple {
const ParamTuple();
}
I want to warn user if the type is ParamTuple but in other cases I don't want warning.
In the code below, the logic should be implemented
const TupleRequired tupleRequired = TupleRequired();
class TupleRequired {
const TupleRequired();
}
also I think that I should add an analysis_options.yaml to show warning like #required for my #tupleRequired.
EXAMPLE OF WHAT I WANT
class Example {
// Tuple0 extends NullTuple
void nullParam({#tupleRequired Tuple0 param}) {}
// Tuple1 extends ParamTuple
void withParam({#tupleRequired Tuple1 param}) {}
}
so when we want to use these methods, I want to see the below custom warning:
nullParam : if I put it empty , shows nothing but if I pass an argument shows the argument is redundant and will be ignored
withParam : if I put it empty , shows warning to pass argument and if I pass an argument shows nothing
In the constructor You can use assert like:
class TupleRequired {
final Tuple touple;
TupleRequired(this.touple): assert(touple is! ParamTuple);
}
in dart is/is! checks if an object is of specific type like for example
var s = 'this is a string type';
print(s is String); // prints true because s is string
print(s is! int); // prints true because s is not an int
Whenever I try to run flutter packages pub run build_runner watch I get this error message in the Terminal
Failed to precompile build_runner:build_runner:
/C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/dart_style-1.3.3/lib/src/dart_formatter.dart:105:30: Error: Too
many positional arguments: 0 allowed, but 1 found.
Try removing the extra positional arguments.
scanner.configureFeatures(featureSet);
^
pub finished with exit code 1
this happend after i update moor_flutter plugin from ^1.6.0 => ^ 3.0.0
There is no errors with the older plugin
This is my code
import 'package:moor_flutter/moor_flutter.dart';
part 'Database.g.dart';
class Users extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get name => text().withLength(min:1,max:50)();
TextColumn get mobile => text().withLength(min:1,max:25)();
DateTimeColumn get birthdate => dateTime()();
}
#UseMoor(tables : [Users ],daos:[UserDao])
class AppDatabase extends _$AppDatabase {
AppDatabase():super(FlutterQueryExecutor.inDatabaseFolder(path: 'db.sqlite',
logStatements: true));
#override
int get schemaVersion =>1;
}
#UseDao(tables:[Users ],)
class UserDao extends DatabaseAccessor<AppDatabase> with _$UserDaoMixin{
final AppDatabase db;
UserDao(this.db):super(db);
Future <List<User>> getAllUsers() => select(users).get();
Stream <List<User>> watchAllUsers() {
return (select(users)
..orderBy([
(p)=> OrderingTerm(expression:p.id,mode:OrderingMode.desc ),
// (p)=> OrderingTerm(expression:p.id,mode:Ordering.desc )
])
)
.watch();
}
Stream <List<User>> watchUsersByName(String txt) {
String qu="SELECT * FROM users where ";
for (int i = 0; i < txt.length-1; i++){
String c = txt[i];
qu=qu+"name like '%"+c+"%' and ";
}
qu=qu+"name like '%"+txt[txt.length-1]+"%' ORDER BY id DESC";
return customSelectStream(
qu,readsFrom: {users}
).map((rows){
return rows.map((row) => User.fromData(row.data,db)).toList();
});
}
Future insertUser(Insertable<User> user) => into(users).insert(user);
Future updateUser(Insertable<User> user) => update(users).replace(user);
Future deleteUser(Insertable<User> user) => delete(users).delete(user);
}
the vs code gives me errors in the Appdatabase constructor and customselectstream function but
I searched the example in their Github repository and found the Appdatabase constructor is the same as mine.
The problem still presists after I commented the watchusersbyname also I tried to remove the arguments from super in the Appdatabase constructor but nothing changed
so can you please tell me what is the problem?
Thanks in advance.
Here is the one command which you need to run and check for the solution
flutter pub upgrade
I made a class and not sure why my getter is fine but the setter is showing as not defined in flutter.
class Test {
int range = 1000;
set setRng(int val) => range = val;
get getRng => range;
}
Test.getRng no errors..
Test.setRng(100) throws the error The method 'setRng' isn't defined for the class 'Test'
Clearly they're both defined..?
In Dart, you invoke setters with setter = value;. So your code can be modified like this:
test.setRng = 0;
Getters and setters make member functions look like member variables. By convention, they can then have variable like names, for example:
class Test {
int _range = 1000;
set range(int val) => _range = val; // optionally perform validation, etc
int get range => _range;
}
now it looks more natural when you use:
test.range = 123; // using the setter
print(test.range); // using the getter
I have API communication service in my Flutter app with 10+ different services, and 100+ API calls that heed to parse data. In order to reuse code I've decided to create some common parsing code that is going to parse data from API:
ApiResponse handleObjectResponse({
#required http.Response serverResponse,
#required Function objectConstructor,
}) {
if (serverResponse.statusCode == 200) {
dynamic responseObject = objectConstructor(json.decode(serverResponse.body));
return ApiResponse(responseObject: responseObject);
} else {
ApiError error = responseHasError(serverResponse.body);
return ApiResponse(error: error);
}
}
This way I am able to parse JSON object from API in a reusable way no matter what the Object class is, just by passing constructor function to this method.
When I call this method in any of the Services I've created for fetching data like this:
handleObjectResponse(serverResponse: response, objectConstructor: ChartData.fromJson);
I get error: The getter 'fromJson' isn't defined for the class 'ChartData'.
Try importing the library that defines 'fromJson', correcting the name to the name of an existing getter, or defining a getter or field named 'fromJson'.
Where I think the problem is is in this model class and factory statement, but I don't know how to fix it:
class ChartData {
List<ChartDataPoint> points;
ChartData({
this.points,
});
factory ChartData.fromJson(Map<String, dynamic> json) {
List jsonPoints = json["data"];
return ChartData(
points: List.generate(jsonPoints.length,
(i) => ChartDataPoint.fromJsonArray(jsonPoints[i])));
}
}
You cannot pass constructors as functions. You need to create a function what will call the constructor instead:
(int a) => Foo(a);
Just a 2022 update: since 2.15 it's possible by Class.new, see the complete issue: https://github.com/dart-lang/language/issues/216.
class A {
final String a;
const A(this.a);
#override
String toString() => 'A($a)';
}
class B {
final String b;
const B(this.b);
#override
String toString() => 'B($b)';
}
void main() {
final List<Object Function(String)> constructors = [A.new, B.new];
for (final Object Function(String) constructor in constructors) {
final Object instance = constructor('My Constructor Parameter');
if (instance is A) {
print(instance.toString());
}
}
}
Note that if you're using named params, both class constructors must have the same param name, otherwise the constructor signatures won't match and then it will generate this static error:
The element type X can't be assigned to the list type Y.