Skip to main content

Temporal coupling vs. complex constructor [Resolved]

I'm working through a book on writing Single Page Applications in Vanilla Javascript. (I'm working on a project where I'm not allowed to use React or any other frameworks, so I'm trying to get better at structuring vanilla SPAs.)

The book is fairly old, so I'm trying to rework some of the examples using more modern Javascript idioms. In particular, I reworked this example using a class:

export class SPA {

    constructor($container) {
        this.$container = $container;
        this.onClickSlider = this.onClickSlider.bind(this);
        this.$container.innerHTML = this.configMap.template_html;
        this.$chatSlider.setAttribute("title", this.configMap.retracted_title);
        this.$chatSlider.addEventListener("click", this.onClickSlider);
    }

    get configMap() {
        return {
            extended_height: 434,
            extended_title: "Click to retract",
            retracted_height: 16,
            retracted_title: "Click to extend",
            template_html: "
" }; } get $chatSlider() { if (!this._$chatSlider) { this._$chatSlider = this.$container.querySelector(".spa-slider"); } return this._$chatSlider; } onClickSlider(event) { this.toggleSlider(); event.preventDefault(); } toggleSlider() { const slider_height = this.$chatSlider.clientHeight; if (slider_height === this.configMap.retracted_height) { this.$chatSlider.style.transition = "1s"; this.$chatSlider.style.height = `${this.configMap.extended_height}px`; this.$chatSlider.setAttribute("title", this.configMap.extended_title); } else if (slider_height === this.configMap.extended_height) { this.$chatSlider.style.transition = "1s"; this.$chatSlider.style.height = `${this.configMap.retracted_height}px`; this.$chatSlider.setAttribute("title", this.configMap.retracted_title); } } }

However, this probably commits the anti-pattern on doing too much in the constructor, so I moved the initialisation of the DOM and event handlers out:

export class SPA {

    constructor($container) {
        this.$container = $container;
        this.onClickSlider = this.onClickSlider.bind(this);
    }

    connect() {
        this.$container.innerHTML = this.configMap.template_html;
        this.$chatSlider.setAttribute("title", this.configMap.retracted_title);
        this.$chatSlider.addEventListener("click", this.onClickSlider);
    }

    get configMap() {
        return {
            extended_height: 434,
            extended_title: "Click to retract",
            retracted_height: 16,
            retracted_title: "Click to extend",
            template_html: "
" }; } get $chatSlider() { if (!this._$chatSlider) { this._$chatSlider = this.$container.querySelector(".spa-slider"); } return this._$chatSlider; } onClickSlider(event) { this.toggleSlider(); event.preventDefault(); } toggleSlider() { const slider_height = this.$chatSlider.clientHeight; if (slider_height === this.configMap.retracted_height) { this.$chatSlider.style.transition = "1s"; this.$chatSlider.style.height = `${this.configMap.extended_height}px`; this.$chatSlider.setAttribute("title", this.configMap.extended_title); } else if (slider_height === this.configMap.extended_height) { this.$chatSlider.style.transition = "1s"; this.$chatSlider.style.height = `${this.configMap.retracted_height}px`; this.$chatSlider.setAttribute("title", this.configMap.retracted_title); } } }

However, now I have temporal coupling, since most of the methods won't work until connect() is called.

Can anyone give any advice for how to avoid the dilemma of doing things in the constructor other than assigning properties vs temporal coupling in this example?


Question Credit: samfrances
Question Reference
Asked July 21, 2019
Posted Under: Programming
28 views
Your Answer
D:\Adnan\Candoerz\CandoProject\vQA