Search code examples
javascriptconstructorimmutabilityconstructable-stylesheet

Can a unique identifier be applied to a Constructable Stylesheet?


Setup

User interaction may lead to one of several components being asynchronously injected into a document.

Each of these components has an associated Constructable Stylesheet.

But - and this is the key point - any of the user interactions may be repeated and the markup of each component injected into the document any number of times.

Regardless of how many times the markup is injected, it stands to reason that the associated constructable stylesheet need only be constructed and adopted by the document once.

After that first time it will continue to determine the presentation of the associated markup, no matter how many times the latter is injected into the document.


Question

I would like to understand how I might go about uniquely identifying each constructable stylesheet (via e.g. a unique title property), such that once it has been adopted by the document the first time I can check against the existing document.adoptedStyleSheets and ensure that the same stylesheet will not be constructed and adopted again.

After I run:

const componentAStylesheet = new CSSStyleSheet();

then, I have tried to...

Write to an existing property:

componentAStylesheet.title == 'Component A'; // no effect

Add a new property:

componentAStylesheet.componentTitle == 'Component A'; // no effect

Edit the constructor prototype:

CSSStyleSheet.prototype.title = 'Component A';  // Error: setting getter-only property "title"

Add a new property to the constructor prototype:

CSSStyleSheet.prototype.componentTitle = 'Component A'; // no effect

Question: Is the CSSStyleSheet object frozen in some way (or read-only?) and this is why I can't add to or edit its properties?


Attempt at an alternative solution

It occurred to me that instead of applying a unique label to the myComponentAStylesheet object, I might create a parent object:

const myComponents = {}

and, after running:

const componentAStylesheet = new CSSStyleSheet();

I could manually add the following entry:

myComponents['componentA'] = componentAStylesheet;

That would still give the browser a way to discern whether a given component-associated stylesheet had already been constructed and adopted by the current document.

But is there really no way to label the constructed stylesheet object, itself?


Solution

  • If you are looking for a Factory Singleton component that can share your "CSSStyleSheet", this is the solution.

    Create a dedicated class in a file, for example "CSSStyleSheetFactory.js". (code not tested, but I use that every time I need to create Singleton)

    class CSSStyleSheetFactory{
       constructor(){
           const hash_map={};
           this.exist=(id)=>{ return hash_map[id]!==undefined }
           this.getByID=(id)=>{ return hash_map[id] }
           this.create_replace=(id,obj)=>{ hash_map[id]=obj; }
           this.dealloc=(id)=>{ delete hash_map[id] }
       }
    }
    
    if(CSSStyleSheetFactory.instance===undefined){
         CSSStyleSheetFactory.instance= new CSSStyleSheetFactory();
    }
    module.exports = CSSStyleSheetFactory.instance;
    

    Then when you need it, just call it

    const CSSStyleSheetFactory= require('./CSSStyleSheetFactory');
    const componentAStylesheet = CSSStyleSheetFactory.exist("your id or name");
    

    You can require the module everywhere and you can check with some console.log if it works as you need.

    Of course, if you are working on js client side, if you reload the browser page, you will lose everything, and the Singleton will be flushed out by the memory (same for react and similar framework). If you are using node.js, you will lose the Singleton content after the node.js process shout-down.

    May you need persistence in order to save the Singleton data and reload it if the singleton will be flush and recreated, just add a "save" and "load" data function inside the singleton (using db or files, cookies, persistor, ...).


    Anyway, I'm not sure to understand your needs, because that code should work: (tested)

    const t = new CSSStyleSheet();
    t.name="test";
    const check= t.name==="test"; //this is true
    

    You should able to add properties to any instance of CSSStyleSheet, if is a new one, if the property already exists, may it is a "const" so it is read-only.