Skip to content

601 Setting Up The Module

zarlex edited this page Mar 9, 2017 · 1 revision

Setting up the Super Power Module

As a basis for our super power module we take the hero module. The base functionality of the super power module is pretty much the same as for the hero module:

  • we have a list view to show all super powers
  • we have a delte button with a confirm modal to delete a super power
  • we have a form view to create/edit super powers

Copy the folder

Copy the hero folder and name it super-power. After that we are adjusting the file names

  • _hero.scss -> _super-power.scss
  • hero.js -> super-power.js
  • hero.routes.js -> super-power.routes.js

Adjust the file content

_super-power.scss

This file can stay as it is because it is just including files that were also copied

super-power.js

Replace everything that was hero with superPower

angular.module('mwPortal.SuperPower', [])
// Config i18n for translations
  .config(function (i18nProvider) {
    i18nProvider.addResource('app/modules/super-power/i18n');
  })

  // Config response handler toasts that are triggered by backend responses
  .config(function (ResponseToastHandlerProvider) {
    // Display toast when a POST request on the route was successful (item has been created on server)
    ResponseToastHandlerProvider.registerSuccessToast(
      '/api/super-powers', // /api/super-powers route
      {
        singular: 'superPower.toasts.serverResponses.success.created.singular',
        plural: 'superPower.toasts.serverResponses.success.created.plural'
      },
      'POST', // this is the method fo which the toast should be displayed
      'success' // this is the toast type
    );

    // Display toast when a PUT request on the route was successful (item has been updated on server)
    ResponseToastHandlerProvider.registerSuccessToast(
      '/api/super-powers/*', // /api/super-powers/{id} route
      {
        singular: 'superPower.toasts.serverResponses.success.updated.singular',
        plural: 'superPower.toasts.serverResponses.success.updated.plural'
      },
      'PUT', // method
      'success' // toast type
    );

    // Display toast when a DELETE request on the route was successful (item has been deleted from server)
    ResponseToastHandlerProvider.registerSuccessToast(
      '/api/super-powers/*', // /api/super-powers/{id} route
      {
        singular: 'superPower.toasts.serverResponses.success.deleted.singular',
        plural: 'superPower.toasts.serverResponses.success.deleted.plural'
      },
      'DELETE', // method
      'success' // toast type
    );
  });

super-power.routes.js

angular.module('mwPortal.SuperPower')
  .config(function ($routeProvider, $injector) {
    $routeProvider
      .when('/super-powers', {
        templateUrl: 'app/modules/super-power/templates/index.template.html',
        controller: 'SuperPowerIndexController',
        controllerAs: 'ctrl',
        cssClasses: 'super-power index',
        resolve: $injector.get('SuperPowerIndexControllerResolver')
      })
      .when('/super-powers/new', {
        templateUrl: 'app/modules/super-power/templates/new.template.html',
        controller: 'SuperPowerFormController',
        controllerAs: 'ctrl',
        cssClasses: 'super-power form new',
        resolve: $injector.get('SuperPowerFormControllerResolver')
      })
      .when('/super-powers/:superPowerId/edit', {
        templateUrl: 'app/modules/super-power/templates/edit.template.html',
        controller: 'SuperPowerFormController',
        controllerAs: 'ctrl',
        cssClasses: 'super-power form edit',
        resolve: $injector.get('SuperPowerFormControllerResolver')
      });
  });

Add the file to the index.html

...
<!-- Super Powers module -->
<script src="app/modules/super-power/super-power.js"></script>
<script src="app/modules/super-power/super-power.routes.js"></script>
...

New menu entry

As we have new routes we want to have a new menu entry in our menu bar. It belongs also to hero even though it is a new module so we make the hero menu entry a drop down entry. It has the two sub entries heroes and sub entries

Open the file index.html add the new entry as a sub entry of the heroes

...
<div mw-menu-top-entries>
  ...
  <div mw-menu-entry
       label="{{'main.menu.heroes' | i18n}}"> <!-- title of dropdown -->
    <div mw-menu-entry
         label="{{'main.menu.heroes' | i18n}}"
         url="#/heroes">
    </div> <!-- drop down item -->
    <div mw-menu-entry
         label="{{'main.menu.superPowers' | i18n}}"
         url="#/super-powers">
    </div> <!-- drop down item -->
  </div>
</div>
...

Add the translation to the file main/i18n/en_US.json

{
  "main": {
    "menu": {
      ...
      "superPowers": "Super powers"
    }
    ...
  }
}

and to de_DE.json

{
  "main": {
    "menu": {
      ...
      "superPowers": "Superkräfte"
    }
    ...
  }
}

Models

In the models folder are two models the hero.model.js and super-power.model.js Delete hero.model.js Go to the folder hero/models and delete the file super-power.model.js because it is in this module now

Adjust the file path in the index.html

...
<!-- Super Powers module -->
...
<script src="app/modules/super-power/models/super-power.model.js"></script>
...

Collections

In the collections folder are two collections the heroes.collection.js and super-powers.collection.js Delete heroes.collection.js Go to the folder hero/collections and delete the file super-powers.collection.js because it is in this module now

Adjust the file path in the index.html

...
<!-- Super Powers module -->
...
<script src="app/modules/super-power/collections/super-powers.collection.js"></script>
...

controllers/index.controller.js

angular.module('mwPortal.SuperPower')
  .controller('SuperPowerIndexController', function (SuperPowerDeleteConfirmModal, superPowers) {
    var superPowerDeleteConfirmModal = new SuperPowerDeleteConfirmModal();

    this.superPowers = superPowers;

    this.showDeleteConfirmModal = function(){
      // prepare the modal and set all attributes that are needed in the modal
      superPowerDeleteConfirmModal.setScopeAttributes({
        // this attribute will be available in the modal controller
        selected: this.superPowers.selectable.getSelected()
      });

      // show the modal
      superPowerDeleteConfirmModal.show();
    };
  })

  .constant('SuperPowerIndexControllerResolver', {
    superPowers: ['SuperPowersCollection', function (SuperPowersCollection) {
      return ( new SuperPowersCollection() ).fetch();
    }]
  });

Add the file to the index.html

...
<!-- Super Powers module -->
...
<script src="app/modules/super-power/controllers/index.controller.js"></script>
...

templates/index.template.js

<div mw-header
     title="{{'superPower.index.header' | i18n }}"></div>

<div class="row">
  <div class="col-md-3">
   <div mw-sidebar>
     <a href="#/super-powers/new"
        class="btn btn-primary btn-block">
       <span mw-icon="fa-plus-square-o"></span>
       {{'superPower.index.newSuperPower' | i18n}}
     </a>

     <div mw-button-help>
       <button class="btn btn-danger btn-block"
               ng-click="ctrl.showDeleteConfirmModal()"
               ng-disabled="ctrl.superPowers.selectable.getSelected().length<1">
         <span mw-icon="fa-trash-o"></span>
         {{'superPower.index.deleteSuperPower' | i18n}}
       </button>
       <div mw-button-help-condition="ctrl.superPowers.selectable.getSelected().length < 1"
            mw-button-help-text="{{'superPower.tooltips.buttonHelp.nothingSelected' | i18n }}"></div>
     </div>
   </div>
  </div>

  <div class="col-md-9">
    <div mw-listable-head-2
         collection="ctrl.superPowers"
         collection-name="{{'superPower.entityName' | i18n}}"
         name-attribute="name"></div>

    <table mw-listable-bb
           collection="ctrl.superPowers">
      <thead>
      <tr mw-listable-header-row-bb>
        <th mw-listable-header-bb
            width="50%">
          {{'superPower.name' | i18n}}
        </th>
      </tr>
      </thead>
      <tbody>
      <tr mw-listable-body-row-bb
          ng-repeat="item in ctrl.superPowers.models">
        <td class="primary-column">
          <a href="#/super-powers/{{item.id}}/edit">{{ item.get('name') }}</a>
        </td>
        <td mw-listable-link-show-bb="#/super-powers/{{item.id}}/edit"></td>
      </tr>
      </tbody>
    </table>
  </div>
</div>

modals/super-power-delete-confirm.modal.js

rename hero-delete-confirm.modal.js to super-power-delete-confirm.modal.js and adjust the file content

angular.module('mwPortal.SuperPower')

  .service('SuperPowerDeleteConfirmModal', function (Modal) {
    return Modal.prepare({
      templateUrl: 'app/modules/super-power/modals/templates/super-power-delete-confirm.modal.template.html',
      controller: 'SuperPowerDeleteConfirmModalController'
    });
  })

  .controller('SuperPowerDeleteConfirmModalController', function ($scope) {
    $scope.deleteSelected = function () {
      // use .secureEach() instead of .each() otherwise you will get reference problems http://stackoverflow.com/a/22024432
      $scope.selected.secureEach(function (model) {
        model.destroy();
      });
    };
  });

Add the file to the index.html

...
<!-- Super Powers module -->
...
<script src="app/modules/super-power/modals/super-power-delete-confirm.modal.js"></script>
...

modals/templates/super-power-delete-confirm.template.html

rename hero-delete-confirm.template.html to super-power-delete-confirm.template.html and adjust the file content

<div mw-modal-confirm ok="deleteSelected()">
  <div ng-if="selected.length === 1">
    <p>{{ 'superPower.modals.superPowerDeleteConfirm.superPower' | i18n:{name: selected.first().get('name')} }}</p>
  </div>

  <div ng-if="selected.length > 1">
    <p>{{ 'superPower.modals.superPowerDeleteConfirm.superPowers' | i18n }}</p>
    <ul>
      <li ng-repeat="model in selected.models">{{ model.get('name') }}</li>
    </ul>
  </div>
</div>

controllers/form.controller

angular.module('mwPortal.SuperPower')
  .controller('SuperPowerFormController', function ($location, SuperPowersCollection, superPower) {
    this.superPower = superPower;

    this.goBack = function(){
      $location.path('/super-powers');
    };

    this.save = function(){
      return this.superPower.save().then(function(){
        this.goBack();
      }.bind(this));
    };

    this.cancel = function(){
      this.goBack();
    };
  })

  .constant('SuperPowerFormControllerResolver', {
    superPower: ['$route', 'SuperPowerModel', function ($route, SuperPowerModel) {
      if ($route.current.params.superPowerId) {
        return ( new SuperPowerModel({ id: $route.current.params.superPowerId }) ).fetch();
      } else {
        return new SuperPowerModel();
      }
    }]
  });

Add the file to the index.html

...
<!-- Super Powers module -->
...
<script src="app/modules/super-power/controllers/form.controller.js"></script>
...

templates/_form.html

<div mw-input-wrapper
     label="{{'superPower.name' | i18n}}">
  <input name="name"
         type="text"
         ng-model="name"
         mw-model="ctrl.superPower"
         required>
</div>

templates/new.html

<form name="superPowerForm" mw-form-leave-confirmation class="row">
  <div mw-header
       title="{{'superPower.new.header' | i18n }}">
    <div mw-form-actions
         save="ctrl.save()"
         cancel="ctrl.cancel()"></div>
  </div>

  <div class="col-md-12" ng-include="'app/modules/super-power/templates/_form.template.html'"></div>
</form>

templates/edit.html

<form name="superPowerForm" mw-form-leave-confirmation class="row">
  <div mw-header
       title="{{'superPower.edit.header' | i18n:{name: ctrl.superPower.get('name')} }}">
    <div mw-form-actions
         save="ctrl.save()"
         cancel="ctrl.cancel()"></div>
  </div>

  <div class="col-md-12" ng-include="'app/modules/super-power/templates/_form.template.html'"></div>
</form>

i18n/en_US.json

{
  "superPower": {
    "entityName": "Super Powers",
    "name": "Name",
    "superPowers": "Superpowers",
    "tooltips": {
      "buttonHelp": {
        "nothingSelected": "No super power has been selected"
      }
    },
    "index": {
      "header": "Super Powers",
      "newSuperPower": "Create Super Power",
      "deleteSuperPower": "Delete"
    },
    "new": {
      "header": "Create a new Super Power"
    },
    "edit": {
      "header": "Edit {{name}}"
    },
    "modals": {
      "superPowerDeleteConfirm": {
        "superPower": "Do you really want to delete the super power \"{{name}}\"?",
        "superPowers": "Do you really want to delete the following super powers?"
      }
    },
    "toasts": {
      "serverResponses": {
        "success": {
          "created": {
            "singular": "The super power {{name}} has been successfully created!",
            "plural": "{{$count}} super powers have been successfully created!"
          },
          "updated": {
            "singular": "The super power {{name}} has been successfully updated!",
            "plural": "{{$count}} super powers have been successfully updated!"
          },
          "deleted": {
            "singular": "The super power {{name}} has been successfully deleted!",
            "plural": "{{$count}} super powers have been successfully deleted!"
          }
        }
      }
    }
  }
}

i18n/de_DE.json

{
  "superPower": {
    "entityName": "Superkräfte",
    "name": "Name",
    "superPowers": "Superkräfte",
    "tooltips": {
      "buttonHelp": {
        "nothingSelected": "Es wurde keine Superkraft ausgewählt"
      }
    },
    "index": {
      "header": "Superkräfte",
      "newSuperPower": "Superkraft erstellen",
      "deleteSuperPower": "Löschen"
    },
    "new": {
      "header": "Neue Superkraft erstellen"
    },
    "edit": {
      "header": "Edit {{name}}"
    },
    "modals": {
      "superPowerDeleteConfirm": {
        "superPower": "Möchten Sie die Superkraft \"{{name}}\" wirklich löschen?",
        "superPowers": "Möchten Sie die folgenden Superkräfte wirklich löschen?"
      }
    },
    "toasts": {
      "serverResponses": {
        "success": {
          "created": {
            "singular": "Die Superkraft {{name}} wurde erfolgreich angelegt!",
            "plural": "{{$count}} Superkräfte wurden erfolgreich angelegt!"
          },
          "updated": {
            "singular": "Die Superkraft {{name}} wurde erfolgreich aktualisiert!",
            "plural": "{{$count}} Superkräfte wurden erfolgreich aktualisiert!"
          },
          "deleted": {
            "singular": "Die Superkraft {{name}} wurde erfolgreich gelöscht!",
            "plural": "{{$count}} Superkräfte wurden erfolgreich gelöscht!"
          }
        }
      }
    }
  }
}
Clone this wiki locally