Need help with PolymerTS?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

nippur72
186 Stars 27 Forks MIT License 232 Commits 9 Opened issues

Description

Write Polymer 1.0 elements as TypeScript @decorated classes

Services available

!
?

Need anything else?

Contributors list

# 64,879
Shell
c-sharp
WPF
assembl...
138 commits
# 437,590
Dart
CSS
Shell
Google ...
7 commits
# 741,718
HTML
TypeScr...
3 commits
# 37,626
CSS
TypeScr...
Shell
typescr...
2 commits
# 378,095
HTML
CSS
Shell
cqrs
2 commits
# 40,026
C++
node
Node.js
emscrip...
2 commits
# 446,856
HTML
minific...
CSS
optimis...
1 commit
# 88,852
Shell
HTML
C++
quantum...
1 commit
# 34,550
OCaml
slack
f-sharp
allocat...
1 commit
# 5,108
TypeScr...
typescr...
Less
Mongoos...
1 commit
# 29,010
HTML
polymer
Shell
puppete...
1 commit
# 20,070
Svelte
stubs
Ember
Storybo...
1 commit

PolymerTS

Write Polymer 1.x elements as TypeScript @decorated classes.

NOTE: If you need to support Polymer 2.x or higher, see the official PolymerDecorators project. We will be working on providing a migration path for users that are currently using Polymer 1.0 and PolymerTS. To find out more (or help!), see issue #110.

Table of contents

Installation

Install via bower:

bower install -save polymer-ts
You'll get the following files in
bower_components/polymer-ts
: -
polymer-ts.html
the html file to include via
 that loads PolymerTS
- 
polymer-ts.min.html
the html file to include via
 that loads PolymerTS (minified version)
- 
polymer-ts.d.ts
the file to reference in your TypeScript code (
/// 
) -
polymer-ts.ts
the source TypeScript file for debugging purposes -
polymer-ts.js
or
polymer-ts.min.js
the JavaScript file if you want to include PolymerTS via


Supported features

  • Decorators
    • @component(tagName)
      sets component's name (equivalent to
      is:
      in PolymerJS)
    • @extend(name)
      extends a native tag (equivalent to
      extends:
      in PolymerJS)
    • @hostAttributes(attrs)
      sets host attributes (equivalent to
      hostAttributes:
      in PolymerJS)
    • @property(defs)
      sets a property (equivalent to
      properties:
      in PolymerJS)
    • @observe(propList)
      sets an observer function on single or multiple properties (equivalent to
      observers:
      in PolymerJS)
    • @computed()
      defines a computed property
    • @listen(eventName)
      sets an event listener function (equivalent to
      listeners:
      in PolymerJS)
    • @behavior(className)
      gets the behaviors of the class (equivalent to
      behaviors:
      in PolymerJS)
  • Registration functions
    • className.register()
      registers in Polymer
    • className.register(true)
      registers in Polymer but not in
      document.registerElement()
    • className.create()
      creates an instance of the element
  • Other
    • class constructor mapped to factory constructor (
      factoryImpl()
      )

Unsupported: - property defined with getter/setter

How to write elements

  1. Write elements as TypeScript classes
  2. Extend the
    polymer.Base
    class
  3. Use @decorators as needed

A class-element: - can have private properties/fields - can use class constructor (rendered as

factoryImpl()
) - can use inherited properties and methods - can use TypeScript Mixins

How to correctly reference in markup

In the

head
section of your main .html file:
   
   
   
   

   
   

   
   

In your custom element (e.g.

elements/my-element.html
): ```HTML <!-- ... your custom element here... -->
In your element typescript code (e.g. `elements/my-element.ts`):
```TypeScript
/// 

@component("my-element")
class MyElement extends polymer.Base
{
}

// after the element is defined, we register it in Polymer
MyElement.register();

The above example loads in the following order: - WebComponents - Polymer - PolymerTS - Your custom elements - Your app

Note: due to an issue in WebComponents, you can't use the

 tag on the main page to load PolymerTS or custom elements,
you have always to use the 
 syntax.

This will make sure that scripts will be loaded in the correct order in all browsers.

If for some reason you want to use script inclusion for your elements, you have to load Polymer and PolymerTS via script too. Polymer doesn't have a

polymer.js
file (it's shipped as
.html
only), but you can get one from greenify/polymer-js.

Starting the application

Any global code in your app that depends on Polymer should be started only after the event

WebComponentsReady
has been fired:
window.addEventListener('WebComponentsReady', (e) =>
{
   // any code that depends on polymer here
});

Using the yeoman generator to create new elements

New elements can be quickly scaffolded using the

polymerts:el
yeoman generator available with the package generator-polymerts.

First install

yeoman
and
generator-polymerts
:
npm install -g yo
npm install -g generator-polymerts
then use the
polymerts:el
generator to create a new element:
yo polymerts:el my-element

Decorators explained

@component(tagName)

Sets the tag name of the custom component. The decorator is applied on the

class
keyword. Tag names must include a
-
as per WebComponents specs.

Example of a

:
@component("my-element")
class MyElement extends polymer.Base
{
}

If the component extends a native HTML tag, pass the "base" tag name as second argument (alternatively, use the

@extend
decorator)
@component("my-button","button")
class MyButton extends polymer.Base
{
}

@extend(tagName)

Specifies that the element is an extension of a native HTML element.

@component("my-button")
@extend("button")
class MyButton extends polymer.Base
{
}

@property(def)

Creates a Polymer property. It can be applied to a member field or a function. When applied to a function, the property becomes a computed property.

The parameter

def
is a map object that sets the options for the property:
{
    type?: any;                     // Boolean, Date, Number, String, Array or Object
    value?: any;                    // default value for the property
    reflectToAttribute?: boolean;   // should the property reflect to attribute
    readonly?: boolean;             // marks property as read-only
    notify?: boolean;               // if set to true, will trigger "propname-changed"
    computed?: string;              // computed function call (as string)
    observer?: string;              // observer function call (as string)
}

Examples:

TypeScript
@property({ type: number, value: 42 }) // Polymer initialization (preferred)
initialValue: number;

The default value for a property is optional as long as the property is initialized:

TypeScript
@property()
myprop = 42;  // direct initialization
or
@property({ type: number })
myprop: number;

constructor() { this.myprop = 42; // initialized within constructor; called after Polymer initialization }

NOTE: If you use direct initialization, the property will be set after the

ready()
method is called. If you use the
value
attribute of the
@property
decorator, it will be called before
ready()
.

NOTE: If you're creating a

readOnly
property, use Polymer initialization. If you use direct initialization, Polymer will overwrite your value with
undefined
.
@property({type: number, value: 42})
myprop: number;  // will be initialized with value before ready() is called

While you can specify

computed
and
observer
in a property definition, there are the specific decorators
@computed
and
@observe
that are easier to use.

@observe(propList)

Sets an observer function for a single property or a list of properties.

If observing a single property, the function must be of the type

function(newVal,OldVal)
.

If observing multiple properties (comma separated), the function receives only the new values, in the same order of the list.

// single property observer
@observe("name")
nameChanged(newName,oldName)
{
   // ...
}

NOTE: Only one single-property observer is supported for the same property name. If you have multiple single-property observers registered with the same property, only the last one one will be used (you will not get an error).

// multiple property observer
@observe("firstname,lastname")
fullnameChanged(newFirstName,newLastName)
{
   // ...
}

@computed

Creates a computed property or sets the function for a computed property.

The easiest way is to decorate a function that takes as arguments the properties that are involved in the computed property.

In the following example, a computed property named "fullname" is created, based on the properties "firstName" and "lastName":

@computed()
fullname(firstName,lastName)
{
   return firstName+" "+lastName; // firstname is the same as this.firstName
}

The decorator accepts also a map object for setting options on the property, e.g.:

TypeScript
@computed({ type: String })
fullname(firstName,lastName)
{
   return firstName+" "+lastName;
}

The

@computed
decorator is a shortcut for
@property
:
@property({computed: 'computefullname(firstName,lastName)'})
fullname: string;

computefullname(firstName,lastName) { return firstName+" "+lastName; }

@listen(eventName)

Sets a listener function for an event.

In the following example the function

resetCounter()
is called whenever the event
reset-counters
is triggered (e.g. via
fire()
).
   @listen("reset-counters")
   resetCounter() {
      this.count = 0;
   }

@behavior(className)

Incorporates behaviors from another object.

The object can be either a class (not necessarily a PolymerTS element) or a plain JavaScript object.

The

@behavior
decorator can decorate the
class
keyword or it can be put within the class itself.

Examples:

class MyBehavior extends polymer.Base
{
   @listen("something_has_happened")
   onBehave() {
      console.log("something_has_happened triggered");
   }
}
@component("my-element")
@behavior(MyBehavior)
class MyElement extends polymer.Base
{
  // ...
}

or

TypeScript
@component("my-element")
class MyElement extends polymer.Base
{
    @behavior(MyBehavior)
    // ...
}
Note: a functionality similar to
@behavior
can be also obtained by plain class inheritance or by the use of Mixins.

Writing elements only with code

It's also possible to create elements using TypeScript code only, without having any external .html. That can be useful if you want to keep template and logic in the same TypeScript file.

Use the tags

@template
and
@style
to specify the element's template and style, as in the following example: ```TypeScript @component("my-example")

// pass as argument what would be within and @template(

This element has been created completely from code
)

// pass as argument what would be within @style(

:host { display: block; } div { color: red; }
)

class MyExample extends polymer.Base { // ... }

MyExample.register(); ```

@hostAttributes(attributesObject)

Sets attributes on the host element.

In the following example, the

style
attribute of the host element is changed:
@component("my-element")
@hostAttributes({ style: "color: red;" })
class MyElement extends polymer.Base
{
}

Writing elements without using decorators

It's possible to avoid the use of decorators (e.g. for compatibility with TypeScript < 1.5) by simply writing their respective equivalent in plain Polymer syntax. E.g. ```TypeScript class MyElement extends polymer.Base { is = "my-element";

properties = { myprop: { value: 42 } };

// ... } ```

Examples

A timer-based counter element

@component("my-timer")
class MyTimer extends polymer.Base
{
   @property({ type: Number, value: 0 })
   public start: number;

public count: number;

private timerHandle: number;

constructor() { this.count = this.start; this.timerHandle = setInterval(() => { this.count++; }, 1000); }

@observe("count") countChanged(newValue, oldValue) { if(newValue==100000) { console.log("too much time spent doing nothing!"); this.fire("reset-counters"); } }

@listen("reset-counters") resetCounter() { this.count = 0; }

detatched() { clearInterval(this.timerHandle); } }

MyTimer.register();

   

To use the element

HTML

Using computed properties

There are several (almost equivalent) ways of defining a computed property:

// classic way
@property({name: "fullname", computed: "computeFullName(first,last)"});
fullname: string;
computeFullName(f,l) {
   return f+" "+l;
}

// by decorating a function @property({computed: "first,last"}); fullname(f,l) { return f+" "+l; }

// by using @computed, name and parameters extracted from the function @computed fullname(first,last) { return first+" "+last; }

Using custom constructor

Elements can be instantiated by using a custom constructor:

@component("my-info")
class MyInfo extends polymer.Base
{
   private someInfo: string;

constructor(someInfo: string) { this.someInfo = someInfo; } }

// creates the element passing a parameter var el = MyInfo.create("hello world");

// and attach in some way to the DOM document.body.appendChild(el);

Using behavior defined in paper elements

This example shows how to use a behavior defined in an external library (Polymer paper elements).

/// 

@component('ts-element') @behavior(Polymer['PaperRippleBehavior']) class TsElement extends polymer.Base implements Polymer.PaperRippleBehavior {
// stand-in properties for behavior mixins noink: boolean = false; ensureRipple: (optTriggeringEvent?: Event) => void; getRipple: () => paper.PaperRipple; hasRipple: () => boolean;

handleClick(e:Event) { this.greet = "Holà";
this.fire("greet-event"); this.ensureRipple(e); } }

What it does

In short, PolymerTS:

  • provides a class named
    polymer.Base
    that all your elements can extend
  • provides a suite of decorators to easily implement elements
  • injects the method
    register()
    in your element-class (to allow registration it in Polymer)

in turn, the

register()
method:
  • process decorators translating them in its Polymer counterpart
  • connects the
    constructor()
    before of the
    attached
    event so that properties are correctly initialized
  • connects the
    constructor(args)
    to the
    factoryImpl()
    callback so that custom constructor is processed correctly
  • registers the element in Polymer, saving the constructor function and making it available as the
    create()
    method

Documentation

Typically with Polymer projects you can generate documentation easily with the

 component. 
However, this component doesn't work well with PolymerTS projects because the source code is not in the same file as the HTML. You 
can get around this by using the polymerts-doc-generator, which outputs a version of 
your code that combines HTML and pure JS in one file, which can be easily consumed by 
.

Known issues

  • can't use property defined with
    get
    and
    set
    (Polymer's issue)
  • can't include elements using
     on the main .html page (WebComponent's issue)

Contributing

Contributions are welcome.

If you find bugs or want to improve it, just send a pull request.

Getting Started

  1. Clone this repo
  2. Make sure you have node and bower installed.
  3. Run
    npm install && bower install
  4. To build, just run
    npm run build
    . During development, using the TypeScript compiler settings in your editor should work fine, as long as it points to
    ./tsconfig.json
    and uses the version of
    tsc
    installed in
    node_modules
    .

Testing

PolymerTS uses Jasmine for unit tests. Currently there isn't a test runner like Karma setup, so you'll need to manually run the tests in different browsers.

All of the tests are in the

Test
folder; the entry point is
tests.ts
.

In order to run the tests, you need a local HTTP server. If you don't have one installed, you can install http-server with the command

npm install http-server -g
.

Next, just point your browser to

http://localhost:/Test/
).
http-server
defaults to port 8080.

Samples

There is a

Samples
folder with some examples, but these are not currently built or maintained.

Change log

  • For recent versions, see the Github release logs: https://github.com/nippur72/PolymerTS/releases

Older versions:

  • v0.2.0 (Apr 18, 2017)
    • Fix: allow access/modify styles (override prototype.style)
  • v0.1.28 (Aug 8, 2016)
    • Added
      unlisten()
      to API
  • v0.1.19 (Sep 16, 2015)
    • Extended
      @behavior
      to work with plain JavaScript objects (in addition to TypeScript classes)
  • v0.1.17 (Sep 14, 2015)
    • BREAKING CHANGE: (mostly harmless) Polymer.Base is now an extension of HTMLElement
    • Added
      is
      to Element's interface
  • v0.1.7 (Aug 7, 2015)
    • Corrected signature for
      Polymer.dom.flush()
  • v0.1.6 (Jul 21, 2015)
    • provided
      polymer-ts.d.ts
      to reference from external projects
    • no longer need to include
      webcomponents.js
      (non-lite) in IE
  • v0.1.5 (Jul 18, 2015)
    • BREAKING CHANGE: global functions
      createElement()
      and
      createClass()
      deprecated, use
      Element.resgister()
      instead
    • BREAKING CHANGE: use
       to load PolymerTS and custom elements
  • v0.1.4 (Jul 17, 2015)
    • register elements with
      className.register()
  • v0.1.3 (Jul 16, 2015)
    • polymer.Base is now seen as a full ES6 inheritable class
  • v0.1.2 (Jul 13, 2015)
    • Improved the way objects are instatiated
    • support for static method
      create()
      on the element class
  • v0.1.1 (Jul 10, 2015)
    • Added support for constructor() with parameters.
    • constructor()
      is now a replacement of
      factoryImpl()
      .
    • preamble
      implements polymer.Element
      no longer required
  • v0.1.0 (Jul 10, 2015)
    • Added support for class inheritance
    • Added support for use of
      constructor()
    • Added support for decorator-less syntax
  • v0.0.1 to v0.0.9
    • early experimental versions

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.