Skip to content

Commit

Permalink
feat: Add hook to web component.
Browse files Browse the repository at this point in the history
  • Loading branch information
GSMLG-BOT committed Oct 8, 2022
1 parent 3585d8f commit eec2b47
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 36 deletions.
41 changes: 41 additions & 0 deletions apps/phoenix_webcomponent/assets/js/hook.js
@@ -0,0 +1,41 @@
export const PhxWCHook = {
mounted() {
const attrs = this.el.attributes;
const phxTarget = attrs["phx-target"].value;
const pushEvent = phxTarget
? (event, payload, callback) =>
this.pushEventTo(phxTarget, event, payload, callback)
: this.pushEvent;

for (var i = 0; i < attrs.length; i++) {
if (/^phx-wc-send-/.test(attrs[i].name)) {
const eventName = attrs[i].name.replace(/^phx-wc-send-/, "");
const [phxEvent, callbackName] = attrs[i].value.split(';');
this.el.addEventListener(eventName, ({ detail }) => {
pushEvent(phxEvent, detail, (e) => {
this[callbackName]?.(e, detail, eventName)
});
});
}
if (/^phx-wc-receive-/.test(attrs[i].name)) {
const eventName = attrs[i].name.replace(/^phx-wc-receive-/, "");
const handler = attrs[i].value;
this.handleEvent(eventName, (payload) => {
if (handler && this.el[handler]) {
this.el[handler]?.(payload);
} else {
this.el.dispatchEvent(new CustomEvent(eventName, { detail: payload }));
}
});
}
if ('phx-wc-receive' === attrs[i].name) {
const [phxEvent, callbackName] = attrs[i].value.split(';');
this.handleEvent(phxEvent, (payload) => {
this.el[callbackName]?.(payload);
});
}
}
},
};


2 changes: 2 additions & 0 deletions apps/phoenix_webcomponent/assets/js/phoenix_webcomponent.js
@@ -1 +1,3 @@
import '@gsmlg/lit';

export { PhxWCHook } from './hook';
25 changes: 13 additions & 12 deletions apps/phx_wc_storybook_web/assets/js/app.js
Expand Up @@ -19,27 +19,28 @@
//

// Include phoenix_html to handle method=PUT/DELETE in forms and buttons.
import "phoenix_html"
import "phoenix_html";
// Establish Phoenix Socket and LiveView configuration.
import {Socket} from "phoenix"
import {LiveSocket} from "phoenix_live_view"
import topbar from "../vendor/topbar"
import {Socket} from "phoenix";
import {LiveSocket} from "phoenix_live_view";
import { PhxWCHook } from "phoenix_webcomponent";
import topbar from "../vendor/topbar";

let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}})
const csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content");
const liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}, hooks: { PhxWCHook }});

// Show progress bar on live navigation and form submits
topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"})
window.addEventListener("phx:page-loading-start", info => topbar.show())
window.addEventListener("phx:page-loading-stop", info => topbar.hide())
topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"});
window.addEventListener("phx:page-loading-start", info => topbar.show());
window.addEventListener("phx:page-loading-stop", info => topbar.hide());

// connect if there are any LiveViews on the page
liveSocket.connect()
liveSocket.connect();

// expose liveSocket on window for web console debug logs and latency simulation:
// >> liveSocket.enableDebug()
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session
// >> liveSocket.disableLatencySim()
window.liveSocket = liveSocket
window.liveSocket = liveSocket;

import 'phoenix_webcomponent';
import 'phoenix_webcomponent';
Expand Up @@ -3,7 +3,11 @@
<main class="container h-[calc(100vh-56px)] flex flex-row justify-start items-start">
<.wc_left_menu
class="w-48 h-[calc(100vh-56px)]"
active={"phx-wc-hook"}
menus={[
{"Hooks", [
{"phx-wc-hook", "PhxWCHook", "/"}
]},
{"Components",
[
{"actionbar", "Actionbar", "/storybook/components/actionbar"},
Expand Down
@@ -1,30 +1,40 @@

<.wc_card class="w-[100%_!important] h-[calc(100vh-56px-2em)_!important]">
<:title class="flex flex-row justify-center items-center">
<%= link "To Storybook", to: Routes.live_storybook_path(@conn, :root), class: "text-4xl text-blue-600 hover:text-blue-400" %>
<span class="text-4xl text-blue-600 hover:text-blue-400">
PhxWCHook
</span>
</:title>
<.wc_markdown content={"""

<div class="flex flex-col justify-start items-start">
<div>
wc_actionbar
</div>
<div>
wc_appbar
</div>
<div>
wc_card
</div>
<div>
wc_left_menu
</div>
<div>
wc_markdown
</div>
<div>
wc_pagination
</div>
<div>
wc_table
</div>
</div>
Custom hook `PhxWCHook` for connect custom elements to phoenix.
This will send and receive event to live view.

```js
const csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content");

import { PhxWCHook } from "phoenix_webcomponent";

const liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}, hooks: { PhxWCHook }});
```

Send custom events to live view:
```html
<Element phx-wc-send-sync-content="load_content" phx-hook="PhxWCHook" />
<Element phx-wc-send-sync-content="load_content;loadAccepted" phx-hook="PhxWCHook" />
```
- In the first element, when element trigger customEvents `sync-content`, also use `pushEvent` send `load_content` to live view.
- Second element are same as first, but will call `loadAccepted` on element when receive server send feedback.

Receive live view event:
```html
<Element phx-wc-receive-update_content="updateContent" phx-hook="PhxWCHook" />
<!-- equal -->
<Element phx-wc-receive="update_content;updateContent" phx-hook="PhxWCHook" />
```
- In this case, when live view fire `update_content` event, also trigger `updateContent` method on elmenet.
- If value(`updateContent`) is empty, trigger a same event `update_content` on element.

"""}>
</.wc_markdown>
</.wc_card>

0 comments on commit eec2b47

Please sign in to comment.