WebComponents - Attribute Changed

371 views Asked by At

From the link qr-code.js I have the code below.

Then I don't understand, on the highlighted line (60), what means the suffix: "Changed"?

attributeChangedCallback: {
    value: function (attrName, oldVal, newVal) {
        var fn = this[attrName+'Changed'];
        if (fn && typeof fn === 'function') {
            fn.call(this, oldVal, newVal);
        }
        this.generate();
    }

Also I don't understand the usage of:

this[attrName+'Changed']

Could you explain me this?, I don't find any clear explanation about this on Google. Thanks.

Below is the full code:

'use strict';

(function(definition) {
    if (typeof define === 'function' && define.amd) {
        define(['QRCode'], definition);
    } else if (typeof module === 'object' && module.exports) {
        var QRCode = require('qrjs');
        module.exports = definition(QRCode);
    } else {
        definition(window.QRCode);
    }
})(function(QRCode) {
//
// Prototype
//
var proto = Object.create(HTMLElement.prototype, {
    //
    // Attributes
    //
    attrs: {
        value: {
            data: null,
            format: 'png',
            modulesize: 5,
            margin: 4
        }
    },
    defineAttributes: {
        value: function () {
            var attrs = Object.keys(this.attrs),
                attr;
            for (var i=0; i<attrs.length; i++) {
                attr = attrs[i];
                (function (attr) {
                    Object.defineProperty(this, attr, {
                        get: function () {
                            var value = this.getAttribute(attr);
                            return value === null ? this.attrs[attr] : value;
                        },
                        set: function (value) {
                            this.setAttribute(attr, value);
                        }
                    });
                }.bind(this))(attr);
            }
        }
    },
    //
    // LifeCycle Callbacks
    //
    createdCallback: {
        value: function () {
            this.createShadowRoot();
            this.defineAttributes();
            this.generate();
        }
    },
    attributeChangedCallback: {
        value: function (attrName, oldVal, newVal) {
            var fn = this[attrName+'Changed'];
            if (fn && typeof fn === 'function') {
                fn.call(this, oldVal, newVal);
            }
            this.generate();
        }
    },
    //
    // Methods
    //
    getOptions: {
        value: function () {
            var modulesize = this.modulesize,
                margin = this.margin;
            return {
                modulesize: modulesize !== null ? parseInt(modulesize) : modulesize,
                margin: margin !== null ? parseInt(margin) : margin
            };
        }
    },
    generate: {
        value: function () {
            if (this.data !== null) {
                if (this.format === 'png') {
                    this.generatePNG();
                }
                else if (this.format === 'html') {
                    this.generateHTML();
                }
                else if (this.format === 'svg') {
                    this.generateSVG();
                }
                else {
                    this.shadowRoot.innerHTML = '<div>qr-code: '+ this.format +' not supported!</div>'
                }
            }
            else {
                this.shadowRoot.innerHTML = '<div>qr-code: no data!</div>'
            }
        }
    },
    generatePNG: {
        value: function () {
            try {
                var img = document.createElement('img');
                img.src = QRCode.generatePNG(this.data, this.getOptions());
                this.clear();
                this.shadowRoot.appendChild(img);
            }
            catch (e) {
                this.shadowRoot.innerHTML = '<div>qr-code: no canvas support!</div>'
            }
        }
    },
    generateHTML: {
        value: function () {
            var div = QRCode.generateHTML(this.data, this.getOptions());
            this.clear();
            this.shadowRoot.appendChild(div);
        }
    },
    generateSVG: {
        value: function () {
            var div = QRCode.generateSVG(this.data, this.getOptions());
            this.clear();
            this.shadowRoot.appendChild(div);
        }
    },
    clear: {
        value: function () {
            while (this.shadowRoot.lastChild) {
                this.shadowRoot.removeChild(this.shadowRoot.lastChild);
            }
        }
    }
});
//
// Register
//
document.registerElement('qr-code', {
    prototype: proto
});
});
1

There are 1 answers

0
Supersharp On

As @Jhecht suggested, it's a combination of the name of a attribute and the suffix "Changed" in order to create generic method names.

For example if the <qr-code> element has an attribute "foo" that is added, updated or removed, then the callback will define the fn variable to this["fooChanged"], which is equivalent to this.fooChanged.

If this method exists, it will be invoked by fn.call().

However I see nowhere in the code you posted such method signature attached to the custom element prototype, so it's useless code until further notice.