Search code examples
javascriptpolymerweb-componentcustom-element

Polymer: Create a "general" custom element


I am attempting to build an element with attributes that would specify which element should take place of this element.

I have a 3d-card flip element that I am using fo this purposes in the index.html that is defined as:

<html>
    <head>
        <script src="bower_components/webcomponentsjs/webcomponents.js">
        </script>
        <link rel="import" href="elements/general-element.html">
    </head>
    <body>
        <general-element 
            name="card-flip" 
            address="elements/card-flip.html">
            <front>
                FRONT
            </front>
            <back>
                BACK
            </back>
        </general-element>
    </body>
</html>

The general-element.html is defined here:

<link rel="import" 
    href="../bower_components/polymer/polymer.html">
<polymer-element name="general-element" attributes="name address">
    <template>
        <div id="element_here">
        </div>
    </template>
    <script>

      function addElementToDOM( element_name, _that ) {
          var elem = _that.shadowRoot.querySelector( "#element_here" );
          add_elem = document.createElement( element_name );
          elem.appendChild( add_elem );
      }

        Polymer ( 'general-element', {
          ready: function() {
              if ( 
                  ( this.address != undefined ) && 
                  ( this.name != undefined ) ) {

                  Polymer.import( 
                      [this.address], 
                      addElementToDOM( this.name, this )
                  );
              }
          }
        } );
    </script>
</polymer-element>

WARNING: The output is a blank with an error in the console saying Attributes on card-flip were data bound prior to Polymer upgrading the element. This may result in incorrect binding types.

Can this be achieved in any way?


Solution

  • It’s hard to say what you are trying to achieve, but I would point at some glitches within your code and provide the working version with paper-button instead of flip-card (since I have no code of flip-card.)

    TL;DR Live preview: http://plnkr.co/edit/yO865EkclZAsWBhzVSU4?p=preview

    1. The main issue with your code is that you call function addElementToDOM instead of passing it as a callback as requested by Polymer.import. function() { addElementToDOM(...); } would be OK.

    2. You use hyphen-less names for custom elements (like front and back) which is conventionally prohibited. Please use dashed as in my example.

    3. You have your function polluted into global space for no reason. I put it inside an element.

    4. You were likely want to puts your custom flip-card between front and back, but there is no vestige of content select='front/back' tag inside your template.

    5. You are trying to access shadowRoot in improper way. You might want to take a look at getDistributedNodes function, but in this case it’s easier to use naming convention and address an element simply by this.$.elementHere.

    6. You are supposed to explicitly specify <body unresolved> for the polyfill to take care about unresolved things.

    The working code:

    <!doctype html>
    <html>
    <head>
      <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
      <title>Add paper button</title>
      <script src="https://www.polymer-project.org/components/webcomponentsjs/webcomponents.js"></script>
      <link href="https://www.polymer-project.org/components/polymer/polymer.html" rel="import"> 
    </head>
    
    <body unresolved>
      <polymer-element name="general-element" attributes="name address">
        <template>
          <content select='my-front'></content>
          <div id="elementHere">
          </div>
          <content select='my-back'></content>
        </template>
        <script>
          Polymer ({
            addElementToDOM: function ( element_name ) {
              var elem = this.$.elementHere;
              add_elem = document.createElement( element_name );
              add_elem.appendChild(document.createTextNode('¡Hola!'));
              elem.appendChild( add_elem );
            },
    
            domReady: function() {
              if ( this.address && this.name ) {
                var self = this;
                Polymer.import( 
                  [self.address], 
                  function() { self.addElementToDOM( self.name ); }
                );
              }
            }
          });
        </script>
      </polymer-element>
      <general-element 
          name="paper-button" 
          address="https://www.polymer-project.org/components/paper-button/paper-button.html">
          <my-front>
              FRONT
          </my-front>
          <my-back>
              BACK
          </my-back>
      </general-element>
    </body>
    </html>
    

    I bet, your code could be working by applying the fix #1 but I strongly suggest you to fix other glitches as well. Hope it helps.

    P.S. Why on the earth you needed to dynamically import your element? What’s wrong with simple

        <template>
          <content select='my-front'></content>
     <!-- ⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓ -->
          <flip-card></flip-card>
          <content select='my-back'></content>
        </template>