How do I do custom validation in Polymer Dart - dart

Similar to javascript and the implementation of IronValidatorBehavior how do I do custom validation in Polymer Dart?
I can create a new custom-validator which implements IronValidatorBehavior e.g.
<dom-module id="form-input">
<template>
<style include='shared-styles iron-flex iron-flex-alignment'>
:host {
display: block;
padding: 1em;
}
</style>
<custom-validator id="validator" validator-name="jsonValidator" validator-type="json"></custom-validator>
<paper-textarea label="[[label]]" id="body" name="body" autofocus tabindex="0"
validator="jsonValidator" auto-validate error-message="This is not a valid format"></paper-textarea>
</template>
</dom-module>
The custom-validator is written as
library main_app.custom_validator;
import 'dart:html';
import 'package:polymer/polymer.dart';
import 'package:polymer_elements/iron_validator_behavior.dart' show IronValidatorBehavior;
#PolymerRegister('custom-validator')
class CustomValidator extends PolymerElement with IronValidatorBehavior{
CustomValidator.created() : super.created();
#reflectable
bool validate(e, [_]){
switch(validatorType) {
case 'json':
return textValidator(e);
}
return false;
}
bool textValidator(e){
return false;
}
}

okay, it was a typo, the above works if I change.
<custom-validator id="validator" validator-name="jsonValidator" validator-type="json"></custom-validator>
to
<custom-validator id="validator" validator-name="jsonValidator" validator-check="json"></custom-validator>
The property validatorType needs to be set to its default value of 'validator'. Instead added a new property validatorCheck, where I set the validation method name to be called.
library custom_validator;
import 'dart:mirrors' show reflect;
import 'package:polymer/polymer.dart';
import 'package:polymer_elements/iron_validator_behavior.dart' show IronValidatorBehavior;
import 'package:validator/validator.dart' show isJSON;
#PolymerRegister('custom-validator')
class CustomValidator extends PolymerElement with IronValidatorBehavior{
#property
String validatorCheck;
CustomValidator.created() : super.created();
#reflectable
bool validate(value, [_]){
if(validatorCheck.isNotEmpty) {
Symbol sym = new Symbol(validatorCheck);
return reflect(this).invoke(sym, [value]).reflectee;
}
return false;
}
bool json(String value, [_]){
if(value.isNotEmpty) {
return isJSON(value);
}
return true;
}
}

Related

How to remove a nested dom rep element in dart using polymer >1.0

Hello I cant seem to find the correct way to remove a nested element using polymer 1.0
createMigrationTable.html
<dom-module id="custom-create-migration-table">
<template>
<style>
paper-button {
/**border: 1px solid #d81b60;*/
}
paper-material {
width: 98%;
margin: 5px auto;
}
br{
clear:both;
}
</style>
<paper-material elevation="2" id="page_2">
createTable:
<paper-button raised on-tap="addTable">
+ add new table
</paper-button>
<template is="dom-repeat" items="{{createTables}}">
{{item.name}}
<paper-input required label="Table Name" value="{{item.name}}"></paper-input>
<template is="dom-repeat" items="{{item.columns}}" as="column">
<custom-column-view column="{{column}}"></custom-column-view>
<a on-tap="removeColumn">remove</a>
<br/>
</template>
<paper-button raised on-tap="addColumn">
Add Column
</paper-button>
</template>
</paper-material>
</template>
</dom-module>
createMigrationTable.dart
#HtmlImport('createMigrationTable.html')
library dartabase.poly.createMigrationTable;
// Import the paper element from Polymer.
import 'package:polymer_elements/iron_pages.dart';
import 'package:polymer_elements/paper_material.dart';
import 'package:polymer_elements/paper_button.dart';
import 'package:polymer_elements/paper_input.dart';
//import "../poly/columnView.dart";
import "../poly/table.dart";
// Import the Polymer and Web Components scripts.
import 'package:polymer/polymer.dart';
import 'package:web_components/web_components.dart';
#PolymerRegister('custom-create-migration-table')
class CreateMigrationTable extends PolymerElement {
#property
List<Table> createTables = new List();
CreateMigrationTable.created() : super.created();
#reflectable
addTable(event, [_]) {
Table table = new Table(name:"defaultName",columns: [{
"name":"defaultName",
"type":["BINT",
"INT",
"VARCHAR"
],
"def":"",
"nil":true
}]);
/*Map table = {
"tableName":"defaultTableName",
"columns":[{
"name":"defaultName",
"type":"defaultType",
"default":"",
"notNull":true
}]
};*/
//createTables.add(table);
add('createTables', table);
}
#reflectable
transition(event, [_]) {
IronPages ip = Polymer.dom(this.root).querySelector("iron-pages");
ip.selectNext();
}
#reflectable
void addColumn(event, [_]) {
var model = new DomRepeatModel.fromEvent(event);
model.add("item.columns", {
"name":"defaultName",
"type":"",
"def":"",
"nil":true
});
}
#reflectable
void removeColumn(event, [_]) {
var model = new DomRepeatModel.fromEvent(event);
model.removeItem("item", model.item);
}
void ready() {
print("$runtimeType::ready()");
}
}
tabel.dart
import 'package:polymer/polymer.dart';
import 'package:web_components/web_components.dart';
class Table extends JsProxy {
#reflectable
String name;
#reflectable
List columns;
Table({this.name, this.columns});
}
what should be the correct way to remove the element.
first I tried to call remove from inside the custom-column-view. but that did not update the bindings
then I read that the parent elements should have the control over adding and removing elements.. so I moved it one level above.
I would have thought that I can do it like in the addColumn method but but inside removeColumn I only receive the column view item.
I also tried to use index-as but I dont know how to be able to access both indexes i and j inside the removeColumn functions.
A custom equals implementation might fix it (not sure)
class Table extends JsProxy {
#reflectable
final String name;
#reflectable
List columns;
Table({this.name, this.columns});
int get hasCode => name.hashCode;
int operator ==(Object other) => other is Table && other.name == name;
}

How to listen for event passed from parent to child in polymer.dart

I am trying to pass an event from a parent to child in Polymer 1.0.0-rc2 in Dart. The problem is that I do not know how to go about listening for the event in the child. I've tried to put the on-control-panel-refire attribute in the dom-module in the notation_view.html file, and calling handle button from there, but it didn't work. What is the proper way to listen for this event? I know that on-control-panel-button-pressed is working well.
notation_view.dart
#PolymerRegister('notation-view')
class NotationView extends PolymerElement {
NotationView.created() : super.created();
#reflectable
handleButton(Event e, var detail) {
print("received");
}
}
main_app.dart
#PolymerRegister('main-app')
class MainApp extends PolymerElement {
MainApp.created() : super.created();
#reflectable
refire(Event e, var detail) {
querySelector('notation-view').dispatchEvent(new CustomEvent("control-panel-refire",
detail: {'name' : detail["button-id"]}));
}
main_app.html
<link rel="import" href="notation_view.html">
<dom-module id="main-app">
<style>
:host {
display: block;
}
</style>
<template>
<notation-view id="notation-view"></notation-view>
<control-panel id="control-panel" on-control-panel-button-pressed="refire"></control-panel>
</template>
</dom-module>
notation_view.html
<dom-module id="notation-view" >
<style>
:host {
display: block;
}
</style>
<template>
<canvas id="canvas" width="1000" height="1000"></canvas>
</template>
</dom-module>
I haven't actually tried this but I think instead of
querySelector('notation-view').dispatchEvent(new CustomEvent("control-panel-refire",
detail: {'name' : detail["button-id"]}));
}
it should be
new PolymerDom(root).querySelector('notation-view').fire("control-panel-refire",
detail: {'name' : detail["button-id"]}));
}
You can cast the result of querySelector() to PolymerElement or NotationView if the analyzer complains about the unknown fire() method.
To listen to an event use
#PolymerRegister('notation-view')
class NotationView extends PolymerElement {
NotationView.created() : super.created();
#reflectable
handleButton(Event e, var detail) {
print("received");
}
#Listen('control-panel-refire')
void handleControlPanelRefire(CustomEvent e, [_] /* or `Map detail` instead of [_] */) {
// handle event
}
// alternatively
EventSubscription _controlPanelRefireSubscr;
attached() {
super.attached();
_controlPanelRefireSubscr = this.on['control-panel-refire'].listen((event) {
// handle event
});
}
detached() {
super.detached();
_controlPanelRefireSubscr?.cancel();
}
}

How to detect that a polymer button has been clicked in the dart class

I want to be able to catch the click event on the paper button and change the "clic me" text.
my-module.html:
<dom-module id="my-module">
<template>
<paper-button>{{btnTxt}}</paper-button>
</template>
<script type="application/dart" src="my-module.dart"></script>
</dom-module>
my-module.dart:
#HtmlImport('my-module.html')
library blink.my_module;
import 'package:polymer/polymer.dart';
import 'package:web_components/web_components.dart' show HtmlImport;
#PolymerRegister('my-module')
class MyModule extends PolymerElement {
#property String btnTxt = "Clic me!";
MyModule.created() : super.created();
}
OK, to do so you have to add this to the following files:
my-module.html:
//Adding the 'on-tap' tag with the dart methode name attribute, can also use 'on-click'
<paper-button on-tap="btnClicked">{{btnTxt}}</paper-button>
my-module.dart:
#PolymerRegister('my-module')
class MyModule extends PolymerElement {
#property String btnTxt = "Clic me!";
MyModule.created() : super.created();
//this method will listen for the linked event in the html
#reflectable
void btnClicked(Event e, [_]) {
set('btnTxt', btnTxt = 'Button Clicked!');
}
}

How can an ObservableList<T> be sorted in Dart?

I can't seem to sort an ObservableList<T> and have the sort reflected in my Polymer element. Here's a sample element definition:
class PeopleElement extends PolymerElement {
ObservableList<Person> people = toObservable(new List<Person>());
PeopleElement.created() : super.created();
}
And here is the definition of the Person class:
class Person {
String name;
Person(this.name);
int compare(Person p) {
return name.compareTo(p.name);
}
}
Now, I want to add a sort function to the PeopleElement class:
class PeopleElement extends PolymerElement {
...
ObservableList<Person> sortByName() {
people.sort((Person a, Person b) {
a.compare(b);
}
}
}
I've also tried the above function as returning void and that didn't seem to work either. Does anything jump out as being incorrect here?
Your Person class needs to implement Comparable with the method compareTo instead of compare
library people_element;
import 'dart:async';
import 'package:polymer/polymer.dart';
class Person implements Comparable{
String name;
Person(this.name);
#override
int compareTo(Person other) {
return name.compareTo(other.name);
}
}
#CustomTag('people-element')
class PeopleElement extends PolymerElement {
var people = toObservable(new List<Person>());
PeopleElement.created() : super.created() {
print('PeopleElement');
}
#override
void enteredView() {
people.add(new Person('c'));
people.add(new Person('a'));
people.add(new Person('f'));
people.add(new Person('b'));
super.enteredView();
new Timer(new Duration(seconds: 3), () => sortByName());
}
ObservableList<Person> sortByName() {
people.sort();
}
}
<polymer-element name="people-element">
<template>
<template repeat="{{p in people}}">
<p>{{p.name}}</p>
</template>
</template>
<script type="application/dart" src="people_element.dart"></script>
</polymer-element>

dart-polymer: cannot set an attribute from an event handler

The following code doesn't work. Maybe I do something wrong.. Please correct my code:
index.html:
<html>
<head>
<title>Page</title>
<link rel="import" href="msg_box.html">
</head>
<body>
<msg-box id="msg" caption="Caption 1"></msg-box>
<button id="btn">click me</button>
<script type="application/dart" src="index.dart"></script>
<script src="packages/browser/dart.js"></script>
</body>
</html>
import 'dart:html';
import 'package:polymer/polymer.dart';
import 'msg_box.dart';
void main() {
initPolymer();
ButtonElement btn = querySelector("#btn");
btn.onMouseEnter.listen((e) {
MsgBoxElement elm = querySelector("#msg");
window.alert(elm.caption); // SHOWS 'Caption 1'
elm.caption = "Caption 2"; // DON'T WORK!
window.alert(elm.caption); // SHOWS 'Caption 2', BUT PAGE SHOWS 'Caption 1'!!!
});`
}
msg_box.html
<polymer-element name="msg-box" attributes="caption">
<template>
<h4>{{caption}}</h4>
</template>
<script type="application/dart" src="msg_box.dart"></script>
</polymer-element>
import 'package:polymer/polymer.dart';
#CustomTag('msg-box')
class MsgBoxElement extends PolymerElement {
// fields
String _caption;
String get caption => _caption;
void set caption(String value) {
_caption = notifyPropertyChange(#caption, _caption, value);
}
MsgBoxElement.created() : super.created() {
}
}
This issue is critical for me. See also https://code.google.com/p/dart/issues/detail?id=14753&sort=-id&colspec=ID%20Type%20Status%20Priority%20Area%20Milestone%20Owner%20Summary
I believe the problem here is that there are pending change notifications not being processed because your code is not running in the dirty-checking zone. There are two things you can do to fix this:
call Observable.dirtyCheck() right after your update to caption; or,
run your code within the dirty-checking zone:
void main() {
var dirtyCheckingZone = initPolymer();
dirtyCheckingZone.run(() {
ButtonElement btn = querySelector("#btn");
btn.onMouseEnter.listen((e) {
MsgBoxElement elm = querySelector("#msg");
elm.caption = "Caption 2";
});
});
}
This zone makes sure that after any callback or listener is executed, we'll call Observable.dirtyCheck for you. This approach is slightly better than calling dirtyCheck explicitly because, when we compile for deployment, we switch from dirty-checking to explicit notifications. The zone returned by initPolymer is changed to reflect this.
A separate note: the MsgBoxElement above can be simplified if you use the #published annotation. This is meant to express that a property is both observable and exposed as an attribute of your element.
import 'package:polymer/polymer.dart';
#CustomTag('msg-box')
class MsgBoxElement extends PolymerElement {
#published String caption;
MsgBoxElement.created() : super.created();
}
Based on your information, it appears that the model is being updated, however the DOM isn't updating, most likely because an observable element isn't set. Try adding the following annotations to your msg_box dart code:
import 'package:polymer/polymer.dart';
#CustomTag('msg-box')
class MsgBoxElement extends PolymerElement {
// fields
#observable String _caption;
#reflectable String get caption => _caption;
#reflectable void set caption(String value) {
_caption = notifyPropertyChange(#caption, _caption, value);
}
MsgBoxElement.created() : super.created() {
}
}
See this Breaking change announcement on the dart mailing lists regarding the #reflectable attribute. Also see this discussion on setting up #observable getters

Resources