Update: I added more details of how I’m using the constants in response to questions. The actual problem I’m observing is that the constants are added to the global object, and so I’m worried about potential name collisions.
I defined a WebComponent for my team. The component uses several constants, which – for convenience – I just defined at the top of the file.
const SESSION_KEEP_ALIVE = "session-keep-alive";
const MILLISECONDS_IN_MINUTE = 60000;
const PAGE_TIMEOUT_DIALOG_ID = `${SESSION_KEEP_ALIVE}-extend-session-dialog`;
const YES_BUTTON_ID = `${PAGE_TIMEOUT_DIALOG_ID}-yes-button`;
const NO_BUTTON_ID = `${PAGE_TIMEOUT_DIALOG_ID}-no-button`;
// TEMPLATES
const PAGE_TIMEOUT_DIALOG_TEMPLATE = document.createElement("template");
PAGE_TIMEOUT_DIALOG_TEMPLATE.innerHTML = `
<uef-dialog action-required="" backdrop="" width="500px" id="${PAGE_TIMEOUT_DIALOG_ID}">
<uef-typography slot="uef-dialog-header">Warning</uef-typography>
<uef-typography line-height="1.5" slot="uef-dialog-body">
Your session will expire in 5 minutes. Do you want to extend it?
</uef-typography>
<uef-button-group slot="uef-dialog-footer" alignment="right" direction="rtl">
<uef-button fill="solid" id="${YES_BUTTON_ID}">Yes</uef-button>
<uef-button fill="outline" id="${NO_BUTTON_ID}">No</uef-button>
</uef-button-group>
</uef-dialog>`;
class SessionKeepAlive extends HTMLElement {
connectedCallback() {
document.body.appendChild(PAGE_TIMEOUT_DIALOG_TEMPLATE.content);
this.dialog = document.getElementById(PAGE_TIMEOUT_DIALOG_ID);
let yesButton = this.dialog.querySelector(`#${YES_BUTTON_ID}`);
yesButton.addEventListener("buttonClick", this.yesButtonClickHandler.bind(this));
let noButton = this.dialog.querySelector(`#${NO_BUTTON_ID}`);
noButton.addEventListener("buttonClick", this.noButtonClickHandler.bind(this));
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === "delay") {
if (!isNaN(newValue)) {
this.timeoutDelay = newValue * MILLISECONDS_IN_MINUTE;
}
}
}
yesButtonClickHandler() {
this.dialog.removeAttribute("open");
... // Code to extend session elided
}
noButtonClickHandler() {
this.dialog.removeAttribute("open");
}
}
window.customElements.define(SESSION_KEEP_ALIVE, SessionKeepAlive);
In this simplified example, you can see how I use two constants. One I use to register the WebComponent and also define IDs for elements in the component. This constant seems to genuinely be greater than the scope of the WebComponent.
The other – MILLISECONDS_IN_MINUTES – could probably just be replaced by a literal. I did consider defining it as just another property in the constructor, but I wanted to know the best way to handle these situations.
I tried a few things – including using an anonymous function to limit the scope:
(function() {
// The above code, here
}) ();
This worked, but it feels wrong.
I tried using the "static" keyword to define these as class-level variables. Unfortunately, that’s not how the "static" keyword works in JavaScript.
I also considered using a Constants file, but the point of using components is to encapsulate code, not to put aspects in separate files.
Any advice?
2
Answers
For now I've decided to recommend using the anonymous function closures:
This works, and it's a common practice in JavaScript.
If you want limit the scope (without using modules), you can just use a block, like this: