Syntax Error When Using "targets"


#1

I believe I’ve integrated Stimulus with my Rails/TL app as I can print simple logs from connect methods. However, when trying to reference targets I get a syntax error.

window.application.register("calendar", class extends Stimulus.Controller {
  static targets = [ "href" ] // <-- Uncaught SyntaxError: Unexpected token =

  // ...
})

I’m not using webpacks, babel, or any other build system. I have stimulus.umd.js tucked away in my vendor directory. Here is my application.js file:

//= require jquery3
//= require rails-ujs
//= require popper
//= require turbolinks
//= require bootstrap-sprockets
//= require stimulus.umd

//= require_self
//= require_tree .

//= require trix

window.application = Stimulus.Application.start()

Any help would be appreciated - thanks!


#2

Just an FYI, that same error message shows in the Glitch examples, but they do seem to work. I haven’t yet tried moving the examples outside of Glitch though.


#3

This looks to be caused by a missing transformation. There is a closed issue on the Github when using babel. I’m not sure what the solution is when using the asset pipeline, but hopefully that helps.


#4

Until the static class fields proposal is standardized, you’ll need the transform-class-properties plugin for Babel. See the Using Babel section of the installation guide for more details and an example configuration.

You can also use TypeScript, which has support for static class properties built-in.


#5

I’m not sure what the solution is when using the asset pipeline

You can use a static get method instead of a static class property:

// app/assets/javascripts/controllers/calendar_controller.js
application.register("calendar", class extends Stimulus.Controller {
  static get targets() {
    return [ "href" ]
  }

  connect() {
    console.log(this.hrefTarget)
  }
})

Or, if you’re using CoffeeScript:

# app/assets/javascripts/controllers/calendar_controller.coffee
application.register "calendar", class extends Stimulus.Controller
  @targets = [ "href" ]

  connect: ->
    console.log(@hrefTarget)

#6

If I try something like this using TypeScript, I get something like a “property hrefTarget does not exist on type default” error in compile? How do you get Typescript to learn the dynamic target methods?


#7

The CoffeeScript solution works great, thanks @javan!

As mentioned in my original question, I’m not using Babel (or webpacks), just the plain ol’ Rails Asset Pipeline.


#8

We’d love to figure out a way to define those types automatically. For now, you’ll have to declare the ones you’re using manually:

import { Controller } from "stimulus"

export default class extends Controller {
  nameTarget: Element
  nameTargets: Element[] 
  hasNameTarget: boolean

  static targets = [ "name" ]

  // …
}

#9

You can also use TypeScript to compile JavaScript files without needing to declare any types in your source.

// tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "allowJs": true,
    "esModuleInterop": true
  }
}