I'm trying to get Angular Dart to display a link in a tag from an HTML string.
At first, I tried to just set the inner HTML of the container to be the HTML string, but that didn't work, so I then I tried to use Dart's DomSanitizationService class, but that also doesn't seem to work.
What I have so far is
Dart:
class SomeComponent {
final DomSanitizationService sanitizer;
SafeUrl some_url;
SomeComponent(this.sanitizer) {
some_url = this.sanitizer.bypassSecurityTrustUrl('https://www.google.com');
}
String html_string = '''
<a [href]="some_url">Hi</a>
''';
String get Text => html_string;
}
HTML:
<div [innerHTML]="Text"></div>
The error I'm getting is Removing disallowed attribute <A [href]="some_url">. The text Hi seems to show, but there is no link anymore.
Just as you bypassed URL sanitanization, you have to bypass HTML sanitanization as well using bypassSecurityTrustHtml to return markup.
https://angular.io/api/platform-browser/DomSanitizer#bypassSecurityTrustHtml
app_element.dart
library attribute_binding.app_element;
import 'package:angular2/angular2.dart';
import 'package:attribute_binding/app_element.dart';
#Component(selector: 'app-element', templateUrl: 'app_element.html')
class AppElement {
#Input() String attr2 = 'foo';
}
app_element.html
<h2>app-element</h2>
<div my-attr="attr1">attr1</div>
<div [my-attr]="attr2">attr2 {{attr2}}</div>
so that both <div> get a green background color?
With the code above only the first <div> gets a green background.
If you want to bind to an attribute instead of a property of the element, you must use the form [attr.my-attribute]="expression".
For more info about it you can see the official cheatsheet and Template syntax - Attribute, Class, and Style Bindings from the official doc as well.
Regarding your finding, that seems to be from an old PR (15 July) and see that it's not being even exported, and most important you can't find that const anymore in the latest master (see dom_renderer).
Glad it helped.
I'm using PaperInput and like the feel. But, is there a way to do the validation using my own logic? For instance, in some cases a pattern match is not enough to determine the error I'd like to display. An example would be I want the PaperInput to specify an item which can only be added once, so the validation would do a lookup in some model map and if input.inputValue is not present it is valid, otherwise invalid.
<paper-input floatingLabel
id="alias-input"
validate="{{aliasIsValid}}"
type="text"
error="{{aliasError}}"
label="Person Alias (eg: King, Eldest Son, Mooch, etc.)"
required
></paper-input>
So, I would like to be able to implement bool aliasIsValid() and set #observable String aliasError when validation is invalid. I do not think this is how it works, but is there a way to achieve this?
Polymer.dart <= 0.16.x
import 'dart:html';
import 'package:polymer/polymer.dart';
import 'package:core_elements/core_input.dart';
#CustomTag('app-element')
class AppElement extends PolymerElement {
AppElement.created() : super.created() {}
void inputHandler(Event e) {
var inp = ($['custom'] as CoreInput);
// very simple check - you can check what you want of courxe
if(inp.inputValue.length < 5) {
// any text is treated as validation error
inp.jsElement.callMethod('setCustomValidity', ["Give me more!"]);
} else {
// empty message text is interpreted as valid input
inp.jsElement.callMethod('setCustomValidity', [""]);
}
}
}
To validate only when the input element loses focus remove validateImmediately from the HTML element and use the on-change event instead (not tested).
<paper-input id="custom" on-input="{{inputHandler}}" validateImmediately></paper-input>
I added a comment at https://github.com/dart-lang/core-elements/pull/102 to make this method available directly in Dart with the next update.
The documentation of <core-input> states that the HTML5 constraint validation API is supported. For more information see
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation
Here's something I thought might be a bit easier. Despite the specifics of the question, I'm interested in any method that will let me have a third form field auto-updated based on the content of two other fields with Polymer.dart.
Something like this, where the "[ ]" represent form fields.
Name: [given name] [family name]
Full name: [family_name, given_name]
So for example; if someone enters "John" and "Smith" in the first two fields. Then the "full name" line shows: [Smith, John], when either of the fields are updated.
I've based the following example on the classes and mark-up from the form Dart Polymer tutorial
Get Input from a Form tutorial
For a form like this ...
<polymer-element name="reference-form" extends="form" >
<template>
<style> ... </style>
<div id="slambookform" >
<div class="entry">
<label>Author:</label>
<input type="text" value="{{theData['authorGivenName']}}" >
<input type="text" value="{{theData['authorFamilyName']}}">
</div>
:
<div class="entry">
<label>Full name:</label>
<input disabled type="text" value="{{fullName}}" >
</div>
:
</div>
<template>
</polymer-element>
My initial attempt to make this happen was a function like:
#observable
String fullName(){
return theData['authorFamilyName'] +', '+ theData['authorGivenName'];
}
Which doesn't work. When I make 'fullName' to an #observable variable and update it with a button the form is updates as required. Hence my question, can I bind a third field to two (or more) others?
I think I will need some kind of event handler. For two fields, formatting on a change even is simple enough. I want to format several fields in the ultimate case, not just two fields.
While on this topic, is there a hook in dart-polymer or dart to supply a future or call-back? In my example, something like: 'after-change'. Just thinking out loud, something like that would be good.
Thanks in advance.
Along those lines (caution - code is not tested)
<polymer-element name="reference-form" extends="form" >
<template>
<style> ... </style>
<div id="slambookform" >
<div class="entry">
<label>Author:</label>
<input type="text" value="{{authorGivenName}}" >
<input type="text" value="{{authorFamilyName}}">
</div>
:
<div class="entry">
<label>Full name:</label>
<input disabled type="text" value="{{fullName}}" >
</div>
:
</div>
<template>
</polymer-element>
class reference_form.dart
String _authorGivenName;
#observable get authorGivenName => _authorGivenName;
set authorGivenName(String val) {
_authorGivenName = val;
notifyPropertyChange(#fullName, '${_authorGivenName} ${_authorFamilyName}',
'${val} ${_authorFamilyName}');
}
String _authorFamilyName;
#observable get authorFamilyName => _authorFamilyName;
set authorFamilyName(String val) {
_authorFamilyName = val;
notifyPropertyChange(#fullName, '${_authorGivenName} ${_authorFamilyName}',
'${_autorGivenName} ${val}');
}
#observable
String get fullName => '${_authorGivenName} ${_authorFamilyName}';
I have a workaround for this problem, standing on the shoulders of Günter Zöchbauer (comment above). My objective is to "bind" one field value to two in a read-only fashion. We are not quite there yet, however the pathway is educational in its own right.
Observer method
This solution is kind of a workaround for the objective I set myself. I've made some annotations on this code to explain what I saw, or why I think is happening.
The intention is for fullName to show both names in the form:
familyName, givenName; e.g.
Smith, John
reference-form.html:
<polymer-element name="reference-form" extends="form" >
<template>
<style> ... </style>
<div id="slambookform" >
<div class="entry">
<label>Author:</label>
<input type="text" value="{{theData['givenName']}}" >
<input type="text" value="{{familyName}}">
</div>
:
<div class="entry">
<label>Full name:</label>
<input disabled type="text" value="{{fullName}}" >
</div>
:
</div>
<template>
</polymer-element>
The code for the form properties, the things Polymer-dart binds to the HTML with the moustache syntax, "{{fullName}}". To keep things simple, I used just one 'notifier' field and this updates the fullName field from both familyName and givenName.
reference_form.dart:
//---- testing ----
String _familyName; // (1)
#observable // (2)
String get familyName => _familyName; // (3)
void set familyName( String nam ){ // (4)
_familyName = nam;
fullName = notifyPropertyChange( // (5)
#fullName,
"${fullName}",
"${nam}, ${theData['givenName']}" );
}
#observable
String fullName; // (6)
//---- end: testing ----
The private member, "_familyName", is a shadow for the public familyName property used in the template (snippet above).
Shadow (private) member, "_familyName", stores the data for the familyName pseudo property.
The next three lines declare an #observable property, familyName
Get familyName. Simply echo the value for the shadow variable.
Set familyName. Updates the shadow variable and the composite fullName property.
Note: the composit formatting could be done with two lines: _familyName = nam; fullName = nam; ... But we want to see all changes propagated see (#5).
The notifyPropertyChange() method updated all observers of the fullName property.
Note: I didn't hack around inside Polymer itself; inside the Observable class, fullName doesn't has no observers with the code shown.
Until I saw this, I assumed that the Polymer binding to the HTML template was via an observer (watcher), it would seem not. I may be mistaken. In any case, the call to notifyPropertyChange() for the '#fullName' symbol didn't change the results for this test case.
fullName property bound to the Polymer form.
Basically the {{fullName}} value will be updated every time there's a change to the familyName pseudo property.
Note on efficiency:
The familyName setter is called with every keystroke (observed while debugging). I understand that, and suggest it is not always really the best solution.
For me, I'd prefer to only call the setter when a user exits the field. However when I used onblur, the trigger was a blur of the form, not the field.
It seems that we might all benefit in terms of performance with a bit more insider information about these hooks, pathways and any options available to make things more efficient.
Comments and improvements welcome. This example is a workaround for me, so its definitely a work in progress. ;-)
Encapsulation method
I am evolving a solution closer to the original ambition and based on the 'observer method' above. This approach relies on the current, i.e. Dart v4, use of modules and libraries. I'll show the working code first and explain interesting stuff with notes.
reference_form.dart:
import 'package:exportable/exportable.dart'; // [1]
class _Data // [2]
extends Object with Exportable { // [3]
#export String publishDate; // [4]
#export String authorGivenName = '(given)';
#export String authorFamilyName = '(family)';
#export String authorUrl = '';
//--- attributes ---
String get fullName => "${authorFamilyName}, ${authorGivenName}"; // [5]
void set fullName( String nam ){ // [6]
//don't need this
}
//--- ctor ---
_Data(){
publishDate = new DateTime.now().toString(); // [7]
}
} //_Data
#CustomTag('reference-form')
class SlamBookComponent extends FormElement with Polymer, Observable {
SlamBookComponent.created() : super.created();
//---- testing ----
#observable
_Data data = new _Data(); // [8]
:
} //SlambookComponent
Notes:
Include Exportable mixin to convert to JSON. I'm not exporting 'fullName' because it is just formatting at the moment.
Add exportable to your pubspec.yaml and 'Run Pub get'.
The "_Data" class is private to the reference_form.dart module. I did a bit of testing of the scope rules because I do not want the internal data structure to leak, except for something catholic like JSON of course (small-c).
Bring-in the Exportable mixin.
I have tested Exportable, it implements exactly what I thought I'd have to write myself. Happy with this.
JSON is not a requirement of the original question; but I did want the (eventual) solution to be a first class artefact that can be serialized or saved is important in the majority of my use-cases.
This is a very good example of the facility to extend Dart quick and agile!
Use the #export modifier to identify fields specific to be interchanged as JSON.
Export the fullName attribute as a String (get).
There is no need for set operation. However Dart apparently insists that a Set method matches 'get'.
I am disappointed by this. I much prefer the idea that I can have READ-ONLY properties and attributes, e.g. like ruby.
As tested, Dart SDK v1.4.0; fails when a matching setter is not implemented/declared(??).
Use a constructor to set initial values for Date data attribute.
Declares an opaque public property called "data", as an (private) _Data instance.
The data formatting of key fields is encapsulated in the private _Data declaration.
The Exportable mixin interface is used to map the private class to a public JSON result.
Point #8 demonstrates a powerful aspect of dart, to enable an opaque implementation of objects and yet, you can 'deliver'/'share' details without specific internal details.
I have run this code and checked that the concepts work for hidden data (the _Data type) and opaque access and serialisation. Also you can't accidentally look at internal private type (accidentally, although explicit hacks may be possible). I don't apologise for accepting the C / C++ conscious responsibility paradigm -- I think this a the most powerful aspect of being a programmer; WE are responsible for effects/bugs stemming from the code we produce. I recommend testing 'bits of behaviour' in small mini-use-cases.
I put examples of the polymer markup; nothing surprising. For me this approach is less verbose and a bit more Object Oriented than the original (early) Dart tutorial
reference_form.html
<polymer-element name="reference-form" extends="form" >
<template>
<style> ... </style>
<div id="slambookform" >
<div class="entry">
<label>Author:</label>
<input type="text" value="{{data.authorGivenName}}" >
<input type="text" value="{{data.authorFamilyName}}">
</div>
<div class="entry">
<label>Published:</label>
<input type="date" value="{{data.publishDate}}">
</div>
</div>
</template>
<script type="application/dart" src="reference_form.dart"> </script>
</polymer-element>
In the Polymer mark-up can know (and has visibility over) internal field names. Why?
... Because the "reference_form.html" and "reference_form.dart" via Polymer-dart. It is quite nice really; although it seems that the ".dart" and ".html" components are closely coupled like ASP.NET and C#/VN.NET as (also) specified by convenience(??). I confess that's a completely different subject; there are things to resolve to keep things yar (yachting term).
Anyway for me, I feel the approach begun with the encapsulation shamble above is better suited to my needs for a small utility.
Polymer now supports this use case directly with #ObserveProperty
#observable String authorGivenName = '';
#observable String authorFamilyName = '';
#observable String get fullName => '${authorGivenName} ${authorFamilyName}';
#ObserveProperty('authorGivenName authorFamilyName')
void updateFullName(old) {
notifyPropertyChange(#fullName, old, fullName);
}
I'm enclosing my app in a Polymer element and I want to use another polymer element inside it. To call all the method of the inner element I'm trying to use $[].
Insider the external polymer element I have this:
ImageEditor ime;
DivElement div2;
ImageTool.created(): super.created(){
div2 = $["secondDiv"];
ime = $["imageEditor1"]
}
In the Html I simply have:
<polymer-element name="da-imagetool">
<template>
<div class="images" id="mainDiv">
<da-imageeditor id="imageEditor1" name="ied"></da-imageeditor>
with the script src at the end.
For some reason I get an exception when I assign the imageEditor1 to ime.
Exception: type 'HtmlElement' is not a subtype of type 'ImageEditor' of 'value'.
It looks like the browser hasn't upgraded the <da-imageeditor> elements.
Make sure that you <import> the <da-imageeditor> element, and have the correct #CustomTag annotation on the ImageEditor class declaration.
This is most likely an issue with the import path.
If you don't use the right path the type is not recognized (canonicalization problem)
This bug should be solved since a while
https://code.google.com/p/dart/issues/detail?id=15953
but I haven't worked with Polymer since.
Show your import paths (HTML and Dart) and the directory structure of your app (where is your entry page and your Polymer elements) then I'll take a look.
Which version of dart-polymer are you using? With the 0.9.5, the following lines:
XElement.created(): super.created() { print($['el-id']); }
void enteredView() { print($['el-id']); }
In created(), the referred element gives nothing whereas in enteredView(), it does refer to the specific element of the shadow root.
The behavior disappears if shadowRoot.querySelector('#el-id') is used in lieu of the shorthand map $['el-id'].