Tinkering with Google Polymer and Typescript

Tinkering with Google Polymer and Typescript

I recently had the opportunity to experiment with something I have been meaning to play with for a little while, Google’s Polymer.

I first heard about Polymer at Google IO 2014:

I highly recommend watching that video if you want to know more about Polymer but the high level idea is that its a library built on top of the new HTML Web Components and it allows us to write our own custom HTML elements in a way that makes sense.

I really liked the look of it as it reminded me greatly of Adobe’s Flex (MXML) in the way you can write your own components in a declarative manner then bind to various data in the code behind.

So it took me a few days to get my head around things to begin with. One thing I would recommend if you are interested in tinkering with Polymer then first checkout this video:

I wish I had used that to begin with as it would have saved me a whole heap of “is this the correct way to do it?” headaches.

One complication with my setup however is that I really wanted to use Typescript rather than raw Javascript for my code. Well fortunately Visual Studio has really great Typescript support and I was able to create a Typescript project in Visual studio and get cracking immediately.

I ran into an issue with how to use Polymer with Typescript however and there wasn’t too much info on the web out there so hopefully this short guide will help:

1) Create your custom element

I’m using a login element as an example:

login.html

<link rel="import" href="/bower_components/polymer/polymer.html">
<link rel="import" href="/bower_components/paper-toast/paper-toast.html">
<link rel="import" href="/bower_components/paper-button/paper-button.html">
<link rel="import" href="/bower_components/paper-input/paper-input.html">
<link rel="import" href="/bower_components/paper-fab/paper-fab.html">
<link rel="import" href="/bower_components/core-icons/core-icons.html">

<polymer-element name="tt-login" attributes="userService">
    <template>

        <style>

            .card {
                margin-top: 64px;
                max-height: 580px;
                max-width: 512px;
                box-shadow: 0 2px 5px 0 rgba(0,0,0,.26);
                border-radius: 2px;
                padding: 20px 16px;
                box-sizing: border-box;
                background-color: white;
            }
			
        </style>

        <div class="card">
            <h1>Login</h1>


            <paper-input floatinglabel label="Your email" type="email" value="{{email}}" error="Input is not an email!"></paper-input>
            <paper-input floatinglabel label="Your password" type="password" value="{{password}}" error="Input is not an email!"></paper-input>

            
            <div horizontal center layout>
                <a href="/#signup"><paper-button disabled?="{{isLoggingIn}}">Signup</paper-button></a>
                <div flex></div>
                <paper-button id="check" on-click="{{login}}" disabled?="{{isLoggingIn}}">Login</paper-button>
            </div>          

            <paper-toast id="errorToast"></paper-toast>
        </div>        

    </template>
    <script src="login.js"></script>
</polymer-element>

Its a pretty simple login element with some binding using some of Google’s paper elements but hopefully you get the idea.

2) Create your custom element’s script

login.ts

class Login extends PolymerElement {

    userService: UserService;

    email: string;
    password: string;
    isLoggingIn: boolean;

    errorToast: PaperToast;

    ready() {
        this.errorToast = this.$.errorToast;
    }

    login() {
        this.isLoggingIn = true;
        this.userService.login(this.email, this.password)
            .then(user => this.onUserLoggedIn(user))
            .fail(err => this.onParseError(err));
    }

    private onUserLoggedIn(u: Parse.User) {
        this.isLoggingIn = false;
        this.fire("logged-in");
    }

    private onParseError(error: Parse.Error) {
        this.isLoggingIn = false;
        this.errorToast.text = error.message;
        this.errorToast.show();
    }

}

Polymer(Login.prototype);

Here we define the variables that we are going to bind to in the element. We also include the “userService” which is an attribute that is a dependency passed into the element.

Note that im able to use this.$ to access the “errorToast” element by ID. Im able to do this because Login extends a class I wrote called PolymerElement:

class PolymerElement {
    $: any;
    style:any;
    fire(eventname: string, payload?: any) { }
    addEventListener(eventName: string, handler: (e : CustomEvent) => void) { }
} 

For now it a bit of a hack to get around the fact that Typescript requires that you implement all elements in an interface so I cant just do “class Login implements HTMLElement”.

Note also the call to Polymer:

Polymer(Login.prototype);

We must pass the prototype into the call then do our variable initting in the ready() function.

3) Use the element

Now we can use it pretty easily:

<!DOCTYPE html>
<html>
<head>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
    <title>Login Example</title>
        
    <script src="bower_components/platform/platform.js"></script>

    <!-- This is only needed because of the Typescript interface problem! -->
    <script src="lib/polymer_utils.js"></script>

	<!-- Our login element -->
    <link rel="import" href="login.html">

</head>
<body fullbleed layout vertical unresolved>
	<userService id="userService"></userService>
    <login userService="{{$.userService}}"></login>
</body>
</html>

I hope that helps other that are looking to do their own tinkering with Typescript and Polymer!

MK Bridges

MK Bridges

MK Bridges is an ongoing freelance project I worked on for Martin-Kaye Solicitors.

The firm works with a number of suppliers that provide them clients. Those suppliers need information about the progress of a case such as when certain milestones have been met. Unfortunately MK’s current system doesn’t easily allow for this reporting to third parties and thus they were logging into each supplier’s website and manually entering the data whenever the case updated. As this can happen many times a day for each case the extra workload was high.

MK Bridges is a solution to that problem. It uses daily snapshots of the MK database to work out which milestones have been completed and then sends API calls to the relevant supplier thus saving a great deal of manual labour.

It was developed using ASP.NET 5 with Entity Framework 6 with some sprinkling of Typescript for the client side.

screenshot_016 Oct. 06 16.11

Although the project sounds deceptively simple it was actually quite complex and required quite a bit of back and forth with suppliers and hosting providers to link it all up correctly. There is an internal error handling system that uses Mandril to report on errors, a message request and response logging system and a moderately complex system for filtering information to send and display in the user interface.

Post To Tumblr 5.9

Post To Tumblr 5.9

One thing that has always bothered me with Post To Tumblr ever since version 1.0, and I have finally fixed it in 5.9!

First I should explain how photo posting works in Post To Tumblr. Its pretty simple. First I take the URL of the image the user clicks on from Chrome, then send that URL to my server with some other information (such as formatting options) then I bundle all that up into an API call to Tumblr. Tumblr then takes that URL and downloads it, caching it to its own server returning a URL with the newly created post, I hand that back to the browser for the user to view and we are done.

Now the problem comes if Tumblr is unable to access that image. That could happen if the image is behind a password protected firewall such a GMail attachment or a private Facebook photo for example.

The solution is to upload the image bytes to Tumblr directly so that Tumblr doesn’t have to go and try to download the image from a URL. The problem is that the Tumblr API is a NIGHTMARE. Im not kidding, I have struggled for years (off and on) to try to get this to work with no hope.

An idea came to me the other day however, why not just cache that image on my server temporarily then provide a URL that tumblr can definitely access and use to download the image. Well after an hour or two of hacking I have it working!

Images are cached on my Parse.com backend and will be deleted after a certain period of time.

Im so happy to finally have this working. Now I have this in place I hope to get uploading from the desktop working soon!