Mixins
Inheritance in Polymer is implemented with so called mixins. A mixin is a set of methods, properties, observers and lifecycle callback methods that can be inherited by any Polymer component.
Each web component can use any number of mixins. Web components can use mixins' methods and properties as if they were their own. And mixins can use web components' methods and properties.
Below is an example demonstrating how to write and use mixins. It’s a spelling improvement program that offers a user to type a word. If the user fails to spell it correctly then the input will be highlighted with red. On any typing the highlighting will be removed. Logic for setting/removing error state in the component is implemented by a mixin called ValidatedElementMixin
.
Spelling checker
Source code
<html>
<head>
<link rel="import" href="src/polymer-advanced/mixins/spelling-checker.html">
<script src="bower_components/webcomponentsjs/webcomponents-loader.js"></script>
</head>
<body>
<spelling-checker word="Elephant"></spelling-checker>
</body>
</html>
<link rel="import" href="../../../bower_components/polymer/polymer-element.html">
<link rel="import" href="input-with-validation.html">
<dom-module id="spelling-checker">
<template>
<input-with-validation id="wordInput" value="{{typedValue}}">
Please try to enter word "[[word]]" without mistakes
</input-with-validation>
<button on-click="checkWord">Check</button>
</template>
<script>
class SpellingChecker extends Polymer.Element {
static get is() {
return 'spelling-checker';
}
static get properties() {
return {
typedValue: String,
word: String
}
}
checkWord() {
if (this.typedValue === this.word) {
alert('Great! You did it!');
} else {
this.$.wordInput.setError('The word was not typed correctly. Please, try again!');
}
}
}
customElements.define(SpellingChecker.is, SpellingChecker);
</script>
</dom-module>
<link rel="import" href="../../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../../bower_components/polymer/lib/elements/dom-if.html">
<link rel="import" href="../../../bower_components/iron-input/iron-input.html">
<link rel="import" href="validated-element-mixin.html">
<dom-module id="input-with-validation">
<template>
<style>
.error-input-msg,
input[error] {
color: red;
}
</style>
<label>
<slot></slot>
</label>
<br/>
<br/>
<iron-input bind-value="{{value}}">
<input error$="[[error]]" placeholder="[[placeholder]]" />
</iron-input>
<br/>
<br/>
<template is="dom-if" if="[[errorMsg]]">
<div class="error-input-msg">[[errorMsg]]</div>
<br/>
</template>
</template>
<script>
// Please note how we are inheriting our class from a mixin
class InputWithValidation extends ValidatedElementMixin(Polymer.Element) {
static get is() {
return 'input-with-validation';
}
static get properties() {
return {
value: {
type: String,
// This attribute is required to enable 2-way binding.
// If we don't set it then the client of the input-with-validation.html won't get notifications
// that the property has changed.
notify: true
}
}
}
}
customElements.define(InputWithValidation.is, InputWithValidation);
</script>
</dom-module>
<script>
// Mixin can contain properties, observers, methods, lifecycle callback methods as a normal Polymer component
ValidatedElementMixin = function(superClass) {
// Actually a mixin function just returns a class extending a class passed to it
return class extends superClass {
static get properties() {
return {
error: Boolean,
errorMsg: String
};
}
static get observers() {
return [
'_resetError(value)'
];
}
setError(msgCode) {
this.set('error', true);
this.set('errorMsg', msgCode);
}
_resetError() {
this.set('error', false);
this.set('errorMsg', null);
}
}
};
</script>
input-with-validation
represents a common UI component that supports validation. ValidatedElementMixin
can be used with other types of elements: comboboxes, text areas, radio-buttons, etc.
Tip
|
Please note what we marked the |
In this example, we used just one mixin, but it’s possible to use any number of mixins by including them one into another. For example, we could create something like that:
class PowerfulInput extends ElementWithDebounceMixin(SelfPersistedElementMixin(ValidatedElementMixin(Polymer.Element)))
Tip
|
Please note that prior to version 2.0, Polymer used so called behaviors instead of mixins. They are elements similar to mixins with the same purpose and possibilities but using another syntax for creation and usage. You don’t need to create or use behaviors in your code but you might encounter them in third-party components. See more details in https://www.polymer-project.org/1.0/docs/devguide/behaviors. |
- What we have learned so far
-
-
We can use mixins to implement some common logic and share it between components.
-
Mixins can contain methods, properties, lifecycle callback methods and observers.
-
After extending a mixin, a Polymer component doesn’t know which properties/methods are inherited and which are not. So, the component treats them the same.
-
In order to allow some property to be used by clients in two-way binding, we have to mark it with the
notify
parameter.
-