diff --git a/examples/controllers/async_controller.js b/examples/controllers/async_controller.js new file mode 100644 index 00000000..513de70c --- /dev/null +++ b/examples/controllers/async_controller.js @@ -0,0 +1,25 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "button" ] + + async sleep() { + return new Promise(r => setTimeout(r, 1000)); + } + + + async initialize() { + await this.sleep(); + alert('async initialize complete') + } + + async run() { + await this.sleep(); + alert('Async function complete'); + } + + async throwError() { + await this.sleep(); + throw Error('This error should be caught by stimulus, and stimulus should display a detailed error in the console'); + } +} diff --git a/examples/index.js b/examples/index.js index b44c9c76..100b2c8a 100644 --- a/examples/index.js +++ b/examples/index.js @@ -17,3 +17,6 @@ application.register("slideshow", SlideshowController) import TabsController from "./controllers/tabs_controller" application.register("tabs", TabsController) + +import AsyncController from "./controllers/async_controller" +application.register("async", AsyncController) diff --git a/examples/server.js b/examples/server.js index a5573f33..3058be49 100644 --- a/examples/server.js +++ b/examples/server.js @@ -23,6 +23,7 @@ const pages = [ { path: "/slideshow", title: "Slideshow" }, { path: "/content-loader", title: "Content Loader" }, { path: "/tabs", title: "Tabs" }, + { path: "/async", title: "Async" }, ] app.get("/", (req, res) => { diff --git a/examples/views/async.ejs b/examples/views/async.ejs new file mode 100644 index 00000000..bd53ce25 --- /dev/null +++ b/examples/views/async.ejs @@ -0,0 +1,13 @@ +<%- include("layout/head") %> + +

+ +

+ +
+ +

+ +

+ +<%- include("layout/tail") %> diff --git a/src/core/binding.ts b/src/core/binding.ts index 33958667..21e02441 100644 --- a/src/core/binding.ts +++ b/src/core/binding.ts @@ -72,14 +72,20 @@ export class Binding { } private invokeWithEvent(event: ActionEvent) { + const handleError = (error: any) => { + const { identifier, controller, element, index } = this + const detail = { identifier, controller, element, index, event } + this.context.handleError(error, `invoking action "${this.action}"`, detail) + } + const { target, currentTarget } = event try { - this.method.call(this.controller, event) + Promise + .resolve(this.method.call(this.controller, event)) + .catch(error => handleError(error)) this.context.logDebugActivity(this.methodName, { event, target, currentTarget, action: this.methodName }) } catch (error: any) { - const { identifier, controller, element, index } = this - const detail = { identifier, controller, element, index, event } - this.context.handleError(error, `invoking action "${this.action}"`, detail) + handleError(error) } } diff --git a/src/core/context.ts b/src/core/context.ts index e1187add..e5a6cef5 100644 --- a/src/core/context.ts +++ b/src/core/context.ts @@ -30,7 +30,9 @@ export class Context implements ErrorHandler, TargetObserverDelegate, OutletObse this.outletObserver = new OutletObserver(this, this) try { - this.controller.initialize() + Promise + .resolve(this.controller.initialize()) + .catch(error => this.handleError(error, "initializing controller")) this.logDebugActivity("initialize") } catch (error: any) { this.handleError(error, "initializing controller") @@ -44,7 +46,9 @@ export class Context implements ErrorHandler, TargetObserverDelegate, OutletObse this.outletObserver.start() try { - this.controller.connect() + Promise + .resolve(this.controller.connect()) + .catch(error => this.handleError(error, "connecting controller")) this.logDebugActivity("connect") } catch (error: any) { this.handleError(error, "connecting controller") @@ -57,7 +61,9 @@ export class Context implements ErrorHandler, TargetObserverDelegate, OutletObse disconnect() { try { - this.controller.disconnect() + Promise + .resolve(this.controller.disconnect()) + .catch(error => this.handleError(error, "disconnecting controller")) this.logDebugActivity("disconnect") } catch (error: any) { this.handleError(error, "disconnecting controller")