1

I am trying to create a custom HTML5 web component in a Rails application, but I am getting errors instantiating the Javascript object.

Version info:
Rails 4.2.11.3
ruby 2.5.8
coffee-rails 4.1.1

I've reproduced the issue in a minimal Rails app, available at https://github.com/fredwillmore/coffee_test

Here's the coffeescript file that creates the component:

class ThingDoer extends HTMLElement # constructor: -> # super() customElements.define("thing-doer", ThingDoer); 

This is what the coffeescript transpiles to:

ThingDoer = (function(superClass) { extend(ThingDoer, superClass); function ThingDoer() { return ThingDoer.__super__.constructor.apply(this, arguments); } return ThingDoer; })(HTMLElement); customElements.define("thing-doer", ThingDoer); 

Errors:

with no constructor defined, I get the following error:

Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.

same with a constructor that just calls "super":

Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.

I tried a constructor that just calls new HTMLElement:

Uncaught TypeError: Illegal constructor

What am I missing?

    1 Answer 1

    0

    The compiled script isn’t suitable as the class has been compiled to an ES5-style class which is not compatible with Custom Elements API.

    Instead, you can write a little bit of raw JavaScript to generate a real class, then augment more methods to it using the CoffeeScript’s Prototypal Inheritance syntax:

    ThingDoer = `class ThingDoer extends HTMLElement { constructor() { super(); this.initialize(); } }` ThingDoer::initialize = -> @innerHTML = 'meow' customElements.define "thing-doer", ThingDoer 

    If the above code works in development but not when precompiling assets for production, the reason for that may be that your JS compresser doesn’t support ES6 syntax. You can fix your asset pipeline by using a more modern compressor such as terser-ruby or don’t transpile it (define the class in eval instead).

    ThingDoer = eval '(class ThingDoer extends HTMLElement { constructor() { super(); this.initialize(); } })' ThingDoer::initialize = -> @innerHTML = 'meow' customElements.define "thing-doer", ThingDoer 

      Start asking to get answers

      Find the answer to your question by asking.

      Ask question

      Explore related questions

      See similar questions with these tags.