In polymer dart, what are the ways to communicate from parent to child component? - dart

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});

Related

Reflectable: myAnnotation.annotatedClasses different result CmdApp<>Client

Say I have the following Annotation and 2 classes:
class AppModel extends Reflectable {
final String name;
const AppModel([this.name])
: super(newInstanceCapability, metadataCapability);
}
const appModel = const AppModel();
#appModel
class ImGonnaBePickedUp {
}
#AppModel(' :( ')
class AndImNotPickedUpOnServer_IDoOnWebClient {
}
main() {
appModel.annotatedClasses // that's what I mean by "Picked Up".
}
On CmdApp side (Server): only AndImNotPickedUpOnServer_IDoOnWebClient is given in appModel.annotatedClasses.
On the web side, both classes are given.
Long story short, how do I retrieve classes annotated with direct const constructor calls like in the example above #AppModel(' :( ') (for both CmdApp and Web)?
since version 0.5.4 reflectable classes doesn't support constructors with arguments
This appears in reflectable documentation:
Footnotes: 1. Currently, the only setup which is supported is when the metadata object is an instance of a direct subclass of the class [Reflectable], say MyReflectable, and that subclass defines a const constructor taking zero arguments. This ensures that every subclass of Reflectable used as metadata is a singleton class, which means that the behavior of the instance can be expressed by generating code in the class. Generalizations of this setup may be supported in the future if compelling use cases come up.
one possible solution could be to use a second annotation to handle the name, for example:
import 'package:reflectable/reflectable.dart';
import 'package:drails_commons/drails_commons.dart';
class AppModel extends Reflectable {
const AppModel()
: super(newInstanceCapability, metadataCapability);
}
const appModel = const AppModel();
class TableName {
final String name;
const TableName(this.name);
}
#appModel
class ImGonnaBePickedUp {
}
#appModel
#TableName(' :( ')
class AndImNotPickedUpOnServer_WorksOnWebClient {
}
main() {
print(appModel.annotatedClasses); // that's what I mean by "Picked Up".
print(new GetValueOfAnnotation<TableName>()
.fromDeclaration(appModel.reflectType(AndImNotPickedUpOnServer_WorksOnWebClient)).name);
}
Note: I'm also using drails_common package

Seeming to set a 1-directional databind even though it should be bidirectional

Been working with 2 files: my_ajax_fetcher.data/html with the data as follows:
my_ajax_fetcher.dart
#HtmlImport('my_ajax_fetcher.html')
library webserver_ajax.lib.iron_ajax;
import 'package:web_components/web_components.dart';
import 'package:polymer/polymer.dart';
import 'package:polymer_elements/iron_ajax.dart';
import 'package:polymer_elements/iron_request.dart';
///Uses [IronAjax]
#PolymerRegister('my-ajax-fetcher')
class IronAjaxSample extends PolymerElement {
#property
String f_name;
#property
String l_name;
#property
int identification;
//IronAjax ia = querySelector('myAjaxId');
IronAjaxSample.created() : super.created(){
print("created.");
//ia.generateRequest();
}
#reflectable
void handleResponse ( [CustomEventWrapper cew, IronRequest ir] ){
print("handle response fired");
var data = ir.response;
f_name = data["f_name"];
l_name = data["l_name"];
identification = data["id"];
print("$f_name $l_name: $identification");
}
}
my_ajax_fetcher.html
<dom-module id="my-ajax-fetcher">
<template>
<iron-ajax id="myAjaxId" auto
url="http://localhost:8675/test_server/v1/users/35"
handle-as="json"
on-response="handleResponse" ></iron-ajax>
<div>First Name: {{f_name}}</div>
<div>Last Name: {{l_name}}</div>
<div>Student ID: {{identification}}</div>
</template>
</dom-module>
And when the ajax call finishes it will call handleResponse which will set f_name, l_name, identification variables. The issue is that i see the variables are set in the last line of handleResponse.
It doesn't set the markup according to say: First Name: Frank at all, it is just empty. I have determined that for some reason, handleResponse is a different scope than the other functions. How do i fix this?
In Dart you always need to use set(...) or any other method provided by Polymer to update data.
set('f_name', data["f_name"]);
set('l_name', data["l_name"]);
set('identification', data["id"]);
In JavaScript this is not necessary for fields of a Polymer element, only for properties of complex types (custom classes, collections, ...)
See also
https://github.com/dart-lang/polymer-dart/wiki/properties#list-mutation-methods
https://github.com/dart-lang/polymer-dart/wiki/data-binding-syntax#path-change-notification
https://pub.dartlang.org/packages/polymer_autonotify
https://pub.dartlang.org/packages/autonotify_observe

Dart Cross-Polymer Action Listerners

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).

Extend svg.RectElement (factory constructor)

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?

Define a custom jQuery UI widget in TypeScript

We're currently looking at translating our JavaScript project to TypeScript. Our application relies heavily on custom developed jQuery UI widgets.
In our current code base, we're using a deep copy mechanism to inherit from widget definitions allowing us, for example, to declare a generic TableWidget as well as an OrdersTableWidget which defines more specific functions.
Therefore, I'd like to define my widget definitions as TypeScript classes and then bind an instance of these classes to jQuery.
For example
class MyWidget {
options: WidgetOptions;
_init(){
// general initialization
}
}
class MySecondWidget extends MyWidget {
_init(){
super._init();
// specific initialization
}
}
And then
$.widget("MyNameSpace.MyWidget", new MyWidget());
$.widget("MyNameSpace.MySeWidget", new MyWidget());
Furthermore, I'd like to denote my custom widgets as implementations of jQuery UI's Widget definition
class MyWidget implements Widget {
options: WidgetOptions;
_init(){
// general initialization
}
}
so I'm able to use the following syntax in TypeScript:
$(selector).MyWidget(options);
I know I have to work with the definition file (from DefinitelyTyped), however I have not yet found a reliable source explaining me how I should write custom jQuery UI Widgets in TypeScript. Has anyone got experience with this?
Any help greatly appreciated, as always!
I'm not sure you can write a class that implements the Widget interface, due to the lack of overloaded constructors. You could create a variable that is typed by the Widget interface.
A standard jQuery plugin would be represent in almost pure JavaScript and wouldn't use modules or classes as it ends up being wrapped up as part of jQuery, which itself isn't a module or class.
Here is an empty plugin called plugin that looks like any standard jQuery plugin, but you can see it takes advantage of the TypeScript type system and extends the JQuery interface to allow it to be called.
/// <reference path="jquery.d.ts" />
interface JQuery {
plugin(): JQuery;
plugin(settings: Object): JQuery;
}
(function ($) {
function DoSomething(someParamater: string) : void {
}
$.fn.plugin = function (settings) {
var config = {
settingA: "Example",
settingB: 5
};
if (settings) {
$.extend(config, settings);
}
return this.each(function () {
});
};
})(jQuery);
This would be called in the normal way.
$('#id').plugin();
So really, my answer is - you can't really do what you want because you are adding to the declared interfaces for jQuery rather than exposing them as modules. You could wrap the usage in a module, like an adaptor that abstracts the jQuery aspect away from the use in your TypeScript, or you can call your classes from inside the plugin, but the plugin or widget doesn't really fit into a module or class.
It might help to have a base class in typescript from which other widget classes may derive.
Its only purpose is to provide the base class semantic so you can access the base class'es members without having to resort to weak typing.
The trick is to remove all the members at runtime (in the constructor) -- otherwise you run into problems with the inheritance provided by the widget factory. For example, the option method would override the widget's original method which is not desired: we just want to be able to call it (in a statically typed way).
class WidgetBase {
public element:JQuery;
constructor() {
// remove all members, they are only needed at compile time.
var myPrototype = (<Function>WidgetBase).prototype;
$.each(myPrototype, (propertyName, value)=>{
delete myPrototype[propertyName];
});
}
/**
* Calles the base implementation of a method when called from a derived method.
* #private
*/
public _super(arg1?:any, arg2?:any, arg3?:any, arg4?:any) {
}
/**
* #private
*/
public _superApply(arguments) {
}
/**
* Gets or sets the value of the widget option associated with the specified optionName.
*/
public option(optionName:string, value?:any):any {
}
// ... further methods from http://api.jqueryui.com/jQuery.widget/
}
Then you can implement your own widget like this:
class SmartWidget extends WidgetBase {
constructor(){
super();
}
public _create() {
var mySmartOption = this.option('smart'); // compiles because of base class
this.beSmart(mySmartOption);
}
public _setOption(key:string, value:any) {
if (key === 'smart') {
this.beSmart(value);
}
this._super(key, value); // compiles because of base class
}
private beSmart(smartOne:any){
// ...
}
}
// register
jQuery.widget("myLib.smartWidget", new SmartWidget());
// assuming you are using https://github.com/borisyankov/DefinitelyTyped
declare interface JQuery{
smartWidget();
smartWidget(options:any);
smartWidget(methodName:string, param1?:any, param2?:any, param3?:any, param4?:any);
}
And finally, you can use your widget:
$(".selector").smartWidget({smart:"you"});

Resources