I have two dart polymer components defined: an input and a list
This looks a little something like this:
#CustomTag('input-button')
class Input extends PolymerElement {
#observable String value = '';
Input.created() : super.created();
void blah(Event e, var detail, Node target) {
someMethodCallToTheOtherObject(value);
}
}
and the other element:
#CustomTag('page-content')
class PageContent extends PolymerElement {
final List<String> values = stuff;
PageContent.created() : super.created();
someMethodCallListerningForEventInOtherObject(String value) {
values.add(value);
}
}
As demonstrated in the code, I'm trying to set up and ActionListerner so that when one method is "fired" in the first button object, it calls a method in the second object with given parameters.
I know this might be a little of the basic side, but I haven't see this concept really well documented anywhere. Any input you could give to point me in the right direction would be appreciated.
Thanks!
You can query for one element and add an event listener
(querySelector(' /deep/ page-content') as PageContent)
.someMethodCallListerningForEventInOtherObject(value);
as PageContent is not necessary but it enables autocompletion.
You also need to import the file that contains the PageContent class to make this work.
or you can use an element like core-signals or a number of other possible variants depending on how your elements are organized (see my comments to your question).
Related
So, basically I need to create restrictions of which types can be used in a Type variable, something like this:
class ElementFilter<T extends Element> {
final Type<T> elementType; // What I want is something like Type<T>, but Type does not have a generic parameter
ElementFilter(this.elementType);
}
List<T> filterElements<T extends Element>(ElementFilter<T> element) {
return elements.where((el) => _isOfType(el, element.type)).toList();
}
filterElements(ElementFilter(ClassThatExtendsElement)); // Would work fine
filterELements(ElementFilter(String)); // Error, String does not extends Element
So it would only be possible to create ElementFilters with types that extend Element. Is this possible in some way?
I think you probably want:
/// Example usage: ElementFilter<ClassThatExtendsElement>();
class ElementFilter<T extends Element> {
final Type elementType;
ElementFilter() : elementType = T;
}
Unfortunately, there's no way to make the generic type argument non-optional. You will have to choose between having a required argument and having a compile-time constraint on the Type argument.
Dart doesn't support algebraic types, so if you additionally want to support a finite set of types that don't derive from Element, you could make specialized derived classes and require that clients use those instead of ElementFilter. For example:
class StringElementFilter extends ElementFilter<Element> {
#override
final Type elementType = String;
}
(You also could create a StringElement class that extends Element if you want, but at least for this example, it would serve no purpose.)
I highly recommend not using Type objects at all. Ever. They're pretty useless, and if you have the type available as a type parameter, you're always better off. (The type variable can always be converted to a Type object, but it can also be actually useful in many other ways).
Example:
class ElementFilter<T extends Element> {
bool test(Object? element) => element is T;
Iterable<T> filterElements(Iterable<Object?> elements) =>
elements.whereType<T>();
}
List<T> filterElements<T extends Element>(ElementFilter<T> filter) =>
filter.filterElements(elements).toList();
filterElements(ElementFilter<ClassThatExtendsElement>()); // Would work fine
filterElements(ElementFilter<String>()); // Error, String does not extends Element
I begin with Dart and I would like to extend RectElement class to create a MyRectElement class which is able to move rectangle in SVG area :
import 'dart:html';
import 'dart:svg';
class MyRectElement extends RectElement{
int xOrigin;
int yOrigin;
factory MyRectElement() {
}
}
void main() {
var rect = new MyRectElement();
var container = querySelector("#container");
container.append(rect);
}
But RectElement has a factory constructor.
I must admit that I don't understand factory constructor even if I read lots of posts about it...
What should I put in MyRectElement factory contructor ?
Extending just the class is not supported.
You can build a Polymer element that extends a DOM element or if you don't want to use Polymer this question should provide some information Is it possible to create a Polymer element without Html?
In order to communicate from child to parent, events seem to be the most elegant way.
What are the options to communicate from parent to child?
More specifically, I want a method called in a child when it becomes visible.
These are the ideas I came up with:
xtag - elegant and works
observing 'hidden' - didn't manage to get this working, hidden is not marked as observable in Element
publishing a trigger variable in child, binding and changing it in parent - ugly
Are there any other options?
I have not tried it yet but maybe MutationObserver does what you want.
Seth Ladd's polymer examples containes two examples:
The first listens to the onMutation event
https://github.com/sethladd/dart-polymer-dart-examples/blob/master/web/onmutation-mutation-observer/my_element.dart
library my_element;
import 'package:polymer/polymer.dart';
import 'dart:html';
import 'dart:async';
#CustomTag('my-element')
class MyElement extends PolymerElement {
MyElement.created() : super.created() {
// NOTE this only fires once,
// see https://groups.google.com/forum/#!topic/polymer-dev/llfRAC_cMIo
// This is useful for waiting for a node to change in response
// to some data change. Since we don't know when the node will
// change, we can use onMutation.
onMutation($['list']).then((List<MutationRecord> records) {
$['out'].text = 'Change detected at ${new DateTime.now()}';
});
new Timer(const Duration(seconds:1), () {
$['list'].children.add(new LIElement()..text='hello from timer');
});
}
}
the second example uses the MutationObserver class
https://github.com/sethladd/dart-polymer-dart-examples/blob/master/web/mutation_observers/my_element.dart
=== edit ===
Have you tried the linked example?
The observe method allows to specify what should be observed:
/**
* Observes the target for the specified changes.
*
* Some requirements for the optional parameters:
*
* * Either childList, attributes or characterData must be true.
* * If attributeOldValue is true then attributes must also be true.
* * If attributeFilter is specified then attributes must be true.
* * If characterDataOldValue is true then characterData must be true.
*/
void observe(Node target,
{bool childList,
bool attributes,
bool characterData,
bool subtree,
bool attributeOldValue,
bool characterDataOldValue,
List<String> attributeFilter}) {
To communicate from parent polymer to child polymer , this solution works good for me.
If we have a child polymer element like this:
library my_element;
import 'package:polymer/polymer.dart';
import 'dart:html';
import 'dart:async';
#CustomTag('my-element')
class MyElement extends PolymerElement {
MyElement.created() : super.created() {
}
myCustomMethod(param){
print("pass-in param = $param");
}
}
To access to your child element from parent:
Query your child polymer element in parent element (yes, access to the HTML element first)
Cast it to the binding Class (ex: MyElement.dart in our case)
(theParentClass.querySelector("my-element") as MyElement).myCustomMethod({"done":true});
I would like to implement an observer pattern in Dart but I'm not sure how to go about it.
Let's say I have a class:
class MyClass {
String observed_field;
}
Now, whenever I change the field, I'd like to print "observed_field changed" string into the console. Pretty simple to do with a custom setter:
class MyClass {
String _observed_field;
get observed_field => _observed_field;
set observed_field(v) {
_observed_field = v;
print("observed_field changed");
}
}
Now, of course, if I have not one, but many of those fields, I wouldn't want to create all those getters and setters. The obvious theoretical solution is to have them dynamically added to the class with something like this (not a working code, just an example of how I wish it looked):
class MyClass
String _observeable_field;
String _observeable_field_2;
observe(#observeable_field, #observeable_field_2);
end
Is it even possible? Additionally, it would be super awesome to not have those fields defined above the observe() call, but rather write something like:
observe(String: #_observeable_field, String: #_observeable_field_2);
So that those fields are declared automatically.
Here's a way to do it using the Observe package. The example is taken from code comments in that package (and adapted to your example above). Essentially, you annotate fields you want to be observable with the #observable annotation, and then listen for changes (which you trigger with the call to Observable.dirtyCheck();
First, add the observable package in your pubspec.yaml
dependencies:
observe: any
Then create a quick test program...
import 'package:observe/observe.dart';
class MyClass extends Object with Observable {
#observable String observedField = "Hello";
toString() => observedField.toString();
}
main() {
var obj = new MyClass();
// anonymous function that executes when there are changes
obj.changes.listen((records) {
print('Changes to $obj were: $records');
});
obj.observedField = "Hello World";
// No changes are delivered until we check for them
Observable.dirtyCheck();
print('done!');
}
This produces the following output:
Changes to Hello World were: [#<PropertyChangeRecord Symbol("observedField") from: Hello to: Hello World>]
done!
Update in response to comments...
Updating the example to omit the Observable.dirtyCheck() you can use a setter and notifyPropertyChanged, with the class instead mixing in ChangeNotifier
class MyClass2 extends Object with ChangeNotifier {
String _observedField = "Hello";
#reflectable get observedField => _observedField;
#reflectable set observedField(v) {
_observedField = notifyPropertyChange(#observedField, _observedField, v);
}
toString() => observedField;
}
im looking for a way to add an PropertyChangeEvent to an object that I have defined. The goal is to raise a change event when any of the property of the object is been changed.
so i can do something like the following
var newItem:MyObject = new MyObject();
newItem.addEventListener(event.PropertyChangeEvent, myO_PropertyChangeHandler);
class MyObject extends EventDispatcher
{
public function doSomething() :void
{
// change values, and dispatch event
dispatchEvent( PropertyChangeEvent.createUpdateEvent( this, "myProperty", oldValue, newValue ) );
}
}
If you can't extend EventDispatcher because your object extends something else, and if that super class isn't already a subtype of EventDispatcher or implements IEventDispatcher (which includes most types), you need to implement IEventDispatcher manually. See the help page for IEventDispatcher for example code on how you do that (i.e. with an internal EventDispatcher doing the actual job).
If I understand you correctly you're looking for the Bindable Meta tag.