How to add attributes to a dynamically created component - dart

I would like to add a published attribute to a dynamically created component. The code for the component is shown below:
<!DOCTYPE html>
<link rel="import" href="name-form.html">
<link rel="import" href="../../shared/red-asterisk.html">
<polymer-element name='name-view'>
<template>
<div id='name-view' class='flex-row-container view'>
<section id='row0' class='flex-row' >
<button id='add-name-btn'
class='button add-button'
on-click='{{addName}}'
autofocus>Add Name</button>
<red-asterisk></red-asterisk>
</section >
<section id='names' class='flex-column'>
</section>
</div>
</template>
<script type="application/dart">
import 'package:polymer/polymer.dart';
import 'dart:html' show Event, Node, Element;
#CustomTag( 'name-view' )
class NameViewForm extends PolymerEment
{
#published String receiver = '';
NameViewForm.created() : super.created();
void addName( Event e, var detail, Node target )
{
if( $[ 'names' ].children.length < 1 )
{
$[ 'names' ].children
.add( new Element.tag( 'name-form' ) );
}
$['names'].on["deleteDispatch"]
.listen( (Event e)
{
(e.target as Element).remove();
});
}
}
</script>
</polymer-element>
It is the element ('name-form' created by
$[ 'names' ].children
.add( new Element.tag( 'name-form' ) );
to which I would like to add an attribute receiver='patient'.
Thanks

Is this a follow up question to Custom Events in Nested Polymer Dart UI?. In this case it would not be necessary to create a published attribute. You can just add a field like role in the class and set this field to 'nok-form' or 'patient-form'.
Element nameForm = new Element.tag( 'name-form' )
nameForm.role = 'nok-form';
$[ 'names' ].children
.add(nameForm);
You only need a published attribute when you want to set the value in markup (HTML).

Related

Auto convert html string to element

Say I have a polymer-element <polymer-element> <div id="foo"> {{html}} </div> </polymer-element>, where html is supposed to be a HTML formated string, like <p>blah</p>, what I want is, when html changes, the polymer-element also changes, and use html as its innerHtml, i.e. auto convert the string to an element and insert it as foo's child.
Can polymer/polymer_expression do this for me, or I have to do a querySelector(), then set html as innerHtml manually?
My solution is a custom element that extends a div and uses the DocumentFragment class to parse HTML strings into the DOM via data binding.
From my Github gist
<!-- Polymer Dart element that allows HTML to be inserted into the DOM via data binding -->
<link rel="import" href="packages/polymer/polymer.html">
<polymer-element name="html-display" extends="div">
<script type="application/dart">
import 'dart:html';
import 'package:polymer/polymer.dart';
#CustomTag('html-display')
class HtmlDisplay extends DivElement with Polymer, Observable {
#published String htmlContent;
// we need this stuff because we're extending <div> instead of PolymerElement
factory HtmlDisplay() => new Element.tag('div', 'html-display');
HtmlDisplay.created() : super.created() {
polymerCreated();
}
#override void attached() {
super.attached();
}
// respond to any change in the "htmlContent" attribute
void htmlContentChanged(oldValue) {
if (htmlContent == null) {
htmlContent = "";
}
// creating a DocumentFragment allows for HTML parsing
this.nodes..clear()..add(new DocumentFragment.html("$htmlContent"));
}
}
</script>
</polymer-element>
<!--
Once you've imported the Polymer element's HTML file, you can use it from another Polymer element like so:
<link rel="import" href="html_display.html">
<div is="html-display" htmlContent="{{htmlString}}"></div>
*htmlString* can be something like "I <em>love</em> Polymer Dart!"
-->
I use solution as described in https://stackoverflow.com/a/20869025/789338.
The key class is DocumentFragment.
The official way to do it is described in the doc: https://www.polymer-project.org/docs/polymer/databinding-advanced.html#boundhtml
The example on the doc:
<polymer-element name="my-element">
<template>
<div id="message_area"></div>
</template>
<script>
Polymer({
message: 'hi there',
ready: function() {
this.injectBoundHTML('<b>{{message}}</b>', this.$.message_area);
}
});
</script>
</polymer-element>

Forcing a paper-dialog to be the topmost window

I created a dialog and it renders. However, it can be hidden by its parent if the window is small. I tried the layered attribute on PaperDialog layered attribute it does not seem to help.
others.html
<!DOCTYPE html>
<link href='../../../../packages/polymer/polymer.html' rel='import' >
<link href='../../../../packages/bwu_datagrid/bwu_datagrid.html' rel='import' >
<link href='../../../../packages/paper_elements/paper_input.html' rel='import' >
<polymer-element name='others-form'>
<template>
<paper-input floatinglabel multiline
id = 'description'>
</paper-input>
</template>
<script type='application/dart' src='others_form.dart'></script>
</polymer-element>
others.dart
import 'package:polymer/polymer.dart';
import 'package:vacuum_persistent/persistent.dart' show PersistentMap;
import 'package:clean_data/clean_data.dart' show DataMap;
import 'package:epimss_shared/shared_event.dart' show eventBus,
PersistentMapEvent;
#CustomTag( 'others-form' )
class OthersForm extends PolymerElement
{
#observable String z = '3';
#observable DataMap<String, dynamic> selections;
String errorMsg;
OthersForm.created() : super.created();
#override
void attached()
{
super.attached();
selections = new DataMap<String, dynamic>.from({});
eventBus.on( PersistentMapEvent, ( event )
{
switch( event.topic )
{
case 'shared|description-form --> lab|routine-culture-rqst':
selections[ 'other' ] = event.pmap[ 'description' ];
break;
}
});
/*
selections.onChange.listen( (changeset)
{
if ((selections.length == 1 && !selections.containsKey( 'other' )) ||
selections.containsKey( 'other' ))
{
eventBus.signal(
new PersistentMapEvent (
new PersistentMap<String, String>.fromMap( selections ))
..topic = this.dataset[ 'topic' ]);
}
});
*
*/
}
}
ssss_form.html
<!DOCTYPE html>
<link href='../../../../packages/polymer/polymer.html' rel='import'>
<link href='../../../../packages/paper_elements/paper_icon_button.html' rel='import' >
<link href='../../../../packages/paper_elements/paper_shadow.html' rel='import'>
<link href='../../../../packages/paper_elements/paper_button.html' rel='import'>
<link href='../../../../packages/paper_elements/paper_dialog_transition.html' rel='import'>
<link href='../../../../packages/paper_elements/paper_dialog.html' rel='import'>
<link href='../../../../packages/html_components/input/select_item.html' rel='import'>
<link href='../../../../packages/html_components/input/select_checkbox_menu.html' rel='import'>
<link href='others_form.html' rel='import'>
<polymer-element name='ssss-form'>
<template>
<div layout horizontal>
<div layout vertical
id='specimen-div'
class='card'>
<h-select-checkbox-menu
label='Specimen'
on-selectionchanged='{{onSelectionChangedFiredSpecimen}}'>
<template repeat='{{key in specimens.keys}}'>
<h-select-item
label='{{key}}'
value='{{specimens[key]}}'>
</h-select-item>
</template>
</h-select-checkbox-menu>
</div>
<paper-shadow z='{{z}}'></paper-shadow>
</div>
<paper-dialog
id='other-dialog'
heading='Other'
transition='paper-dialog-transition-center'>
<others-form> </others-form>
<paper-button dismissive
label='More Info...' >
</paper-button>
<paper-button affirmative
label='Cancel'>
</paper-button>
<paper-button affirmative autofocus
label='Accept'>
</paper-button>
</paper-dialog>
</template>
<script type='application/dart' src='ssss_form.dart'></script>
</polymer-element>
ssss_form.dart
import '
package:polymer/polymer.dart';
import 'dart:html';
import 'package:paper_elements/paper_dialog.dart';
import 'package:html_components/html_components.dart' show SelectCheckboxMenuComponent;
import 'package:vacuum_persistent/persistent.dart' show PersistentMap;
import 'package:clean_data/clean_data.dart';
import 'package:epimss_shared/shared_transformers.dart' show CheckboxMenuItemsConverter;
#CustomTag( 'ssss-form' )
class SsssForm extends PolymerElement with CheckboxMenuItemsConverter
{
DataSet<DataMap> selections;
DataMap<String, dynamic> specimenSelections;
PersistentMap<String, Map> pmap;
#observable
Map<String, dynamic> specimens = toObservable(
{
'CSF': 'CSF',
'Other': 'Other'
});
#observable String specimen = '';
#observable String z = '3';
var sideForm;
SsssForm.created() : super.created();
void onSelectionChangedFiredSpecimen( Event event, var detail,
SelectCheckboxMenuComponent target)
{
var list = getItemModels( target.selectedItems );
specimenSelections.clear();
list.forEach( (item)
{
specimenSelections[item.label] = item.selected;
/// Checks if [item] selected is equal to 'Other' and if so creates a
/// a dialogue to make the selection
if ( item.label == 'Other')
{ toggleDialog( 'paper-dialog-transition-center' ); }
});
}
toggleDialog( transition ) => $['other-dialog'].toggle();
#override
void attached()
{
super.attached();
specimenSelections = new DataMap<String, dynamic>.from({});
selections = new DataSet<DataMap>.from( [specimenSelections] );
}
}
others.html is the contents of the dialog - the latter is hosted in the ssss_form.html file. When the 'Others' checkbox in the 'Specimen' dropdown is clicked, this triggers the dialog.
I also get the following when the application is run
Attributes on ssss-form were data bound prior to Polymer upgrading the element. This may result in incorrect binding types. (:1)
The "label" property is deprecated. (http://localhost:8080/polymer_bug.html:7467)
The "label" property is deprecated. (http://localhost:8080/polymer_bug.html:7467)
The "label" property is deprecated. (http://localhost:8080/polymer_bug.html:7467)
The "label" property is deprecated. (http://localhost:8080/polymer_bug.html:7467)
The "label" property is deprecated. (http://localhost:8080/polymer_bug.html:7467)
The "label" property is deprecated. (http://localhost:8080/polymer_bug.html:7467)
Please see attached graphic.
Thanks
I think you just need to set a higher value for the zIndex CSS property than every other HTML element on that page.

How to remove a child component with a delete button in the child itself

I have an email component (email-tag.html) that consist of a label, a select and a delete button element.
The email-tag.html component is hosted in its parent email-view-tag.html. email-view-tag contains an add-email-button that adds the email-tag element to the DOM each time it is clicked.
I need help in removing an added email-tag component when its delete-button is clicked. It is the compnoent that contains the delete-button that should be removed.
The two components are shown below:
email-tag.html
<!DOCTYPE html>
<polymer-element name='email-tag'>
<template>
<style>
.main-flex-container
{
display:flex;
flex-flow:row wrap;
align-content:flex-start;
}
.col
{
display:flex;
flex-flow:column;
align-content:flex-start;
flex-grow:1;
}
</style>
<div id='email' class='main-flex-container'>
<section id='col1' class='col'>
<input id=emailTxt
type='text'
list='_emails'
value='{{webContact.homeEmail}}'>
<datalist id='_emails'>
<template repeat='{{email in emails}}'>
<option value='{{email}}'>{{email}}</option>
</template>
</datalist>
</section>
<section id='col2' class='col'>
<button id='delete-email-btn' type='button' on-click='{{deletePhone}}'>Delete</button>
</section>
</div>
</template>
<script type="application/dart">
import 'package:polymer/polymer.dart' show CustomTag, PolymerElement;
import 'dart:html' show Event, Node;
#CustomTag( 'email-tag' )
class EmailElement extends PolymerElement
{
//#observable
EmailElement.created() : super.created();
List<String> emails = [ '', 'Home', 'Personal', 'Private', 'Work', ];
void deletePhone( Event e, var detail, Node target)
{
//shadowRoot.querySelector('#new-phone' ).remove();
//print( 'Current row deleted' );
}
}
</script>
</polymer-element>
email-view-tag.html
<!DOCTYPE html>
<link rel="import" href="email-tag.html">
<polymer-element name='email-view-tag'>
<template>
<style>
.main-flex-container
{
display:flex;
flex-flow:row wrap;
align-content:flex-start;
}
.col
{
display:flex;
flex-flow:column;
align-content:flex-start;
flex-grow:1;
}
</style>
<div id='email-view' class='main-flex-container'>
<section id='row0' >
<button id='add-email-btn' type='button' on-click='{{addPhone}}'>Add Phone</button>
</section >
<section id='rows' class='col'>
<!-- <epimss-phone-header-tag id='col1' class='col'></epimss-phone-header-tag> -->
</section>
</div>
</template>
<script type="application/dart">
import 'package:polymer/polymer.dart' show CustomTag, PolymerElement;
import 'dart:html' show Event, Node, Element;
#CustomTag( 'email-view-tag' )
class EmailViewElement extends PolymerElement
{
//#observable
EmailViewElement.created() : super.created();
void addPhone( Event e, var detail, Node target )
{
$[ 'rows' ].children.add( new Element.tag( 'email-tag' ) );
}
#override
void attached() {
super.attached();
$[ 'add-email-btn' ].click();
}
}
</script>
</polymer-element>
The application does execute normally and clicking the add button does add the email component. The delete button does not work - it is here I am asking for help.
Thanks
The child component, <email-tag> should not be in the business of deleting itself. Instead, it should delegate that responsibility to the the parent component, email-view-tag, by dispatching a custom event.
Here is the code for dispatching a custom event from deletePhone:
void deletePhone( Event e, var detail, Node target){
dispatchEvent(new CustomEvent('notneeded'));
}
Then, in the parent, <custom-view>, change your code for adding <email-tag>s like so:
void addPhone( Event e, var detail, Node target ) {
$['rows'].children.add( new Element.tag('email-tag'));
$['rows'].on["notneeded"].listen((Event e) {
(e.target as Element).remove();
});
}
Also, I would change the name of deletePhone, since the method no longer deletes the record but merely informs the parent that it is not needed. Call it 'notNeeded' or something similar.
EDIT
#ShailenTuli is right about encapsulation should not be broken.
But also JS Polymer elements access the parent in their layout elements because it's still convenient in some scenarios.
This works now in PolymerDart too.
(this.parentNode as ShadowRoot).host
ORIGINAL
You can fire an event and make the email-view-tag listen to this tag and the event handler can remove the event target from it's childs.
I had a similar question a while ago:
How to access parent model from polymer component
This was actually the question I wanted refer to
How can I access the host of a custom element
but the first one may be of some use too.
PolymerJS FAQ - When is the best time to access an element’s parent node?
attached() currently still named enteredView() in Dart, but will be renamed probably soon.

How do I fire a custom event from Polymer Dart?

I want to fire/send/emit a custom event from inside a Polymer element. For example, I want to convert a normal DOM event like "changed" to a more semantic event like "todoupdated".
This is the HTML that I have:
<polymer-element name="todo-item" extends="li" attributes="item">
<template>
<style>
label.done {
color: gray;
text-decoration: line-through;
}
</style>
<label class="checkbox {{item.doneClass}}">
<input type="checkbox" checked="{{item.done}}">
{{item.text}}
</label>
</template>
<script type="application/dart" src="todo_item.dart"></script>
</polymer-element>
I want the change events on checkbox to bubble out of the custom element as something more... useful. :)
Step 1
Capture the change events on the <input>. Notice the on-change below.
<!-- from inside todo_item.html -->
<input type="checkbox" checked="{{item.done}}" on-change="{{change}}">
Step 2
Handle the change event in the custom element code that contains the checkbox.
import 'package:polymer/polymer.dart';
import 'dart:html';
import 'models.dart';
#CustomTag('todo-item')
class TodoItemElement extends PolymerElement with ObservableMixin {
#observable Item item;
bool get applyAuthorStyles => true;
void change(Event e, var details, Node target) {
// do stuff here
}
}
Notice the change event handler. That method is run any time the checkbox state changes.
Step 3
Dispatch a custom event.
void change(Event e, var details, Node target) {
dispatchEvent(new CustomEvent('todochange'));
}
NOTE: the custom event name must not contain dashes.
Step 4
Listen for the custom event in a parent custom element.
<template repeat="{{item in items}}" >
<li is="todo-item" class="{{item.doneClass}}" item="{{item}}" on-todochange="todoChanged"></li>
</template>
Notice the use of on-todochange.
Enjoy!
Polymer has a helper method that simplifies firing events
// dispatch a custom event
this.fire('polymer-select', detail: {'item': item, 'isSelected': isSelected});
Additional info:
To make the event available to subscriber that want to add a listener programmatically
// getter
async.Stream<dom.CustomEvent> get onPolymerSelect =>
PolymerSelection._onPolymerSelect.forTarget(this);
// private EventStreamProvider
static const dom.EventStreamProvider<dom.CustomEvent> _onPolymerSelect =
const dom.EventStreamProvider<dom.CustomEvent>('polymer-select');
subscribe to the event programmatically instead of declaratively:
($['#ps'] as PolymerSelect) // get the children and cast it to its actual type
.onPolymerSelect.listen((e) => print(e['isSelected'])); // subscribe
I managed this using <core-signals> and the polymer helper method fire. This way you are able to listen to events fired from elements that are not children. source.
todochange.html
<!doctype html>
<polymer-element name="todo-item" extends="li">
<template>
<style>
label.done {
color: gray;
text-decoration: line-through;
}
</style>
<label class="checkbox {{item.doneClass}}">
<input type="checkbox" checked="{{item.done}}">
{{item.text}}
</label>
</template>
<script type="application/dart" src="todo_item.dart"></script>
</polymer-element>
todochange.dart
import 'package:polymer/polymer.dart';
import 'dart:html';
#CustomTag('todo-item')
class TodoItemElement extends PolymerElement {
#observable Item item;
void change(Event e, var details, Node target) {
// the name is the name of your custom event
this.fire( "core-signal", detail: { "name": "todochange" } );
}
}
Then any subscriber just has to do this
subscriber.html
...
<link rel="import" href="packages/core_elements/core_signals.html>
...
<template>
<core-signals on-core-signal-todochange="{{handleToDoChange}}"></core-signals>
...
</template>
subscriber.dart
#CustomTag( "subscriber" )
class Sub extends PolymerElement {
...
void handleToDoChange( Event e, var detail, Node target ) {
print( "Got event from <todo-item>" );
}
...
}

Using Select Element in polymer dart component

Trying to use Select component in custom element as follows. button click works but when an item is selected in the list, the 'selected' and 'value' attribute does not change and list always shows the first element selected. Binding seems to work from dart to html but not from html to dart. Help please!
<html>
<head>
<title>index</title>
<script src="packages/polymer/boot.js"></script>
</head>
<body>
<polymer-element name="my-element" extends="div">
<template >
<button on-click='bclick'>Add new fruit</button>
<select selectedIndex="{{selected}}" value="{{value}}">
<option template repeat="{{fruit in fruits}}">{{fruit}}</option>
</select>
<div>
You selected option {{selected}} with value-from-list
{{fruits[selected]}} and value-from-binding {{value}}
</div>
</template>
<script type="application/dart" src="polyselect.dart"></script>
</polymer-element>
<my-element></my-element>
<script type="application/dart">main() {}</script>
</body>
</html>
Dart file is as follows:
import 'package:polymer/polymer.dart';
import 'dart:html';
#CustomTag('my-element')
class MyElement extends PolymerElement {
#observable int selected = 1; // Make sure this is not null.
// Set it to the default selection index.
List fruits = toObservable(['apples', 'bananas', 'pears', 'cherry', 'grapes']);
#observable String value = '';
void bclick(Event e) {
fruits.add("passion fruit");
}
}
I had to mixin the ObservableMixin class.
class MyElement extends PolymerElement with ObservableMixin

Resources