View source | Discuss this page | Page history | Printable version   

How to Create Advanced filters components

Bulbgraph.png   This feature is available starting from RR17Q1

Contents

Overview

In the Web POS (and in mobile technology in general), developers can create a selectors with advanced filter functionality.

Base components

In order to reuse the advanced filters selectors in other places of WebPOS, has been created three components:

Filters criterias

Previous components need a filter model to define filters criterias, in this model each property is used to define a filter criteria. The property is defined by following fields:

The following fields only are used when is set "isList" (the values to fill out the list are readed from terminal properties):

The following fields only are used when is set "isSelector":

Events

When a selector is implemented and you like to will be used in other selector filter, it necessary when an item is selected send a new event to notify to the selection change.

When the selector is opened in the arguments are passed the following parameters:

When a item is selected, it necessary to send the following event (you can see an example in org.openbravo.retail.posterminal/js/components/businessparter_selector.js):

 
  selector: {
    name: '',    // The filter name
    value: '',   // Selected identifier
    text: ''     // Selected name
  }
 

Example

View larger
View larger

To illustrate the new functionality for filter selectors, we build a example of selector with advanced filters. And this selector may be used in other filters too.

In this example you are defined the followings filters:

The following figure shown selector and advanced filter.

The following sections shown the code to implement this example.


Filter model

To define the fields to be used as filters is necessary create a model. Each model property can be define a filter. Only properties with filter = true are used as filters.

 
OB.Model.Example_OrderFilter = OB.Data.ExtensibleModel.extend({});
 
OB.Model.Example_OrderFilter.addProperties([{
  name: 'orderDate',
  column: 'orderDate',
  filter: true,
  type: 'TEXT',
  caption: 'OBORPRE_LblOrderDate',
  operator: OB.Dal.EQ,
  isDate: true
}, {
  name: 'documentNo',
  column: 'documentNo',
  filter: true,
  type: 'TEXT',
  isFixed: true,
  caption: 'OBORPRE_LblDocumentNo',
  operator: OB.Dal.CONTAINS
}, {
  name: 'city',
  column: 'locCity',
  filter: true,
  type: 'TEXT',
  caption: 'OBPOS_LblCity',
  operator: OB.Dal.CONTAINS,
  preset: {
    id: '',
    name: 'Pamplona'
  }
}, {
  name: 'deliveryMethod',
  column: 'deliveryMethod',
  filter: true,
  type: 'TEXT',
  caption: 'OBORPRE_LblDeliveryMethod',
  operator: OB.Dal.EQ,
  isList: true,
  termProperty: 'deliveryConditions',
  propertyId: 'id',
  propertyName: 'name',
  preset: {
    id: 'DeferredCarriedAway',
    name: ''
  }
}, {
  name: 'customer',
  column: 'customer',
  filter: true,
  type: 'TEXT',
  caption: 'OBPOS_LblCustomer',
  operator: OB.Dal.EQ,
  selectorPopup: 'modalcustomer',
  isSelector: true,
  preset: {
    id: '',
    name: ''
  }
}, {
  name: 'orderedQuantity',
  column: 'orderedQuantity',
  filter: true,
  type: 'NUMBER',
  caption: 'OBPOS_LineQuantity',
  isAmount: true,
  preset: {
    id: 'lessThan',
    name: '5'
  }
}]);

FilterSelectorTableHeader

You need to define a component for the table header on result set to show. This component must be inherit from OB.UI.ScrollableTableHeader. The base component include a row with filter, cancel and search buttons. If you want to have advanced filter dialog, you need define a button for this purpose.

The advanced filter button must be inherit from OB.UI.ButtonAdvancedFilter and define the property dialog with the name of advanced filter dialog.

 
enyo.kind({
  kind: 'OB.UI.ButtonAdvancedFilter',
  name: 'Example.UI.ButtonAdvancedFilter',
  dialog: 'Example_ModalAdvancedFilter'
});

The component that defines the table header should define the property filters to get the filter model properties.

 
enyo.kind({
  name: 'Example.UI.ModalScrollableHeader',
  kind: 'OB.UI.ScrollableTableHeader',
  components: [{
    style: 'padding: 10px;',
    kind: 'OB.UI.FilterSelectorTableHeader',
    name: 'filterSelector',
    filters: OB.Model.Example_OrderFilter.getProperties()
  }, {
    showing: true,
    style: 'padding: 7px;',
    components: [{
      style: 'display: table; width: 100%;',
      components: [{
        style: 'display: table - cell; text-align: center; width: 100%;',
        components: [{
          kind: 'Example.UI.ButtonAdvancedFilter'
        }]
      }]
    }]
  }]
});

Scrollable table components

The purpose of the following code is to be used as example for scrollable table component for represent filtered data.

To render a datarow you will extend a OB.UI.ListSelectorLine or can be used a predefined component: OB.UI.FilterSelectorRenderLine.

You need implement a component to show and filter data. This component must have a OB.UI.ScrollableTable with renderHeader and renderLine pointing to previous defined components.

If you want this selector can be used as selector from other selector, you must send the event onChangeFilterSelector when a datarow is selected. This event must have the following parameters:

 
{
   selector: {
     name: ''    // Name of filter (target arguments for caller),
     value: ''   // Identifier of selected item,
     text: ''    // Name of selected item
   }
}
 
enyo.kind({
  name: 'Example.UI.List',
  classes: 'row-fluid',
  handlers: {
    onSearchAction: 'searchAction',
    onClearFilterSelector: 'clearAction'
  },
  events: {
    onChangeFilterSelector: ''
  },
  components: [{
    classes: 'span12',
    components: [{
      style: 'border-bottom: 1px solid #cccccc;',
      classes: 'row-fluid',
      components: [{
        classes: 'span12',
        components: [{
          name: 'exampleTable',
          kind: 'OB.UI.ScrollableTable',
          classes: 'bp-scroller',
          scrollAreaMaxHeight: '400px',
          renderHeader: 'Example.UI.ModalScrollableHeader',
          renderLine: 'OB.UI.FilterSelectorRenderLine',
          renderEmpty: 'OB.UI.RenderEmpty'
        }, {
          name: 'renderLoading',
          style: 'border-bottom: 1px solid #cccccc; padding: 20px; text-align: center; font-weight: bold; font-size: 30px; color: #cccccc',
          showing: false,
          initComponents: function () {
            this.setContent(OB.I18N.getLabel('OBPOS_LblLoading'));
          }
        }]
      }]
    }]
  }],
  clearAction: function (inSender, inEvent) {
    this.itemsList.reset();
    return true;
  },
  searchAction: function (inSender, inEvent) {
    // Write your search code here
    return true;
  },
  itemsList: null,
  init: function (model) {
    var me = this;
    this.itemsList = new Backbone.Collection();
    this.$.exampleTable.setCollection(this.bpsList);
    this.itemsList.on('click', function (model) {
      me.doChangeFilterSelector({
        selector: {
          name: me.target.substring('filterSelectorButton_'.length),
          value: bp.get('id'),
          text: bp.get('_identifier')
        }
      });
    }, this);
  }
});

This component must be implement handlers for the following events:

 
inEvent = {
  advanced: true,
  filters: [
    {
       operator: 'contains',
       column: 'locCity',
       value: 'Pamplona'
    }, {
      operator: '=',
      column: 'deliveryMethod',
      value: 'DeferredCarriedAway',
      caption: 'Deferred carried away'
    }, {
      operator: "=",
      column: "customer",
      value: "63374280D7F64ACFA6C947A428D668AC",
      caption: "Miah Robinson"
    }, {
      operator: 'lessThan',
      column: 'orderedQuantity',
      value: '5'
    }
  ],
  orderby: {
    name: 'city', 
    column: 'locCity',
    serverColumn: 'locCity',
    direction: 'asc'
  }
}

ModalAdvancedFilter

You need implement a Modal Advanced Filter dialog, this dialog must have to be of kind OB.UI.ModalAdvancedFilters and in the constructor call the setFilters method. And register as popup dialog (the name used in register are will be used on other components).

 
enyo.kind({
  kind: 'OB.UI.ModalAdvancedFilters',
  name: 'Example.UI.ModalAdvancedFilter',
  initComponents: function () {
    this.inherited(arguments);
    this.setFilters(OB.Model.Example_OrderFilter.getProperties());
  }
});
 
OB.UI.WindowView.registerPopup('OB.OBPOSPointOfSale.UI.PointOfSale', {
  kind: 'Example.UI.ModalAdvancedFilter',
  name: 'Example_ModalAdvancedFilter'
});

ModalSelector

And finally you define the filter selector to include all functionality working together. This component must be extend OB.UI.ModalSelector kind.

It is mandatory to redefine the following methods:

 
enyo.kind({
  kind: 'OB.UI.ModalSelector',
  name: 'Example.UI.ModalSelector',
  topPosition: '45px',
  style: 'width: 525px',
  i18nHeader: 'Example_LblSelector',
  body: {
    kind: 'Example.UI.List'
  },
  executeOnShow: function () {
    if (!this.initialized) {
      this.inherited(arguments);
      // Preset customer filter to current receipt customer
      var bp = OB.MobileApp.model.receipt.get('bp'),
          column = _.find(OB.Model.Example_OrderFilter.getProperties(), function (prop) {
          return prop.name === 'customer';
        }, this);
      column.preset.id = bp.get('id');
      column.preset.name = bp.get('_identifier');
    }
  },
  getScrollableTable: function () {
    return this.$.body.$.list.$.exampleTable;
  },
  getFilterSelectorTableHeader: function () {
    return this.$.body.$.list.$.exampleTable.$.theader.$.modalScrollableHeader.$.filterSelector;
  },
  getAdvancedFilterBtn: function () {
    return this.$.body.$.list.$.exampleTable.$.theader.$.modalScrollableHeader.$.buttonAdvancedFilter;
  },
  getAdvancedFilterDialog: function () {
    return 'Example_ModalAdvancedFilter';
  }
});
 
OB.UI.WindowView.registerPopup('OB.OBPOSPointOfSale.UI.PointOfSale', {
  kind: 'Example.UI.ModalSelector',
  name: 'Example_ModalSelector'
});

When the advanced filter button is pushed, the Selector Filter dialog must be hidden and the Advanced Filter dialog is shown. After the filter is selected and applied, the Selector Filter must be shown again. This operations may be confused and difficult to control on initialization, closing, reopening, etc. The base component implement some logic to help you to control this situation. But feel free to modify predefined behavior to accomplish your objective and custom functionality.

The base component implement the following events and methods:

Events:

selectorHide to true or the value passed in inEvent.selectorHide

Methods:

Initialize a component and call the method initSelector to link different dialog elements.

 
init: function (model) {
  this.model = model;
  this.initSelector();
}

The method is executed when the dialog is shown and control if open for first time or is reopened because return from Advanced Filter or other dialog.

 
executeOnShow: function () {
  if (!this.initialized) {
    this.selectorHide = false;
    this.initialized = true;
    var filterSelectorTableHeader = this.getFilterSelectorTableHeader();
    if (filterSelectorTableHeader) {
      filterSelectorTableHeader.setAdvancedFilterBtnCaption();
    }
  }
}

The method is executed when the dialog is hidden and control if necessary make a cleanup process or not.

 
executeOnHide: function () {
  if (this.selectorHide) {
    this.selectorHide = false;
  } else {
    this.initialized = false;
    this.doClearAllFilterSelector();
    this.doSetSelectorAdvancedSearch({
      isAdvanced: false
    });
    if (this.scrollableTable) {
      if (!this.scrollableTable.selectedItem) {
        this.doCloseSelector({
          target: this.target
        });
      } else {
        this.scrollableTable.selectedItem = false;
      }
    }
  }
}

Retrieved from "http://wiki.openbravo.com/wiki/How_to_Create_Advanced_filters_components"

This page has been accessed 3,472 times. This page was last modified on 28 February 2019, at 08:19. Content is available under Creative Commons Attribution-ShareAlike 2.5 Spain License.