↓ Skip to main content
  1. Work Notes/
  2. E9 Ecode/

Control Detail Row Count by Main Field

·528 words·3 mins· ·
Ecology E9 Ecode Code Block Detail Table WfForm
Author
molefool
Table of Contents

Purpose
#

Use a numeric main-form field to control the row count of a detail table automatically.

In this snippet:

  • field54450 is the main-form control field.
  • detail_2 is detail table 2.
  • Empty or invalid control values do not change the detail table.
  • A control value of 0 deletes all rows in detail table 2.
  • If users manually add or delete rows in detail table 2, the snippet syncs the row count again after a short delay.

Code
#

<script>
(function () {
  'use strict';

  var CONTROL_FIELD = 'field54450'; // Main-form control field
  var DETAIL_MARK = 'detail_2';     // Detail table 2
  var LOG_PREFIX = '[Detail 2 Row Count Control]';

  var syncing = false;

  function isEmpty(value) {
    return value === undefined || value === null || String(value).trim() === '';
  }

  function parseTargetCount(value) {
    if (isEmpty(value)) {
      return null; // Empty values do not control the detail table
    }

    var count = parseInt(String(value).trim(), 10);

    if (isNaN(count)) {
      console.warn(LOG_PREFIX, 'Control field is not a valid number, skipped:', value);
      return null;
    }

    // Control from 0; negative values are treated as 0
    return Math.max(0, count);
  }

  function getDetailRowIndexes() {
    var rowIndexStr = WfForm.getDetailAllRowIndexStr(DETAIL_MARK) || '';

    if (rowIndexStr === '') {
      return [];
    }

    return rowIndexStr.split(',').filter(function (rowIndex) {
      return rowIndex !== '';
    });
  }

  function syncDetailRows(triggerSource) {
    if (syncing) {
      return;
    }

    var controlValue = WfForm.getFieldValue(CONTROL_FIELD);
    var targetCount = parseTargetCount(controlValue);

    if (targetCount === null) {
      console.log(LOG_PREFIX, triggerSource + ', empty or invalid value, row count not controlled', controlValue);
      return;
    }

    syncing = true;

    try {
      var rowIndexes = getDetailRowIndexes();
      var currentCount = rowIndexes.length;

      console.log(LOG_PREFIX, triggerSource + ', start syncing', {
        controlValue: controlValue,
        targetCount: targetCount,
        currentCount: currentCount,
        rowIndexes: rowIndexes
      });

      if (currentCount < targetCount) {
        for (var i = 0; i < targetCount - currentCount; i += 1) {
          WfForm.addDetailRow(DETAIL_MARK, {});
        }
      }

      if (currentCount > targetCount) {
        var deleteCount = currentCount - targetCount;
        var deleteRows = rowIndexes.slice(targetCount).reverse();

        for (var j = 0; j < deleteCount; j += 1) {
          WfForm.delDetailRow(DETAIL_MARK, deleteRows[j]);
        }
      }

      console.log(LOG_PREFIX, 'Sync finished, target row count: ' + targetCount);
    } catch (error) {
      console.error(LOG_PREFIX, 'Failed to sync detail 2 row count', error);
    } finally {
      window.setTimeout(function () {
        syncing = false;
      }, 300);
    }
  }

  jQuery(document).ready(function () {
    // Run once 1 second after page load
    window.setTimeout(function () {
      syncDetailRows('1 second after page load');
    }, 1000);

    // Sync when the main-form field changes
    WfForm.bindFieldChangeEvent(CONTROL_FIELD, function () {
      syncDetailRows('field54450 changed');
    });

    // Resync after manual row changes so the detail table stays aligned with the control field
    if (WfForm.ACTION_ADDROW && WfForm.registerAction) {
      WfForm.registerAction(WfForm.ACTION_ADDROW + '2', function () {
        window.setTimeout(function () {
          syncDetailRows('detail 2 manually added row');
        }, 300);
      });
    }

    if (WfForm.ACTION_DELROW && WfForm.registerAction) {
      WfForm.registerAction(WfForm.ACTION_DELROW + '2', function () {
        window.setTimeout(function () {
          syncDetailRows('detail 2 manually deleted row');
        }, 300);
      });
    }
  });
})();
</script>

What to Change
#

  • To change the main-form control field, update CONTROL_FIELD.
  • To change the target detail table, update DETAIL_MARK.
  • If the target is not detail table 2, also change the number in ACTION_ADDROW + '2' and ACTION_DELROW + '2' to the corresponding detail-table index.
  • If a control value of 0 should not clear the detail table, change parseTargetCount so values below 1 return 1.

Related