How to Create a Custom Field

This document is referring to a past Scout release. Please click here for the recent version.

This cheat sheet shows how to implement your own custom field for a ScoutJS application. In this example we will write a FlipCard field that will show a playing card. Clicking on the card will flip it from one side to the other.

Setup

For this example we use the helloscout git repository, but you can easily create the field in your own code base as well. In case you want to use the helloscout repo, clone and import it into your favourite IDE:

git clone https://github.com/bsi-software/helloscout.git

Read the readme and start the hellojs application to make sure it works.

Add Empty JS and CSS Files

Create the following files in the folder org.eclipse.scout.hellojs.ui.html

  • src/main/js/flipcard/FlipCardField.js The JavaScript file representing the field.

  • src/main/js/flipcard/FlipCardField.less The LESS file containing the styles of the field.

Add the JS file to the JS index

Listing 1. index.js
...
export {default as FlipCardField} from './flipcard/FlipCardField';
...

Add the LESS file to the LESS index

Listing 2. index.less
...
@import "flipcard/FlipCardField";
...

Minimal Code for a New FormField

Create a Minimal FormField

The FlipCard will inherit from FormField. Every form field consists of a container, a label, the actual field, a mandatory-indicator and a status.

Listing 3. FlipCardField.js
import {FormField} from '@eclipse-scout/core';

export default class FlipCardField extends FormField {
  _render() {
    // Create the container
    this.addContainer(this.$parent, 'flip-card-field');

    // Add a label
    this.addLabel();

    // Create the actual field. This will be your flip card.
    var $field = this.$parent.appendDiv('content');
    // add the field to the form field.
    this.addField($field);

    // Add other required form field elements
    this.addMandatoryIndicator();
    this.addStatus();
  };
}

Add the FlipCard to the HelloForm

Don’t forget to add the import for your FlipCardField.

Listing 4. HelloFormModel.js
{
  id: "hellojs.HelloForm",
  ...
  rootGroupBox: {
    ...
    fields: [
      {
        id: 'DetailBox',
        ...
        fields: [
          {
            id: 'NameField',
            ...

          },
          (1)
          {
            id: 'FlipCardField',
            objectType: FlipCardField,
            label: 'Flip the card',
            gridDataHints: {
              h: 5,
              weightY: 0
            }
          },
          {
            id: 'GreetButton',
            ...
          }
        ]
      }
    ]
  }
}
1 The FlipCard field

Now reload your browser and you should get the following result:

Result Minimal Form Field
flipCard01
Listing 5. FlipCard.js
import {FormField} from '@eclipse-scout/core';

export default class FlipCardField extends FormField {
    constructor() {
    super();
      this.$card = null;
      this.$front = null;
      this.$back = null;
      this.flipped = false;
      this.frontImage = null;
      this.backImage = null;
  }

  _render() {
    // Create the container
    this.addContainer(this.$parent, 'flip-card-field');
    // Add a label
    this.addLabel();

    // Create the actual field (1)
    var $field = this.$parent.appendDiv('content');
    // Create the card inside the field
    this.$card = $field.appendDiv('card')
      .on('mousedown', this._onCardMouseDown.bind(this)); //(2)
    this.$front = this.$card.appendDiv('front');
    this.$back = this.$card.appendDiv('back');
    // Add the field to the form field. It will be available as this.$field.
    this.addField($field);

    // Add other required form field elements
    this.addMandatoryIndicator();
    this.addStatus();
  }

  _renderProperties() { (3)
    super._renderProperties();
    this._renderFrontImage();
    this._renderBackImage();
    this._renderFlipped();
  }

  _renderFrontImage() {
    if (this.frontImage) {
      this.$front.append('<img src=\"' + this.frontImage + '\">');
    }
  }

  _renderBackImage() {
    if (this.backImage) {
      this.$back.append('<img src=\"' + this.backImage + '\">');
    }
  }

  _remove() { (4)
    super._remove();
    this.$card = null;
    this.$front = null;
    this.$back = null;
  }

  _onCardMouseDown() { (2)
    this.setFlipped(!this.flipped);
  }

  setFlipped(flipped) {
    this.setProperty('flipped', flipped);
  }

  _renderFlipped() {
    this.$card.toggleClass('flipped', this.flipped);
  }
}
1 Create the dom elements in the render function.
2 Add event handler which toggles the CSS class flipped.
3 Initial rendering of the properties. Applies the state to the DOM.
4 Keep the references clean. Reset DOM references when the field has been removed.
Listing 6. HelloForm.json
import {FlipCardField} from '../index';

export default {
  id: 'hellojs.HelloForm',
  ...
  rootGroupBox': {
    ...
    fields: [
      {
        id: 'DetailBox',
        ...
        fields: [
          {
            id: 'NameField',
            ...

          },
          (1)
          {
            id: 'FlipCardField',
            objectType: FlipCardField,
            label: 'Flip the card',
            frontImage: 'img/card-back.jpg',
            backImage: 'img/card-front.jpg',
            gridDataHints: {
              h: 5,
              weightY: 0
            }
          },
          {
            id: 'GreetButton',
            ...
          }
        ]
      }
    ]
  }
}
1 FlipCard field is inserted after the name field.
Listing 7. FlipCardField.less
.flip-card-field {

  .card {
    position: absolute;
    cursor: pointer;
    height: 100%;
    width: 152px;
    transition: transform 1s; (1)
    transform-style: preserve-3d;

    &.flipped {
      transform: rotateY( 180deg );
    }

    & > div {
      display: block;
      height: 100%;
      width: 100%;
      position: absolute;
      backface-visibility: hidden; (2)

      &.back {
        transform: rotateY( 180deg ); (3)
      }

      & > img {
        height: 100%;
        width: 100%;
      }
    }
  }
}
1 Animation of the card.
2 Ensure back side is not visible.
3 Rotation to back side.

Finally, create a folder img in the WebContent folder (org.eclipse.scout.hellojs.ui.html.app/src/main/resources/WebContent) and paste the two images of the card into that folder. You should be able to find the images using Google ;-)

Result Flip Card
flipCard02