I'm using Flutter web. I have a javascript class with methods. I can call the constructor from Dart with package:js, and I can access members with getters, but when I try to call a class method I get a NoSuchMethodError. How do I make the class methods available to Dart?
In my index.html I have this in a script block:
class TestClass {
constructor(val) {
this.foo = val;
console.log("TestClass constructed with foo="+this.foo);
}
someGenericFunction() {
console.log("generic");
}
getSomeValue(foo, bar) {
return this.foo+" "+foo+" "+bar;
}
}
This is my Dart interop code:
#JS()
library testclass.js;
import 'package:js/js.dart';
#anonymous
#JS()
abstract class TestClass {
external factory TestClass({String foo});
external String get foo;
external void someGenericFunction();
external String getSomeValue(String foo, String bar);
}
Here's my Dart code:
TestClass ts = TestClass(foo: "dart"); //Works!
String foo = ts.foo; //Works!
//The below methods error with:
//JSNoSuchMethodError (NoSuchMethodError: tried to call a non-function...)
ts.someGenericFunction();
ts.someGenericFunction.call();
String testClassString = ts.getSomeValue("one", "two");
The constructor works and the getter works. How do I correctly expose the TestClass methods?
Related
In PHP there is a way of accessing a static property value that is defined/overridden on an inheritor.
e.g.
class Foo {
public static $name='Foo';
public function who(){
echo static::$name;//the static operator
}
}
class Bar extends Foo {
public static $name='Bar';
}
$bar = new Bar();
$bar->who();
//Prints "Bar";
Is there ANY way of doing the exact same thing in Dart language?
Addressing comments:
About making it instance prop/method: There's a reason for the existence of static properties and methods and it's not having to create a new instance of the object to access a value or functionality that is not mutable.
Yes, but that's not how you are using it. Your use case is to invoke the method on an object, and therefore you really want an instance method. Now, some languages automatically allow invoking class methods as instance methods, and I see two choices for a language that offers that ability:
Statically transform fooInstance.classMethod() to ClassFoo.classMethod() based on the declared type (not the runtime type) of the object. This is what Java and C++ do.
Implicitly generate virtual instance methods that call the class method. This would allow fooInstance.classMethod() to invoke the appropriate method based on the runtime type of the object. For example, given:
class Foo {
static void f() => print('Foo.f');
}
You instead could write:
class Foo {
static void classMethod() => print('Foo.f');
final instanceMethod = classMethod;
}
and then you either could call Foo.classMethod() or Foo().instanceMethod() and do the same thing.
In either case, it's syntactic sugar and therefore isn't anything that you couldn't do yourself by being more verbose.
About the "meaning of static" and "only work because they allow invoking class methods as instance methods" : That affirmation is actually wrong. In the case of PHP, as per the example above, the Language is providing a way to access the TYPE of the class calling the method in the inheritance chain. A(methodA) >B > C. When C calls methodA, PHP allows you to know that the class type you're in is indeed C, but there's no object instance attached to it. the word "static" there is a replacement for the caller class type itself
All of that is still known at compilation time. That C derives from B derives from A is statically known, so when you try to invoke C.methodA, the compiler knows that it needs to look for methodA in B and then in A. There's no dynamic dispatch that occurs at runtime; that is still compile-time syntactic sugar. That is, if you wanted, you could explicitly write:
class A {
static void methodA() {}
}
class B extends A {
static void methodA() => A.methodA();
}
class C extends B {
static void methodA() => B.methodA();
}
Anyway, in your example, you could write:
class Foo {
static String name = 'Foo';
String get nameFromInstance => name;
void who() {
print(nameFromInstance);
}
}
class Bar extends Foo {
static String name = 'Bar';
#override
String get nameFromInstance => name;
}
void main() {
var bar = Bar();
bar.who(); // Prints: Bar
}
class Car {
var name;
var model;
var cc;
Car(this.name, this.model, this.cc);
printAll() {
print(name);
print(model);
print(cc);
}
print(name); //Showing Error
}
void main() {
var obj = Car("Marcedes", "Class E", 5000);
obj.printAll();
}
Why i can't do any kind of operation outside the method body. The code generates error in compilation which given bellow. The code write in Dartpad.
Error in Compilation. The output show
Error compiling to JavaScript:
main.dart:1:7:
Error: The non-abstract class 'Car' is missing implementations for these members:
You have declared a method named print with a parameter called name but without a method body, i.e. an abstract method. In order to instantiate a class, Dart obviously has to know what the method body is, therefore you cannot instantiate an abstract class.
You need to do two things:
Because you have an abstract method, and abstract methods are only allowed in abstract classes, you need to mark Car as abstract.
You need to create a subclass of Car that overrides print with an implementation, and then instead instantiate that class.
Something like this:
abstract class Car {
var name;
var model;
var cc;
Car(this.name, this.model, this.cc);
printAll() {
print(name);
print(model);
print(cc);
}
print(name); // Abstract method `print` with no implementation
}
class ConcreteCar extends Car {
ConcreteCar(name, model, cc): super(name, model, cc);
#override
print(name) {
// Implementation of `print`
}
}
void main() {
var obj = ConcreteCar("Mercedes", "Class E", 5000);
obj.printAll();
}
Note: I left the implementation of print empty because I didn't understand the reason for the abstract print method and what the goal of the design is. But it should be trivial for you to fill out the missing pieces.
I have a singleton class and I would like to refer to it from within itself, however I am getting a CyclicInitializationError (Reading static variable 'instance' during its initialization) when trying to do so.
Here is an example:
void main(){
Singleton newSingleton = Singleton();
print(newSingleton.member);
}
class Singleton {
static final instance = Singleton._internal();
Singleton._internal();
factory Singleton(){
return instance;
}
String member = "hello";
String hamburger = instance.member; // This line causes the error to be thrown
}
Is there a reason why using json_serializable I should use a factory constructor instead of a static method?
I would need to use a static method, but I'm wondering about the downsides
Using factory has a purpose here:
it forces you to define
factory counts as a constructor, so if you define at least one then there's no implicit constructor:
class Foo {
factory Foo.fromJson() {
return Foo(); // Doesn't compile
}
}
Which is opposed to:
class Foo {
static Foo.fromJson() {
return Foo(); // compiles
}
}
have class Klass with static method fn1
class Klass {
static String fn1() => 'hello';
}
> Klass.fn1(); // hello
but when Klass is assigned to a variable, calling the method fn1 fails
var k = Klass;
> k.fn1() // "Unhandled exception: Class '_Type' has no instance method 'fn1'.
don't quite know what's going on here
A simple workaround
class Klass {
static fn1(String name) {
return name;
}
fn1NonStatic(String name) {
return fn1(name);
}
}
Klass().fn1NonStatic("test");
I'm not sure what the intent of the code here is, but you might want to use dart:mirrors to reflectively call fn1(). I don't believe you can invoke it by assigning Klass to a variable. Here is how you can do it:
import 'dart:mirrors';
class Klass {
static String fn1() => 'hello';
}
main() {
final mirror = reflectClass(Klass);
print(mirror.invoke(#fn1, []).reflectee); // Prints 'hello'.
}