Giter VIP home page Giter VIP logo

polymerts's Introduction

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 <link rel="import"> that loads PolymerTS
  • polymer-ts.min.html the html file to include via <link rel="import"> that loads PolymerTS (minified version)
  • polymer-ts.d.ts the file to reference in your TypeScript code (/// <reference path="...">)
  • 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 <script src="">

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:

<head>
   <!-- webcomponents, polymer standard, polymer-ts -->
   <script src="bower_components/webcomponentsjs/webcomponents-lite.js"></script>
   <link rel="import" href="bower_components/polymer/polymer.html">
   <link rel="import" href="bower_components/polymer-ts/polymer-ts.html">

   <!-- your custom elements -->
   <link rel="import" href="elements/my-element.html">

   <!-- your application -->
   <script src="myapp.js"></script>
</head>

In your custom element (e.g. elements/my-element.html):

<dom-module id="my-element">
   <!-- ... your custom element here... -->
</dom-module>

<!-- your element code typescript transpiled file -->
<script type="text/javascript" src="my-element.js"></script>

In your element typescript code (e.g. elements/my-element.ts):

/// <reference path="../bower_components/polymer-ts/polymer-ts.d.ts" />

@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 <script> tag on the main page to load PolymerTS or custom elements, you have always to use the <link rel="import"> 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 <my-element>:

@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:

@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:

@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.:

@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

@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:

@component("my-example")

// pass as argument what would be within <dom-module> and </dom-module>
@template(`<div>This element has been created completely from code</div>`)

// pass as argument what would be within <style> and </style>
@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.

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();
<dom-module id="my-timer">
   <template>
      <p>This is a timer element, and the count which started
      from <span>{{start}}</span> is now: <span>{{count}}</span></p>
   </template>
</dom-module>

To use the element

<my-timer start="42"></my-timer>

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).

/// <reference path="typings/polymer/paper/PaperRippleBehavior.d.ts"/>

@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 <iron-component-page> 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 <iron-component-page>.

Known issues

  • can't use property defined with get and set (Polymer's issue)
  • can't include elements using <script> 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:<port>/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

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 <link rel="import"> 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

polymerts's People

Contributors

43081j avatar almstrand avatar aomarks avatar basarat avatar bpowers avatar fat-crienturu avatar jjrv avatar lgrignon avatar maffoo avatar nippur72 avatar techmatt101 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

polymerts's Issues

Can't add behavior IronControlState to component

(asked in stackoverflow as well http://stackoverflow.com/questions/32599151/importing-polymer-behavior-in-polymerts/32599461#32599461)

Trying to add the behavior for IronControlState to my web component. Here's a minimal working example:
Html Template"

<link rel="import" href="../bower_components/iron-behaviors/iron-control-state.html">

<dom-module id="beh-test">
  <template>
    <button on-click="func">BUTTON</button>
    <content></content>
  </template>
</dom-module>

TS code:

declare var Polymer: {IronControlState: {focused: boolean} };

@component('beh-test')
@behavior(Polymer.IronControlState)
export class BehTest extends polymer.Base {

  func() {
    console.log(this.focused);
    console.log(Polymer.IronControlState);
  }

  ready() {
    console.log('beh-test ready');
  }
}

Polymer.IronControlState is being imported correctly (it get printed to the console when func() is called ), but it's behaviour isn't being added. The browser console kicks out the warning [beh-test::_flattenBehaviorsList]: behavior is null, check for missing or 404 import

What am I doing wrong?

Write .d.ts definition files

The library needs to be written as a .d.ts file so that can it be published on DefinitelyTyped and imported more easily.

Cannot find notifySplices

Using version 0.1.24.
notifySplices is needed for array observation when one cannot use Polymer's array mutation functions.
(notifyPath does not work properly for arrays).

HTML Import polyfill bug

There is a flaw in the webcomponents polyfill (see here and here) that causes a wrong load order of PolymerTS in IE and FF, making it fail to initialize custom elements.

The correct order (Chrome) should be:

  1. webcomponents loads via <script>
  2. polymer loads via HTML import (<link rel="import">)
  3. polymer-ts loads via <script> and creates polymer.Base from Polymer.Base
  4. custom elements loads via HTML import
  5. element html is processed
  6. element typescript code loads via <script>
  7. element typescript code executes, polymer.Base is used to extend elements
  8. everything has loaded, webcomponents fires WebComponentsReady
  9. application responds to WebComponentsReady and starts itself

The bug makes point n.2 and n.3 to be after n.7, and thus point n.7 fails because polymer.Base is undefined.

@sorvell suggested that we listen to the HTMLImportsLoaded event before we initialize PolymerTS (delay n.3), but this is not enough because point n.7 still requires a working polymer.Base, and the only solution that comes in my mind is to add event-wait code for every defined element, which honestly is not viable.

I'm open to suggestions. Currently I've fixed by loading a home-made polymer.js via <script> in point n.2, avoiding the HTMLImport.

Other solutions include:

  • ship a concatenated version of polymer.js + polymer-ts.js with this package (making bowering of Polymer no longer necessary)
  • make HTML import of polymer-ts.js (point n.3) so that it's called in the correct order, but this requires that application is loaded also with an HTML import

Registering on dom-bind element (auto binding)

For main application polymer is using autobinding element described here:
https://www.polymer-project.org/1.0/docs/devguide/templates.html#dom-bind

I would like to have something like this in index.html:

<template is="dom-bind" id="main-app">                                       
    <div>Greet {{appGreet}}</div>                                  
</template>

and main-app.ts:

/// <reference path="../bower_components/polymer-ts/polymer-ts.d.ts"/>                                                              
@component('main-app')                                                                                                              

class MainApp extends polymer.Base {
   @property({ type: String })
   appGreet: string = "GREET!!!";

   public handleSomething() {
      console.log('Handle something');
   }
   public ready() {
     console.log( "READY!!!!")
   }
}

MainApp.register();

It's not working as expected. I guess problem is in component function however I'm not that oriented in polymerts to fix it or find workaround.

Behaviors not working in decorator-less definitions of a component

behaviors: any[] = [
FrostAura.Dynamics.Client.Behaviours.Core.FaCoreBehaviour
];

doesn't seem to work. Nor does (Becaue the polymer.Base extending makes it un-newable):
behaviors: any[] = [
new FrostAura.Dynamics.Client.Behaviours.Core.FaCoreBehaviour()
];

Am I doing this incorrectly or is it not yet supported?

Using polymer behaviors

Is using polymer behaviors, such as those from the neon-animation suite, supported in some manner? If not do you have any tips, tricks or advice about how to implement it?

Thanks.

Two way binding with <input value="{{myProperty}}" />

I'm trying out PolymerTS, with some basic experience in plain Polymer 1.0. Not sure I want the decorators but I could not get it to work without them. I am using TypeScript 1.5.

Now, I was able to bind a property to display to a div and to bind one-way to an input (to display the initial input value), but I've not been able to bind two-ways to the input : ts/js code is not getting the new value of the bound property if the user types something in the input, the value of the property remains the initial value no matter what I type in the input field.

Example:

(.html)
<input type="text" value="{{userName}}" />
(.ts:)
@property({ readonly: false }) userName = "myself";

p.s.: I tried with Polymer's paper-input as well, but no luck:
<paper-input value="{{userName}}"></paper-input>

Again, note that binding to a div works fine, as in this example:

(.html)
<template is="dom-repeat" items="{{tables}}">
  <div>{{item}}</div>
</template>
(.ts)
@property({ type: Array, value: function () { return []; } }) tables;
...
this.set('tables', myTableArrayData);

Thank you !

Upgraded to polymer 1.4, seeing weird issue with change observers now

They are getting called in some cases with strange values. This was working in 1.2

  @observe("pickedMesh")
  pickedMeshChanged(newMesh: THREE.Mesh, oldMesh: THREE.Mesh) {
    window.console.log(arguments);
    if (newMesh instanceof THREE.Mesh) // HAD TO ADD THIS
    ...

When first initialized, pickedMesh is getting called with strange values of true/false and instead they shouldn't be called at all till a user has loaded and clicked on a mesh

pv-view.ts:105 [true, undefined]
pv-view.ts:105 [false, null]
pv-view.ts:105 [null, true]
pv-view.ts:105 [null, false]

This works under polymer 1.2, and the logs are silent. Nothing appears.

Is @property() required?

I've added a class attribute to my component class and did not decorate it with @property keyword. This is still accessible from node.attrName and can be used inside of template via binding. Is this some edge case, or is it supposed to behave like that? Code looks much nicer without it, but I don't want to use it if it breaks in some cases.

Thanks,
Dan

Readme snippets

In the repo's main readme, the snippets for the property and observe annotations have semicolons at the end of the line.

Missing Element definitions

The following code runs as expected, though the TypeScript type checker does not recognize properties clientWidth or clientHeight:

/// <reference path="../../bower_components/polymer-ts/polymer-ts.ts" />


@component("my-element")

class MyElement extends polymer.Base {


    attached() {


      console.log(this.clientWidth + 'x' + this.clientHeight);

    }
}


MyElement.register();

Those properties are currently not defined in polymer.Base. Can this be corrected by having polymer.Base extend Element?

Of course, this request assumes that all custom elements are indeed of type Element, and I am not familiar enough with the Polymer 1.0 implementation to know whether that is the case. Is it correct that custom elements are always created by calling createElement() (which returns an object of type Element)?

I came across this issue filed with the TypeScript GitHub repository, which seems relevant. Perhaps that issue needs to be addressed before a change can be made in PolymerTS?

@observe does not work on path changes

Per the polymer guide, to observe path changes, one needs to add an observer to the list of observers, rather than adding it as a property annotation: (observing path changes)

However, currently the decorator will add an observer to the list of observers only if it has a comma, and will not add it to the list of observers if it has a dot. This can be fixed pretty simply by checking for a period as well as a comma when deciding which invocation to use. (I would submit a change myself, but I believe I am blocked by the lack of a LICENSE on the repository).

I would appreciate if this could be fixed in a release soon.

Annotated Event Listeners

The polymer website describes how to setup annotated event listeners:

https://www.polymer-project.org/1.0/docs/devguide/events.html

Simply writing another function on my custom element's class however does not expose the function properly. For example:

My .ts

@component('my-element')
class MyElement extends polymer.Base {
  public myFunction():void {
    console.log('Hello!');
  }
}
MyElement.register();

My .html

<dom-module id='my-element'>
    <template>
        <button on-click='myFunction'>Click Me!</button>
    </template>
</dom-module>

<script src='/my-element.js'></script>

In the console it logs: [my-element::_createEventHandler]: listener method 'myFunction' not defined. Is there a way to do this in Polymer TS?

What is the right way to wait for an element's constructor to be done

Say I have:

export class MyElement extends polymer.Base {
  field: number;

  constructor(n: number) {
    super();
    this.field = n;
  }
}

And I do:

const myElement = MyElement.create(arg);
Polymer.dom(someContainer).appendChild(myElement);

// I would like to access myElement.field after it is set by the constructor

AFAIU, the constructor (which is actually the factoryImpl) might not have been called yet at the bottom. What should I do in order to make sure that when I access myElement.field, the constructor has run? Is there an event/callback I can latch on, or do I need to implement some logic myself?

Thanks!

Using Typescript Module

Hi

What do you think to use module to better organize the polymer typescript?

Below my suggestion :

module polymer {

export class Base { ... }

export interface Element { ... }

export interface propDefinition { ... }

}  // end module

interface Polymer { ... }

declare var Polymer: Polymer;

function component(tagname: string) { ... }

function extend(tagname: string) { ... }

function hostAttributes(attributes: Object) { ... }

function property(ob: polymer.propDefinition) { ... }

function computed(ob?: polymer.propDefinition) { ... }

function listener(eventName: string) { ... }

function behavior(behaviorObject: any): any { ... }

function observe(propertiesList: string) { ... }

function createElement(element: Function): void { ... }

function createClass(element: Function): void { ... }

yeoman generator

Hi

I've thought that a yeoman generator would be useful to help, this amazing project, to be widely used

So I've released a first version of such generator available here

Please test it and if you consider it useful for project's growing , add it in PolymerTS' references

"Class constructor cannot be invoked without 'new'" error with es6 target

Hi there,

I'm getting following error:

TypeError: Class constructor FooBarElement cannot be invoked without 'new' 
in polymer-ts:208

I'm using the "target": "es6" option in my tsconfig.json file, and my element looks like:

@component('foo-bar')
class FooBarElement extends polymer.Base {
...
}

FooBarElement.register();

I took a look at your issues and some of your code, including this PR https://github.com/nippur72/PolymerTS/pull/27/files which seems to add support for es6, but didn't found yet a solution to solve the error.

Thanks for your work.

Decide what's best syntax for computed properties

We can choose between two alternative syntax for computed properties:

  • with @computed decorator
   // defines a computed property called "fullname" depending on "test" property
   @computed("fullname", "test")
   computeFullName(test)
   {
      return "Douglas Adams [" + test + "]";         
   }
  • allowing @property decorator to be applied on functions:
   @property({ name:"fullname", type: String, computed: "test" })
   computefullname(test)
   {
      return "Douglas Adams [" + test + "]";         
   }

unfortunately in the actual Polymer, a computed function can't have the same name as its property, so in the latter case we must have "computefullname" and { name:"fullname" }

Broken inheritance

It's not possible to have an element-class that extends another class that is not polymer.Base:

class MyAbstract extends polymer.Base implements polymer.Element {
  // methods here are not carried in the final polymer element
}

class My extends MyAbstract  {
  private myProp1: string = 'initialVal';
}

set() supports arrays

In the polymer-ts.d.ts you should have:

 set(path: string|[string, number], value: any, root?: Object): any;

function expression can not be observer

When using either:
@property({... observer: "dataChanged" })
data: any;

or
@observe("data")
public dataChanged(newValue, oldValue)

The observer works as expected, however if I change the function to be a function expression like this:
public dataChanged = (newValue, oldValue) => {...

The observer breaks and I get an error that the observer method "dataChanged" can not be found. I need the ability to use a function expression so that I can control the this reference inside of my event handler. If anyone can help point me in the right direction I can work on PR for this.

Thanks!

Error in polymer-ts.ts

Hello, and thank you for the nice work!

The compiler complains when processing polymer-ts.ts / polymer-td.d.ts: "A class may only extend another class." at: export declare class PolymerBase extends HTMLElement

Base.prototype.register() fails with extending class hierarchies

When inheriting from a polymer.Base derived class, the Register() method on the class prototype fails to work as expected.

  1. The derived element cannot fire Register without the error "element already registered in Polymer".
    (Fix: #57)
  2. In addition to the issue in addressed in #57, the extended element fails to correctly call the derived overrides.
    (Workaround: order registration from child to parent. See below)

These problems occur regardless of the import structure, so a single file example is enough to demonstrate the issue:

// base-element.ts
import 'polymer-ts';

@component('base-element')
export class BaseElement extends polymer.Base {
    ready() { 
        console.log(this.is + " element is ready!");
    }
}

BaseElement.register();

@component('new-element')
export class NewElement extends BaseElement {
    ready() { 
        // FAILS: even with the fix from #1, this override will not fire correctly.
        super.ready();
        console.log("this element is ready!");
    }
}

// FAILS: With "element already registered in polymer"
NewElement.register();

screen shot 2015-10-12 at 7 36 27 pm

Even with the fix from #1, the class inheritance overrides are not successfully applied:
screen shot 2015-10-13 at 1 01 18 pm

Workaround for the second part
@nippur72's suggestion to alter the order of registration shows the correct override behavior:

// BOTTOM of base-element.ts

// WORKAROUND: Order registration from children in hierarchy to parent
NewElement.register();
BaseElement.register();

screen shot 2015-10-13 at 1 02 58 pm

This correctly allows the registration of a hierarchy of derived classes, and displays the expected behavior.

The workaround can be extended as long as the registration is done in child > parent hierarchy order, including multiple children of the same class.

// BOTTOM of base-element.ts

@component('third-element')
export class ThirdElement extends BaseElement {
}

// ThirdElement.register(); // Could place it here
NewElement.register();
ThirdElement.register();  // Or here: New/Third* are the same class level in hierarchy, so order does not trigger the error
BaseElement.register();

screen shot 2015-10-13 at 1 14 15 pm

So a temporary workaround until this issue is fixed is to keep your registration order from child to parent.

Type-safety when calling Component.create

While the automatic plumbing of calls to create to the ready/constructor/attached methods is great, an annoying issue is that the type of the arguments passed to create is never checked against the type of the parameters received by constructor, but rather against the very liberal declared type of polymer.Base.create

Would it be conceivable to make it so that this is actually checked, by changing the plumbing a little?

Is there currently a use-case for calling new Element(args)? If not, could it be used as a shorthand for Element.create(args)? This would trick TypeScript into checking the arguments against the constructor arguments, even though behind the scenes the call is more complex.

Inconsistent change handler param order

Change handlers in Polymer take two parameters; the first one representing the old property value and the second representing the new value.

However, in polymer-ts, the order is reversed, e.g.:

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

This may be a bit opinionated, and of course polymer-ts can change the order, but to remain as API-compatible as possible and not to confuse users coming from the non-typescript world, it may be preferred to match the parameter order as defined in Polymer:

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

Classes do not inherit Typescript properties from Behaviors?

expected: if I have a behavior that defines a new member for the Typescript class, that member is implicitly mixed in to classes that reference that behavior via the decorator.

actual: the member is not mixed in, so that referencing it in the class using the behavior creates a type error.

is fixing this feasible within the constraints of typescript decorators?

Property changed callback not firing

Hi, I'm playing with Polymer + TS and I've found these definitions. I'm experiencing an issue when trying to react to a change in a 2-way bound property: the changed callback never gets called. Yet, as far as I can see by debugging it is correctly defined in the object prototype, and I get no errors in the console. I found no code example for observing a property change in your source, so maybe it's just me doing something stupid.
My element is fairly simple as this is just a test: its template contains an input to be 2-way bound to a property named text:

<input autofocus value="{{text}}" placeholder="enter text"/>

The TS relevant code is (note the notify:true and the callback named after the documented convention):

@tag("my-element")
class MyElement implements PolymerElement {
  @property({type: String, value: "example", notify: true })
  public text: string;
  ...
  public textChanged(): void {
      // this.text should contain the new value. Anyway this never gets called.
  }

}

Could anyone suggest a solution?

.d.ts files for Polymer Material elements

I've written a Babel plugin which parses standard Polymer javascript into TypeScript - https://github.com/nalbion/babel-plugin-polymer-to-typescript.

The output looks okay to my untrained eye, but when I try to generate .d.ts files from the generated .ts files I'm currently getting a bunch of errors - hopefully you can help and then I'll be able to publish about 100 auto-generated .d.ts files to DefinatelyTyped.

I've copied relevant snippets from the generated iron-behaviors/iron-control-state.ts with tsc errors below. Hopefully you'll have more experience with TypeScript than me.

/// <reference path="../../bower_components/polymer-ts/polymer-ts.d.ts"/>
/**
   * @demo demo/index.html
   * @polymerBehavior
   */
//  error TS2300: Duplicate identifier 'Polymer'
declare module Polymer {
  class IronControlState extends polymer.Base {

    /**
     * If true, the element currently has focus.
     */
    @property({
      type: Boolean,
      notify: true,
      readOnly: true,
      reflectToAttribute: true
    })
 // error TS1039: Initializers are not allowed in ambient contexts.
    focused: boolean = false;

    constructor() {
      super();
 // error TS1183: An implementation cannot be declared in ambient contexts.
      this._boundFocusBlurHandler = (() => {
        return this._focusBlurHandler.bind(this);
      })();
    }

   ready() {
// error TS2345: Argument of type 'Function' is not assignable to parameter of type 'EventListener | EventListenerObject'.
      this.addEventListener('focus', this._boundFocusBlurHandler, true);
      this.addEventListener('blur', this._boundFocusBlurHandler, true);
    }

    _disabledChanged(disabled, old) {
      this.setAttribute('aria-disabled', disabled ? 'true' : 'false');
      this.style.pointerEvents = disabled ? 'none' : '';
      if (disabled) {
// error TS1036: Statements are not allowed in ambient contexts.
        this._oldTabIndex = this.tabIndex;
        this.focused = false;
        this.tabIndex = -1;
      } else if (this._oldTabIndex !== undefined) {
        this.tabIndex = this._oldTabIndex;
      }
    }

    @observe('focused, disabled')
    _changedControlState() {
//error TS2339: Property '_controlStateChanged' does not exist on type 'IronControlState'.
      // _controlStateChanged is abstract, follow-on behaviors may implement it
      if (this._controlStateChanged) {
        this._controlStateChanged();
      }
    }

Changed handler not called

Setting notify: true in the object passed to the @Property annotation and modifying the corresponding property value does not cause the change handler to be called, e.g:

/// <reference path="../../bower_components/polymer-ts/polymer-ts.ts" />
@component(“my-component”)
class MyComponent extends polymer.Base {


    @property({type: Boolean, value: true, notify: true})
    public prop:boolean;


    public propChanged(oldValue:boolean, newValue:boolean) {

        console.log("not called")

    }

    
attached() {
        this.prop = false;
    }

}



MyComponent.register();

Note/work-around: The @observe decorator appears to work as expected.

Type checker complains as component is not of type HTMLElement

As of Polymer 1.0, the recommended way of accessing the local or light DOM is through Polymer.dom(this.root) and Polymer.dom(this).

According to the PolymerTS type definitions, "this" inside of polymer.Base does not refer to an HTMLElement so the Typescript type checker does not like the following example:

@component("my-element")
class MyElement extends polymer.Base implements polymer.Element
{
    attached() {
        let div1:HTMLDivElement = document.createElement('div');
        Polymer.dom(this).appendChild(div1);

        let div2:HTMLDivElement = document.createElement('div');
        Polymer.dom(this.root).appendChild(div2);
    }
}

The type checker complains:

TS2345: Argument of type 'MyElement' is not assignable to parameter of type 'HTMLElement'
TS2339: Property 'root' does not exist on type 'MyElement'

@computed with dotted property paths: clarify docs

Seems when the computed value is based on a sub-property, the @computed annotation style does not work. Maybe clarify in the documentation. Example:

    @property({ type: Object, notify: true })
    model: AppModel;

     // this does not compile
    @computed({ type: Boolean, notify: true })
    isAuthenticated(model.userProfile: any): boolean {
        return this.model.userProfile != null;
    }

    //this works
    @property({ type: Boolean, notify: true, computed: "getAuthenticated(model.userProfile)" })
    isAuthenticated: boolean;
    getAuthenticated(userProfile: any): boolean {
        return this.model.userProfile != null;
    }

There is no LICENSE file

I see under bower.json that this is intended to be released under the MIT license. Can you add a LICENSE file to the repository please?

No contribution guide / tooling

There isn't a guide on contributing to this repository, and as a contributor it isn't clear what tools should be run to generate the js, typing files, minified js, et cetera, in a way that's consistent with previous releases.

Perhaps setting up a simple gulp workflow is in order?

Create components at runtime

Hello.
Visual Studio 2013/ typescript 1.5

  • I just create object at runtime this way:
    var el:any = document.createElement('login-form');
    document.appendChild(el);
    is there ay way use strictly typed objects like this ?
    var el:LoginForm = new LoginForm();
    document.body.appendChild(el); // Argument of type 'LoginForm' is not assignable to parameter of type 'Node'.
  • I don't wont put any line of java script in html templates, and manage all the code with types in TS
    How I can access the Class instance associated with dom-element like:
    var el:any = document.createElement('login-form');
    el['login-form.ts-Scope?'].dataProvider = data;
    el['login-form.ts-Scope?'].addEventListener("loginTriggered", myHandler);
  • Also is there any possible issues with initialization of "model" in case of property set?

Great thanks for this repo!

polymer-ts typings errors

Hi, I have following configuration
tsc version is 1.8.7

tsconfig

{
  "compilerOptions": {
    "module": "system",
    "target": "es5",
    "sourceMap": true,
    "experimentalDecorators": true,
    "suppressImplicitAnyIndexErrors": true,
    "out": "."
  },
  "exclude": [
    "node_modules",
    "app/bower_components"
  ],
  "filesGlob": [
    "typings/browser.d.ts"
  ],
  "files": [
    "app/elements/my-element/my-element.ts",
    "typings/browser.d.ts"
  ]
}

typings.json

{
  "version": false,
  "dependencies": {},
  "ambientDependencies": {
    "polymer": "registry:dt/polymer#1.1.6+20160123034809",
    "polymer-ts": "registry:dt/polymer-ts#0.1.19+20151211074327"
  }
}

and I'm trying to compile one of yours element example. I got those erros

typings/browser/ambient/polymer-ts/index.d.ts(103,11): error TS2415: Class 'Base' incorrectly extends base class 'PolymerBase'.
  Property '$' is optional in type 'Base' but required in type 'PolymerBase'.
typings/browser/ambient/polymer-ts/index.d.ts(106,9): error TS2300: Duplicate identifier 'is'.
typings/browser/ambient/polymer/index.d.ts(23,13): error TS2430: Interface 'Base' incorrectly extends interface 'PolymerBase'.
typings/browser/ambient/polymer/index.d.ts(78,5): error TS2300: Duplicate identifier 'is'.
typings/browser/ambient/polymer/index.d.ts(151,5): error TS2425: Class 'PolymerBase' defines instance member property '$$', but extended class 'Base' defines it as instance member function.
typings/browser/ambient/polymer/index.d.ts(311,37): error TS2503: Cannot find namespace 'webcomponents'.
typings/browser/ambient/polymer/index.d.ts(313,42): error TS2503: Cannot find namespace 'webcomponents'.
typings/browser/ambient/polymer/index.d.ts(317,13): error TS2403: Subsequent variable declarations must have the same type.  Variable 'Polymer' must be of type '{ (prototype: Element): FunctionConstructor; Class(prototype: Element): Function; dom: dom; appen...', but here has type 'PolymerStatic'.
error TS5033: Could not write file '.': EISDIR: illegal operation on a directory, open '.'

Is there something that I'm doing wrong?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.