can i pass function as attribute to web component?

前端 未结 3 1006
慢半拍i
慢半拍i 2021-02-20 04:35

I\'m trying to create a native web component for input element. I wanted the component to have custom validation functionality, similar to polymer\'s paper-input custom validato

相关标签:
3条回答
  • 2021-02-20 05:15

    It is best to pass in the function through a property since all attributes are strings.

    If you must pass it in as an attribute then you would need to convert that string into the function. The problem then become the scope of that function.

    If you assume that the function is global in scope then you can use the string as a property name of the window object. TO execute the code you could do this:

    window[fnName]();
    

    But that is pretty limiting since you might want to call a member function of your own class or object.

    You could use a dot notation in the name like func="myObj.fnName()" and if you are not worried about the warnings of using eval you could just do something like this:

    eval(el.getAttribute('func'));

    Of course that leaves you open for all kinds of possible injection attacks. But, then again so does the img tag and the script tag.

    You could try to be safer and do this:

    Set the attribute without the ():

    `func="myObj.fnName"`
    

    Your code that attempts to make the call would look like this:

    var parts = el.getAttribute('func').split('.');
    var obj = window;
    var found = parts.some( part => {
      var next = obj[part];
      if (next) {
        obj = next;
        return true;
      }
    });
    
    if (found) {
      obj();
    }
    

    But this also prevents you from passing in any parameters.

    This complexity is exactly why things like AngularJS, React, Vue, etc exist. This is also the reason why I avoid passing in a function through an attribute.

    If you pass it in through a property then you code can look like this:

    el.callme = globalfunc; // or
    el.callme = this.localFunc; // or
    el.callMe = (some params) => { /* do something */ };
    

    Or anything else you want.

    EVENTS

    Now having said all of that I would also suggest doing what most of the native components do. That is to dispatch an event when something needs to be done, or when something changes and the outside world might be interested in those changes.

    In you element you just call

    this.dispatchEvent(new CustomEvent('event name', {bubbles: true, detail: {your detail}});
    

    Then anyone that cares about your event will listen for it.

    0 讨论(0)
  • 2021-02-20 05:17

    An attribute is a string, not a function. You can pass a a function as a string and then evaluate it with the eval() function. It's not considered as a good practice, for security reasons.

    Another solution is to pass it to the custom element as a Javascript property:

    function validate( value ) { return Number.isInteger( value) }
    myCustomElement.validation = validate
    

    Or, using a arrow function:

    myCustomElement.validation = v => Number.isInteger( va )
    

    class CustomInput extends HTMLElement {
        constructor() {
            super()
            var sh = this.attachShadow( { mode: 'open' } )
            sh.appendChild( tpl.content.cloneNode( true ) )
            
            var div = sh.querySelector( 'div' )
            div.addEventListener( 'input', () => { 
               if ( !this.validate( Number( div.textContent ) ) )
                div.classList.add( 'error' )
               else
                div.classList.remove( 'error' ) 
            } )        
        }
    }
    
    customElements.define( 'custom-input', CustomInput )
    
    integer.validate = v => Number.isInteger( v )
    <template id="tpl">
      <style>
        :host {
           display: inline-block ;
           min-width: 150px ;
           border: 1px solid cyan ;
        }
        
        div.error {
           color: red ;
        }
    
      </style>
      <div contenteditable></div>
    </template>
        
    <custom-input id="integer"></custom-input>

    0 讨论(0)
  • 2021-02-20 05:19

    Just pass it to the constructor. Your custom element statement:

    class CustomInput extends HTMLElement {
      constructor(validator) {
        super()
        this.validate = validator
      }
    
      /* Your Custom Input Methods */
    }
    

    And then instantiate your component via the new operator instead of the document.createElement.

    Instantiation:

    const customInputEl = new CustomInput((inputString) => {
      // your validation code
    })
    

    If you want to pass a function to the component, it must mean that you instantiate it via javascript anyway.

    0 讨论(0)
提交回复
热议问题