dman
dman

Reputation: 11064

Extending Custom Behavior

In polymer 1.0, I created custom behavior pageBehavior for two custom elements. On one of the elements, I would like to extend the behavior. After reading the docs, it seems that I would need to create another behavior and place it in array. I don't want to create another behavior because only this element will be using the extra code.

With the element and the extended behavior needed, how can I add hidePrintButton and to the properties and overwrite function fullDisplayeMode?

custom element:

  <script>
    Polymer({
      is: "resume-page",
      properties: {
        hidePrintButton: {
          type: Boolean,
          reflectToAttribute: true,
          value: true
        }
      },
      behaviors: [pageBehavior],
      fullDisplayMode: function() {
        this.show = true;
        this.hidePrintButton = false;
        this._toggleStyles();
        this.nextElementSibling.show = true;
      }
    });
  </script>

the page behavior:

<script>
  pageBehavior = {
    properties: {
      hideRipple: {
        type: Boolean,
        value: false
      },
      fullDisplay: {
        type: Boolean,
        value: false
      },
      show: {
        type: Boolean,
        reflectToAttribute: true,
        value: true
      }
    },
    _mediaQuery: function(section) {
      if (window.matchMedia( "(min-width: 1200px)" )) {
        section.style.width = "90%";
      } else {
        section.style.width ="90%";
      }
    },
    _toggleWidth: function(section, fullDisplay) {
      if (fullDisplay) {
        section.style.width = "100%";
      } else {
        this._mediaQuery(section);
      }
    },
    _toggleHover: function(section, fullDisplay) {
      if (fullDisplay) {
        section.classList.remove('enabled-hover');
      } else {
        section.classList.add('enabled-hover');
      }
    },
    _toggleRipple: function(fullDisplay) {
      //This is necessary because if page ripple
      //is hidden to quick the animation doesn't finish
      if (fullDisplay) {
        setTimeout(function() {
          this.hideRipple = true;
        }.bind(this), 700);
      } else {
        this.hideRipple = false;
      }
    },
    _toggleStyles: function(fullDisplay) {
      var section = this.firstElementChild;
      this._toggleRipple(fullDisplay);
      this._toggleWidth(section, fullDisplay);
      this._toggleHover(section, fullDisplay);
    },
    fullDisplayMode: function() {
      this._toggleStyles(true);
      this.show = true;
      this.nextElementSibling.show = true;
    },
    homeMode: function() {
      this._toggleStyles(false);
      this.show = true;
      this.nextElementSibling.show = false;
    },
    disappearMode: function() {
      this.show = false;
      this.nextElementSibling.show = false;
    }
  }
</script>

Upvotes: 2

Views: 886

Answers (2)

Jose A
Jose A

Reputation: 11077

I don't know since when we can do this, but we CAN extend behaviors: https://www.polymer-project.org/1.0/docs/devguide/behaviors#extending

I'm going to use as an example the Polymer.AppLocalizeBehavior from app-localize-behavior to set the default language.

1) Namespace your behavior, so they don't collide with others:

var MyNamespace = MyNamespace|| {};

2) Write the behavior's implementation:

MyNamespace.LocalizeImpl = {
        ready() {
        },
        attached: function() {
         this.loadResources(this.resolveUrl('../../../locales.json'));
        },
        properties: {
            language : {
                value : "en"
            } 
        },
  };

3) Add the implementation to the new behavior in an array.

MyNamespace.Localize = [Polymer.AppLocalizeBehavior, MyNamespaceLocalize.Impl]

All together:

var MyNamespace = MyNamespace || {};

    MyNamespace.Localize = {
        ready() {
        },
        attached: function() {
         this.loadResources(this.resolveUrl('../../../locales.json'));
        },
        properties: {
            language : {
                value : "en"
            } 
        },
  };

  MyNamespace.LocalizeBehavior = [Polymer.AppLocalizeBehavior, MyNamespace.Localize]

Then, in your element, include it like this:

<link rel="import" href="../../../../bower_components/polymer/polymer.html">
<link rel="import" href="../path-to-custom-behavior/mynamespace-localize-behavior/mynamespace-localize-behavior.html">
<dom-module id="my-element">
  <style is="custom-style"></style>
  <template is="dom-bind">
   <template is="dom-if" if="{{query}}">
      <h1> {{localize("EmailActivationSuccessful")}}</h1>
    </template>
    <template is="dom-if" if="{{!query}}">
      <h1> {{localize("EmailCodeExpired")}}</h1>
    </template>
  </template>
  <script>
  (function() {
      'use strict';
       Polymer({
        is: 'my-element',
        behaviors: [MyNamespace.LocalizeBehavior],
         });
    })();

  </script>

Now, as you can see I've only included the MyNamespace.LocalizeBehavior and started using all the methods and functions from "Polymer.AppLocalizeBehavior"

This is a great way for setting the default language and only handling the language logic in a single element.

Explanation and notes:

  1. All the properties, methods, functions that match the previous behavior are overwritten. In this case, I overwrote the "language" property from "Polymer.AppLocalizeBehavior".
  2. Remember include the .html file where the old behavior is located only where you are extending the behavior. Afterwards you only include your custom behavior wherever and whenever you want.
  3. In point #3, the array works like this: the first element is the behavior to extend/overwrite, and the second one is your implementation, or the extended behavior.

Upvotes: 1

Hugo Zapata
Hugo Zapata

Reputation: 4474

A behavior method cannot be extended. It can only be overwritten. However you could still abstract the shared logic in the behavior and have some empty methods on the behavior for customization purposes.

E.g

//In your behavior

fullDisplayMode: function() {
    this.show = true;
    this._toggleStyles();
    this.nextElementSibling.show = true;
    this.prepareFullDisplayMode();
  },
prepareFullDisplayMode:function(){
  //Empty inside behavior
  //Elements could opt to implement it with additional logic
}

Using this pattern, one of your custom elements could add additional logic by implementing the 'prepareFullDisplayMode' while the other would not need to.

Upvotes: 3

Related Questions