Services and Dependency Injection

In this section, by a service we mean a program component that provides some specific functionality to other components. The most common examples of services are components working with REST APIs, internationalization, utility services, caches, etc.

There is a number of approaches of creating services and injecting them into your web components. We recommend to adopt the way described below.

Let’s imagine an application that shows notifications to users. These notifications are represented by a piece of text that is shown to users for a short time to inform them about some event. Different parts of the application need an ability to show notifications.

Here is a possible implementation:

index.html
<html>
<head>
	<link rel="import" href="src/recipes/di/forbidden-button.html">
	<script src="bower_components/webcomponentsjs/webcomponents-loader.js"></script>
</head>
<body>
    <forbidden-button></forbidden-button>
</body>
</html>
src/recipes/di/forbidden-button.html
<link rel="import" href="../../../bower_components/polymer/polymer-element.html">
<link rel="import" href="notification-service.html">

<dom-module id="forbidden-button">
  <template>
    <style>
      .forbidden-btn {
        background: #006ba9;
        border: 1px solid #006ba9;
        border-radius: 5%;
        color: #ffffff;
        padding: 5px 10px;
      }
    </style>

    <button class="forbidden-btn" on-click="notifyWrongdoing">Don't push me!</button>

  </template>
  <script>
    class ForbiddenButton extends Polymer.Element {
      static get is() {
        return 'forbidden-button';
      }

      static get properties() {
        return {
          // Injecting the service
          notificationManager: {
            type: Object,
            value: NotificationManager
          }
        }
      }

      notifyWrongdoing() {
        this.notificationManager.showInfo('You have just pressed a button you should not have pressed. ' +
          'Please, try not to do it again.');
      }
    }

    customElements.define(ForbiddenButton.is, ForbiddenButton);
  </script>
</dom-module>
src/recipes/di/notification-service.html
<link rel="import" href="../../../bower_components/paper-toast/paper-toast.html">

<script>

  // Constructor. Place all your properties and initialization logic here.
  NotificationManagerClass = function() {
    this._toast = null;
  };

  // Place all methods here
  NotificationManagerClass.prototype = {

    get toast() {
      if (!this._toast) {
        this._toast = Polymer.dom(document.body).querySelector('#notificationToast');

        if (!this._toast) {
          this._toast = document.createElement('paper-toast');
          this._toast.id = 'notificationToast';
          Polymer.dom(document.body).appendChild(this._toast);
        }
      }
      return this._toast;
    },

    showInfo: function(text) {
      this.toast.text = text;
      this.toast.show();
    }

  };

  // Create an instance of the service and put it into a global variable
  NotificationManager = new NotificationManagerClass();
</script>

Result

So, basically we just instantiate some object, put it in a global variable and assign this variable to a component’s property.