Register Polymer Class Name - dart

So i've been trying to add a PolymerElement dynamically to an other PolymerElement.
MyPolyElem newRow = new MyPolyElem();
(newRow as MyPolyElem).type = type; // -> Exception
panelBody.append(newRow);
Exception: Uncaught Error: type 'HtmlElement' is not a subtype of type 'MyPolyElem ' in type cast.
If I try to access type, it says that newRow is a HtmlElement and does not have "type". If I try to cast it, is says that its not a subtype of HtmlElement.
#CustomTag('poly-elem')
class MyPolyElem extends PolymerElement {
#published String type = "int";
void attached() {
super.attached();
}
factory MyPolyElem() => document.createElement("poly-elem");
MyPolyElem.created() : super.created() {}
}
Apparently, if i create a Polymer Element dynamically, its a HtmlElement. If i would write in the the HTML as tag and query for it, its a MyPolyElem. So i'd like to know how i could register the Name of the Class for this Tag.

Dynamically created elements can be cast like declaratively added elements.
I'm pretty sure this doesn't work in your case because Polymer is not yet fully initialized.
See how to implement a main function in polymer apps for how to initialize Polymer properly when you have a custom main() method.
I never used document.createElement() to create a Polymer element dynamically. I used new Element.tag('xxx-yyy') instead. If the main() method is not the cause you might try this (see also Dynamically create polymer element)
Even though you create it dynamically you need to add an import like when you add it decoratively.

Related

Type safety in Dart using Container

I found something strange in dart. If there is a list that contains instances of a base class (in this example Super), the list can be set with a list of inherited instances. It seems that this changes the list type at runtime.
Is this intended behavior or is this a bug in Dart?
abstract class Super {}
class A extends Super {}
class B extends Super {}
class Container {
List<Super> mylist = [];
Container(this.mylist);
}
void main() {
// 1. dont't works
final container = Container(<A>[A(), A()]);
// 2. works
final container = Container([A(), A()]);
print(container.mylist.runtimeType);
container.mylist.add(B());
print(container.mylist);
}
If case 1 is used in the code above I get the following error:
JSArray<A>
Uncaught Error: TypeError: Instance of 'B': type 'B' is not a subtype of type 'A'
The error is at the line where I try to add an instance of B:
container.mylist.add(B());
Dart has a system called type promotion, where it can promote the type of a variable, similar to type inference.
It works as a cast. On the first example you've explicit promoted the type of your list to be of type A, so there's nothing strange about this.
Take a look at the first article that explains this mechanism.
When you do:
final container = Container(<A>[A(), A()]);
you explicitly create a List<A> object. Although Container's constructor expects a List<Super>, it accepts a List<A> argument because Dart considers Generic<Derived> to be a subtype of Generic<Base> if Derived is a subtype of Base. Your later attempt to do container.mylist.add(B()); will fail because container.mylist is actually a List<A> and therefore cannot legally store any B elements.
When you instead do:
final container = Container([A(), A()]);
then, because the List literal is not given an explicit type, its type is inferred to be List<Super> from Container's expected construction parameter. container.mylist.add(B()); will succeed since container.mylist is actually a List<Super> and therefore can legally store B elements.

Dart gives Unhandled Exception: type is not a subtype of type of 'value'

I have an abstract class ImageUpdate. Two classes, NewImage and ExistingImage implement ImageUpdate.
I have a variable imageUpdates of type List<ImageUpdate>.
When I try adding a variable of type NewImage to the List, I get this error:
Unhandled Exception: type 'NewImage' is not a subtype of type 'ExistingImage' of 'value'
I am pretty stumped, since the list is of ImageUpdate and not ExistingImage, so I have no idea how to debug it, especially since Dart is type safe (nowhere am I using dynamic).
I suspect that you have code similar to:
class Base {}
class Derived1 extends Base {}
class Derived2 extends Base {}
List<Base> makeList() {
var list = [Derived1()];
return list;
}
void main() {
var list = makeList();
list.add(Derived2()); // TypeError
}
What happens is that the List object is originally created as a List<Derived1>. (That is, list.runtimeType will be something like List<Derived1>, not its static (declared) type of List<Base>.) Then, when you try to add a Derived2 object to list, it will fail at runtime because list's actual, runtime type is List<Derived1>, which does not allow Derived2 elements.
This ultimately stems from Dart allowing implicit type conversions from GenericClass<Derived> to GenericClass<Base> if Derived derives from Base. This is useful in many cases, but it also can lead to situations like this one that fail at runtime.
You can fix this by explicitly stating that you want a List<Base> object:
List<Base> makeList() {
var list = <Base>[Derived1()]; // Note the explicit type.
return list;
}
or, if that's not possible, by creating a new List<Base> object:
var list = <Base>[...makeList()];
var list = List<Base>.from(makeList());
(In this particular situation, List.of(makeList()) also would work since it would create a new List object with the static type, but I wouldn't use that since being explicit about the type conversion would be more readable.)

How to get subtypes using `DartType` class from the `analyzer`?

How can I get the subtypes of an element using the class DartType from the analyzer package?
For those wondering, the DartType class is a statically resolved type that is created by the analyzer package, Dart's static tooling package. The author is asking how they can get other types given a DartType - I think you mean super types, i.e. types that you inherit or implement.
(If you simply wanted to check if the DartType is a subtype of something, you could use isSubtypeOf)
We can get a hold of the Element that the DartType originates from, and then, if it is a ClassElement, simply return all of the super types, otherwise perhaps default to an empty list:
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
/// Returns all sub-types of [type].
Iterable<DartType> getSubTypes(DartType type) {
final element = type.element;
if (element is ClassElement) {
return element.allSupertypes;
}
return const [];
}
This is in analyzer version 0.29.3.

Polymer 1.0 change fields of the Dart objects within themselves to reflect to polymer

Good day. I seem to be having issues being able to have value changes within a Dart Object created by extending JsProxy being reflected to the data binding in a Polymer element. See Below
person.dart
class Person extends JsProxy {
#reflectable
String name;
Person() {
name = "temp";
}
void changeVar(){
name = "Matthew";
}
}
my_element.dart
#PolymerRegister('my-element')
class MyElement extends PolymerElement{
//Runner Object
#property Person person = new Person();
//Constructor
MyElement.created() : super.created(){ }
my_element.html
<div>
[[person.name]]
</div>
Now I want to be able to call changeVar() within its own object and have it reflect on the Polymer element. If I print the variable out after calling changeVar() it does show the new value but that value is not reflected within the Polymer element.
Currently the only way I have found to have it change is to use set('person.name', "matthew") from within the elements dart file. However I would prefer not to have to implement it there.
Polymer needs to be notified about the change. That's what set() or notifyPath() or some other Polymer API methods do.
I haven't tried https://pub.dartlang.org/packages/polymer_autonotify but it seems to address your problem.

Is it possible to declaratively bind a CustomEvent handler when using Dart Web UI WebComponents?

I've tried to bind a custom event handler to a WebComponent that has an EventStreamProvider exposed via a getter, but it comes back with "Class 'DivElement' has no instance getter 'onMainAction'.".
Trimmed down component .dart code...
import 'dart:html';
import 'dart:async';
import 'package:web_ui/web_ui.dart';
class SegmentedButtonsListComponent extends WebComponent {
static const EventStreamProvider<CustomEvent> mainActionEvent = const EventStreamProvider<CustomEvent>("MainActionEvent");
Stream<CustomEvent> get onMainAction => mainActionEvent.forTarget(this);
}
Trimmed usage of component…
<x-segmented-buttons-list id="segmented-buttons-list" on-main-action="eventHandler($event)"></x-segmented-buttons-list>
Trimmed code from main.dart…
import 'dart:html';
import 'dart:async';
import 'package:web_ui/web_ui.dart';
const EventStreamProvider<CustomEvent> mainActionEvent = const EventStreamProvider<CustomEvent>("MainActionEvent");
void eventHandler(CustomEvent event) {
print("""
Yabba Dabba Doo!
Type: ${event.type}
Detail: ${event.detail}
""");
}
void main() {
mainActionEvent.forTarget(query('#segmented-buttons-list')).listen(eventHandler);
}
The "MainActionEvent" custom events are being dispatched by components instantiated within this "list" component.
As you can see from the above example I can catch the events if I create an EventStreamProvider in main.dart and target the component, that works fine (but by-passes the Stream getter in the component).
It would be great though if I could dispense with the EventStreamProvider in main.dart and simply bind to the onMainEvent getter on the component.
Is that possible?
Update 2013-05-05:
Siggi explains below that at present it is not possible to do this, but there is a way to reference the component's CustomEventProvider's getter via the element's xtag.
I found that I had to use a Timer to query the DOM after main() has completed because xtags aren't populated until the main() event loop has finished.
void postMainSetup() {
query('#segmented-buttons-list').xtag.onMainAction.listen(eventHandler);
}
void main() {
Timer.run(postMainSetup);
}
With the above setup a new CustomEventProvider isn't needed to monitor the component.
Good question!
I see a couple parts to this question:
using custom events directly on a component: Currently web_ui uses different objects to represent your component and the actual dom element it represents. In the future, we plan to extend directly from "DivElement" instead of "WebComponent" and that will allow you to do what you wrote.
Meanwhile, you'll have to be more explicit when you want to use the host or shadow root of your component. In your example, it seems like you want to attach the event to the host, so you would need to write something more like this:
Stream<CustomEvent> get onMainAction => mainActionEvent.forTarget(this.host);
using 'on-someting-foo' syntax in a component: you probably found a bug/missing feature =). Currently we treat attributes in a special way and bind their values to fields of a component if we identify that the target was corresponds to a component. We do this for value bindings, but not yet for binding custom events. A workaround before this feature is added, would be to query for your element and attach the event by hand:
query('#host-node').xtag.onMainAction.listen(...);

Resources