Extending dart:html class "ButtonElement" in Dart - html

I tried to extend a <button>, but so far did not succeed.
What am I doing wrong. I'm using the Dart Editor+SDK 1.5.2
In pubspec.yaml the version for Polymer is set to:
polymer: ">=0.11.0 <0.12.0"
index.html
<!DOCTYPE html>
<html>
<head>
<!-- <script src="packages/web_components/platform.js"></script>
not necessary anymore with Polymer >= 0.14.0 -->
<script src="packages/web_components/dart_support.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Extended Button - Dart v1.5.2</title>
<!--Extended Button-->
<link rel="import" href="view/ext_button.html" />
</head>
<body>
<button is="ext-button">Test Button</button>
<script type="application/dart">export "package:polymer/init.dart";</script>
</body>
</html>
view/ext_button.dart
import "dart:html";
import "package:polymer/polymer.dart";
#CustomTag("ext-button")
class ExtButton extends ButtonElement {
ExtButton.created() : super.created();
factory ExtButton(){
onClick.listen(clicked);
}
void clicked(MouseEvent e){
print("Ext-Button clicked");
}
}
view/ext_button.html
<!DOCTYPE html>
<link rel="import" href="packages/polymer/polymer.html">
<polymer-element name="ext-button" extends="button">
<template>
</template>
<script type="application/dart" src="ext_button.dart"></script>
</polymer-element>
So the code above does not work, but as soon as write it like below (just to validate the ext-button works) it tells me the following:
"web/index.html:20:7: custom element "ext-button" extends from "button", but this tag will not include the default properties of "button".
To fix this, either write this tag as <button is="ext-button"> or remove the "extends" attribute from the custom element declaration."
<ext-button>Test Button</ext-button>
So a little bit confused ;-) I think the fix is easy and simple - but I just don't see the problem ;-(

Just for further references, the two things above solved the problem.
Here are the updated parts, now it works.
view/ext_button.dart
import "dart:html";
import "package:polymer/polymer.dart";
#CustomTag("ext-button")
class ExtButton extends ButtonElement with Polymer {
ExtButton.created() : super.created()
{
polymerCreated();
onClick.listen(clicked);
}
void clicked(MouseEvent e){
print("Ext-Button clicked");
}
}
view/ext_button.html
<!DOCTYPE html>
<link rel="import" href="packages/polymer/polymer.html">
<polymer-element name="ext-button" extends="button">
<template>
<content></content>
</template>
<script type="application/dart" src="ext_button.dart"></script>
</polymer-element>

As far as I see, you are missing thwo things:
a call to polymerCreated() inside the custom elements constructor.
and extends ButtonElement with Polymer
There are already similar question. I'll look them up later when I have more time. Maybe you find them yourself in the meantime. Please add a comment with a link if you do.

Related

Importing multiple React components into html

I am trying to inject some React code into an HTML document. I am following React's own documentation and feeding their starter code (a simple like button) into the page. Everything was working great. I changed it to use JSX, changed it to a functional component using hooks instead of a class component with state. No problems.
However, whenever I include an import call and try to bring in another component, the component breaks on the page and stops displaying, but doesn't throw any kind of error I can see.
How do I develop in a "react-y" way with components and modularity while injecting it into an html page?
Here is the code I'm working with at the moment:
HTML document
<body>
<div id="react-root"></div>
<!-- inject react, reactDOM and JSX engine -->
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<!-- point to component -->
<script src="transpiled/app.js"></script>
</body>
React Component
'use strict';
import {SecondComponent} from './components/SecondComponent';
const e = React.createElement;
const LikeButton = () => {
const [liked, setLiked] = React.useState(false);
if (liked) return 'You liked this functional component.'
const handleLikeClick = () => {
setLiked(true);
}
return (
<div>
<button onClick={handleLikeClick}>new like button with jsx</button>
{liked && <SecondComponent/>}
</div>
)
}
const domContainer = document.querySelector('#react-root');
ReactDOM.render(e(LikeButton), domContainer);
Like I said, any sort of import statement seems to be where it breaks. Can't find resources online about it. Thanks in advance for your help!
UPDATE: After a bit of research importing modules between several <script> tags is now possible.
This can be achieved adding the Babel Plugin attribute data-plugins and setting the value to "transform-es2015-modules-umd" which will enable the UMD pattern.
You'll also need to set type="text/babel" on each <script> tag.
This will allow you to use the import statements directly inside each file. Like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React</title>
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script data-plugins="transform-es2015-modules-umd" type="text/babel" src="./Header.js"></script>
<script data-plugins="transform-es2015-modules-umd" type="text/babel" src="./App.js"></script>
</body>
</html>
Working Gist Example

How to combine iron-timer and moment-js to show hh:mm:ss format in polymer

I'm trying to convert the time I use in a timer to hh:mm:ss format using moment js but getting stuck. Below is my code.
<iron-timer id="timer" start-time="150" end-time="0" current-time="[[currentTime]]">
<moment-js date="[[_calculatedTime(currentTime)]]"></moment-js>
</iron-timer>
So when the time starts the time doesn't update in case of a formatted date. How can I get this to work
Here's what I came up with, but your question is somewhat incomplete, so correct me if I'm going a wrong way.
Component dependencies: polymer 2.5, iron-timer 2.1.2, moment-js 0.7.2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Timer</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/iron-timer/iron-timer.html">
<link rel="import" href="../bower_components/moment-js/moment-js.html">
</head>
<body>
<dom-module id="moment-timer">
<template>
<iron-timer id="timer" start-time="150" end-time="0" current-time="{{currentTime}}"></iron-timer>
<moment-js date="[[_toMilliSecs(currentTime)]]" format="HH:mm:ss" utc></moment-js>
</template>
<script>
class MomentTimer extends Polymer.Element{
static get is(){
return 'moment-timer';
}
static get properties(){
return {
currentTime: Number
}
}
_toMilliSecs(currentTime){
return currentTime * 1000;
}
ready(){
super.ready();
this.$.timer.start();
}
}
window.customElements.define(MomentTimer.is,MomentTimer);
</script>
</dom-module>
<moment-timer></moment-timer>
</body>
</html>
There are a few things to note:
You have to start the timer somewhere in your script. I did this in the ready() callback. Make sure to call super.ready() first.
You need to pass the currentTime property as milliseconds to the moment-js element - I use a method _toMilliSecs to do just that.
As shown in one of the demo-examples from moment-js, you need to set the utc property on the moment-js element. This is necessary to give a starting reference for your count-down. Essentially, we have it calculate the time from 1970-01-01 00:00:00 and set the timer relative to that. The effect is the same.
Hope that helps!

how to render a raised paper-button with reactjs?

Here is the code that should render a "raised" paper-button:
All the code is in a script tag and renders a paper-button that is not RAISED (see screen shot). I can click and see the RIPPLE effect, seems perfect except the appearance.
UPDATE :
for the moment the only way to get the correct rendering is by replacing
<paper-button raised>test</paper-button>
BY
<div dangerouslySetInnerHTML={{__html: '<paper-button raised>test</paper-button>'}} />
ANY WORKAROUND avoiding this 'dangerous' way?
<!DOCTYPE html>
<html>
<head>
<script src="bower_components/webcomponentsjs/webcomponents.min.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="bower_components/paper-button/paper-button.html">
<title>Hello React</title>
<script src="bower_components/react/react.min.js"></script>
<script src="bower_components/react/JSXTransformer.js"></script>
</head>
<body>
<div id="content">
</div>
<script type="text/jsx">
var ButtonT = React.createClass({
render: function() {
return (
<div>
<paper-button raised="true">test</paper-button>
</div>
);
}
});
React.render(
<ButtonT />,
document.getElementById('content')
);
</script>
</body>
</html>
Should the "raised" attribute be passed as a this.props...?
It won't work in the current version of React. Custom attribute support is an open issue, though. For now, I've found this patch works well.
In JSX if you want a custom HTML attribute, you should prefix it with data-, it then will be resolved to actual name without prefix. See docs;

Dart - Referencing outer HTML div using querySelector from Polymer class

I'm trying to get a reference of outer HTML(index.html)'s div from the polymer dart class. I know I can query the reference of app_element.html's div by the following code:
shadowRoot.querySelector('#select_this')
However, if I were to get a reference of index.html's div (#select_this), how can I do that from app_element.dart class? Is this even possible? If not, how can I design the polymer elements so that it can access DOM of other HTML pages and not only the ones that bind that particular polymer element?
app_element.dart
#CustomTag('app-element')
class AppElement extends PolymerElement {
#override
void attached() {
var my_div = shadowRoot.querySelector('#select_this'); // contains app_element.html's #select_this div
}
}
index.html
<html>
<body>
<head>
<link rel="import" href="../lib/app_element.html">
</head>
<app-element></app-element>
<div id="select_this"></div> <!-- Not sure how to select this... -->
<script type="application/dart">export 'package:polymer/init.dart';</script>-->
<script src="packages/browser/dart.js"></script>
</body>
</html>
app_element.html
<!DOCTYPE html>
<polymer-element name='app-element'>
<div id="select_this"> <!-- selectable via: shadowRoot.querySelector('#select_this') -->
<script type="application/dart" src="app_element.dart"></script>
</polymer-element>
Use the documents querySelector instead:
import 'dart:html';
...
document.querySelector('#select_this');
You can get access to elements within other elements shadow DOM
// old
document.querySelector('* /deep/ #select_this');
// or new (probably not yet supported everywhere
document.querySelector('* >>> #select_this');

Understanding the constructor attribute in Polymer elements

A Polymer noob...
I'm trying to create a custom element as per the Polymer API docs, where my main page looks like this:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Polymer</title>
<script src="bower_components/platform/platform.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html">
</head>
<body>
<div id="test"></div>
<polymer-element name="book-template" constructor="BookTemplate" noscript>
<template>
<style>
h1 { color: orange; }
</style>
<h1>Hello from some-foo</h1>
</template>
</polymer-element>
</body>
</html>
I know that the page content will render if I just put <book-template></book-template> on the page, or if I do something like this inside the <body> tag:
<script>
var book = document.createElement('book-template');
document.getElementById('test').appendChild(book);
</script>
But I'm trying to utilize the element's constructor attribute, assuming that this will create the element when placed somewhere inside of <body>:
<script>
var book = new BookTemplate();
</script>
...but getting a console message that BookTemplate() is not defined.
I'm sure it's something simple...any idea? Thanks in advance.
I guess you have to wait for the polymer-ready event, so that the constructor is available in the global window object http://jsbin.com/kosuf/2/edit?html,console,output:
<script>
document.addEventListener('polymer-ready',function() {
var book = new BookTemplate();
if (book) {
console.log('Ok');
}
});
</script>