Expanded artifacts

element-page-model.js

This file is the root file for a page. It defines the menu, table and other widgets on the page.

Customization Examples

The buildPage function defines a number of variables which can be modified in the ‘custom-page-options’-anchor.

E.g. the template can be overwritten to change the layout of the page:

template = "customTemplates/fancy-layout";

You can also modify the title, menu etc.

Furthermore, the constants object can be modified to define a ‘constant value’ for the page. E.g. if an element has a status field, the following code make sure the page only shows items with the status “done”:

constants.status = "done";

element-table-view.js

The table-view file describes the table for a given element. It is used in the element-page-model file, but can also be reused in other pages.

Customization Examples

The table-view widget also has a template that can be modified.

Intents

Below you can see the expanded implementation of a ‘create’-button for a Person-table. Notice that instead of making a direct call to the ‘create’-dialog, a createIntentTrigger is used.

function defineNewInstanceButton(toolbar, input) {
    var createRightsRequest = accessRightsController.requestRight({
      element: PersonElement,
      requestedRight: AccessRights.Right.CREATE
    })
    var createIntent = PersonEvents.defineCreateIntentTrigger({
      constants: input.constants,
      values: input.values
    });
    return toolbar.defineButton({
      trigger: createIntent,
      icon: "icon-plus",
      visible: createRightsRequest.approved
    });
  }

This is to decouple the triggering of an intent (e.g. by pressing a button or through a shortcut) with the implementation of its execution (showing a popup or redirecting to a new page or …). It is possible to make a custom trigger for creating a new Person:

// anchor:custom-page-after:start
function defineNewInstanceShortCut(input) {
  var createIntent = PersonEvents.defineCreateIntentTrigger({
    constants: input.constants,
    values: input.values
  });

  // trigger create when pressing 'N'-key
  $(document).keypress(function(keyEvent) {
    if (!$(keyEvent.target).is("input") &&
      keyEvent.which === 110) {
      createIntent.trigger();
    }
  })
}
defineNewInstanceShortCut(tableContext);
// anchor:custom-page-after:end

Adding and removing buttons

The table has a number of provided buttons. It is possible to add and remove buttons from the toolbar to customize its functionality.

As an example, let’s replace the standard ‘create’-button with one that has more text. We copy the implementation of the ‘create’-button and make a few adjustments. We can then remove the button before we replace it with our new implementation:

// anchor:custom-page-after:start
function defineBetterNewInstanceButton(toolbar, input) {
  var createRightsRequest = accessRightsController.requestRight({
    element: PersonElement,
    requestedRight: AccessRights.Right.CREATE
  })
  var createIntent = PersonEvents.defineCreateIntentTrigger({
    constants: input.constants,
    values: input.values
  });
  return toolbar.defineButton({
    trigger: createIntent,
    label: "Make new Person",
    icon: "icon-plus",
    visible: createRightsRequest.approved,
    layout: "btn-success",
    position: 0
  });
}

toolbar.removeButton(newInstanceButton);
newInstanceButton = defineBetterNewInstanceButton(toolbar, tableContext)
// anchor:custom-page-after:end

element-waterfall.js

If a data-child is defined under an element, a waterfall-widget is expanded and added to the page of that element. This widget will show a tab for each child-element with a table of that element.

Tab customizations

It is possible to customize each tab in this file. First, there are a number of easily modifiable variables. As an example, we want to use a translation as the name of a tab to support multiple languages:

// anchor:custom-booking-tab-options:start
name = translate("euRent.person.tabs.booking");
// anchor:custom-booking-tab-options:end

Second, it is possible to modify the render options for the tab, namely it is possible to set the position and visibility of the tab. As an example, we make the Booking tab on the Person page visible only if the selected person is a customer.

// anchor:custom-booking-tab-options:start
var selectedPerson = input.target;
tabOptions.visible = ko.pureComputed(function() {
  var person = ko.unwrap(selectedPerson);
  return person.type === "Customer";
})
tabOptions.position = 0;
// anchor:custom-booking-tab-options:end

The tabs are rendered one by one and are placed at end by default. It is possible to use the position option to move the tab in between the already defined tabs. But to move it further back, it is necessary to modify the position of the later tabs.

Adding tabs

Lastly, it is possible to add additional tabs to the waterfall as follows:

// anchor:custom-methods:start
function defineAdditionalTab() {
  var tab = tabRow.defineTab({
      name: "custom tab",
      view: "euRent/custom-tab-template",
      viewModel: {/* ... */}
  })

  // ...
}
// anchor:custom-methods:end

// anchor:custom-page-after:start
defineAdditionalTab();
// anchor:custom-page-after:end

elements-std-create.js

For each dialog on the page, a ‘standard’ file is created. These will define the way a create, modify, view or delete action is handled. As an example, the ‘create’-dialog will be explained.

Default values

It is possible to provide some default values for the form as follows:

defaultValues.type = "Customer"

Disabling or hiding fields

One of the options defined for the form for the ‘create’-dialog is the layoutConfig. This option can be modified in order to hide and disable fields. As an example, we can make some fields visible only if the type field of a new Person is set to “Customer”:

// anchor:custom-options:start
var isCustomer = ko.observable();
layoutConfig.adres.visible = isCustomer;
// anchor:custom-options:end

// anchor:custom-form:start
var type = form.instance.type.value;
type.subscribe(function(newType) {
  if (newType === "Customer") {
    isCustomer(true);
  } else {
    isCustomer(false);
  }
});
// anchor:custom-form:end

Custom dialogs

Lastly, it may be necessary to create an entirely new file. You may want to start by copying the elements-std-create.js file and modifying it.

In order to make sure only our custom dialog is used, we need to register it with the intentHandlerLoader. Otherwise, this loader will load also the standard file when a create intent is triggered.

// anchor:custom-variables:start
var CustomCreate = require('euRent/booking/booking-cmd-create')

var IntentHandler = require('nsx/config/intent-handler');
var IntentAction = IntentHandler.Action;
var intentHandlerLoader = IntentHandler.getIntentHandlerLoader();
// anchor:custom-variables:end

// anchor:custom-page-model:start
CustomCreate.defineDialog(/*...*/);
intentHandlerLoader.registerIntentHandler({
  element: BookingElement,
  action: IntentAction.CREATE,
  handlerReference: "euRent/booking/booking-cmd-create"
});
 // anchor:custom-page-model:end

References