Search code examples
javascriptregexmethodsreplaceprototype

Trying to create a custom method using prototype property but i get Cannot read property 'replace' of undefined


So I'm messing around with JS trying to create a method which adds CSS style to elements without removing currently applied style:

// ==================================================================================================
// this method adds style to an element using CSS inline syntax without removing unaltered CSS styles
// ==================================================================================================
Element.prototype.cssStyle = function (style)
{
    let styleChars = style.split(''); // split each character of the style arg as an item in an array
    let positions = [];
    for(let i=0; i<styleChars.length; i++){
        if(styleChars[i] === '-'){
            positions.push(i+1);
        };
    };
    positions.forEach(function (position){ // for each match
        styleChars.splice(position, 1, style[position].toUpperCase()); // make that character uppercase
    });
    styleChars.splice(0, 0, '[["'); // add a "[[" item on the first position
    styleChars.splice(styleChars.length, 0, '"]]'); //add a "[[" on the last position
    style = styleChars.join('') // join back the array into a string
    style = style.replace(/:/g, "\",\"").replace(/;/g, "\"],[\"").replace(/-/g, ""); // replace some character in order to make the string look like an array
    style = JSON.parse(style); // parse the string into an array
    for(let i=0; i<style.length; i++){ // for each item in the array
        let property = style[i][0].replace(/ */, ""); // remove some characters which might inhibit normal execution
        let value = style[i][1].replace(/;/, "").replace(/ */, ""); //remove some characters which might inhibit normal execution
        this.style[property] = value // change style of the element
    };
    return this.getAttribute('style'); //return all inline CSS styles
}

so if I try to style an element like this:

Element.cssStyle('background-color: white; color: #000')

It works as expected, but if I add a ; at the end of the parameter string I get this

Element.cssStyle('background-color: white; color: #000;')
'Uncaught TypeError: Cannot read property 'toUpperCase' of undefined'

Even though I don't see any apparent issues with the replace method, what could it be?

Replacing whitespace at that exact line works just fine, but trying to replace ; I get that error.

Also how badly written is my code?

Thanks!


Solution

  • Here is an example:

    Element.prototype.cssStyle = function(styleStr) {
      let styles = styleStr.split(';')
      styles.forEach(style => {
        if (!style.trim()) return;
    
        let name = style.split(':')[0].trim();
        let value = style.split(':')[1].trim();
        this.style[name] = value;
      })
    
      return this.getAttribute('style'); //return all inline CSS styles
    }
    
    let testEl = document.getElementById("test")
    console.log(testEl.cssStyle("color: white; background-color: black;"))
    <p id="test">This is a test paragraph</p>

    A few things to note:

    • This does NOT parse all CSS but I believe it works for your examples.
    • It is NOT recommended to modify the prototype of an object because if you are using someone else's code along with yours you might run into problems of overwriting each other's modifications.

    The code works by splitting the string into each style segment and then it loops over those with forEach and changes the style of the element using this.style

    Documentation:

    Hopefully, this helps.