Form control

Always used with forms. Goerp application handles all pages with one dynamic handler and pages may have multiple forms. When the page is processed by the handler, then all forms and related input models are involved. We need to know the exact model to be sure that after submitting the form POST request, the right model gets processed. This model name should be passed with the postActionEntity input name.

All form control fields:

  • postAction - what action should be applied to the entity, currently there is only one option - delete, if passed then form control should also have postActionIds input included. If postAction is not specified, then by default applied save/update action.
  • postActionIds - entity ID’s separated by comma (,). Those are input parameters for performing changes under specific entities (in most cases deleting them)
  • postActionEntity - defines the model name which is related to the form. Needed only for the save, update and delete options (not needed in query type forms). Supports multiple entities, each of them should be defined in separate input with the same name, check Multi-entity form topic in this section.
  • postActionRedirect - defines the link where to redirect after successful post action (not applied to delete action and to forms with GET method)

Subsections of Form control

Simple actions with form

GET for fetching data based on query criteria

Note

Do not use any form control inputs while submitting the form using GET method (at least for now there is no practical use of form control options in GET requests).

Use GET requests to fetch multiple data for tables using Query model, or to fetch single Input entity (usually just passing its ID) while defining link to the edit form.

Query models always connected with the List models. When defining the List model in your template, GOERP will make request to the related API and fetch data based on the Query parameters.

<form method="get" id="query-form">
  <label for="query-parameter-1">Query parameter 1:</label>
  <input type="text" id="query-parameter-1" name="Api.ModelQuery.Field"
         value="{{ .Data.Api.ModelQuery.Field }}">

  <label for="query-parameter-2">Query parameter 2:</label>
  <input type="text" id="query-parameter-2" name="Api.ModelQuery.AnotherField"
         value="{{ .Data.Api.ModelQuery.AnotherField }}">

  <button type="submit">Find</button>
</form>

<!-- Use List entities to actually apply the query, otherwise Query parameters will be ignored -->
<ul>
  {{ range .Data.Api.ModelList }}
  <li>{{ .Name }}</li>
  {{ end }}
</ul>

POST for create and update actions

Let’s take a look into simple create/update example form:

<form method="post" id="post-form">
  <!-- For saving action need to pass only postActionEntity, which will ensure that you are working with correct model -->
  <input type="hidden" name="postActionEntity" value="ModelInput">

  <!-- Optionally, use redirect option to redirect to the specified page after successful saving -->
  <input type="hidden" name="postActionRedirect" value="https://erply.com/">

  <!-- Next 2 fields are related to actual model parameters -->
  <label for="input-1">Input 1:</label>
  <input type="text" id="input-1" name="Api.ModelInput.Field"
         value="{{ .Data.Api.ModelInput.Field }}">

  <label for="input-2">Input 2:</label>
  <input type="text" id="input-2" name="Api.ModelInput.AnotherField"
         value="{{ .Data.Api.ModelInput.AnotherField }}">

  <button type="submit" id="save">Save</button>
</form> 

Often we need to make reference from the list of rows to the specific entity edit form. In this case pass entity ID from the selected row to the edit link by attaching it to the Input ID (some input models doesn’t have Input suffix, but you can check in data source definitions in editor if model have “write” option):

<!-- Use built-in .Session object to access account related configuration -->
<!-- Use  prefix '$' if linking made inside the range loop, otherwise omit it -->
<a href="/{{ $.Session.ClientCode }}/{{ $.Session.Language.Code }}/example-page?Api.ModelInput.Id={{ .Id }}"
   target="_self" class="table-action-button">
  <i class="button nowrap  button--transparent icon-Edit-Line"></i>
</a>

POST for delete action

Delete actions should be made by following next steps:

  • Form must have method parameter set to POST
  • Inside the form set hidden postAction input to delete
  • Inside the form set hidden postActionIds input to entity IDs (separated by comma) that should be deleted (using custom JS or predefined goerp components)
  • Inside the form set hidden postActionEntity input to the entity name that should be deleted. If it is row in the table, then that entity should have suffix List (e.g. WarehouseDtoList or WarehouseDtoList). If deleting from the single entity edit form, then suffix may be Input or just model name, check data sources definition in the editor for exact model names. Please note, postActionEntity value shouldn’t have API definition, just model name.
<form method="get" id="entity-table-id">
  <input type="hidden" name="postAction" value="delete">
  <input type="hidden" name="postActionIds" value="">
  <input type="hidden" name="postActionEntity" value="ModelList">
  <!-- Add submit button if delete modal not used -->
  <!-- <button type="submit">DELETE</button>-->
</form>

<!-- and then somewhere in the list range -->
<ul>
  {{ range .Data.Api.ModelList }}
  <li>{{ .Name }}</li>
  <!-- If used delete-confirm-partial component, then define next parameters inside the button -->
  <button data-form-id="entity-table-id"
          data-delete-identifier="{{ .Id }}"
          data-post-action-entity="ModelList"
          class="button button--transparent  nowrap table-action-button action-row-red form-delete-button">
    <i class="icon-Trash-Empty-NotFilled"></i>
  </button>
  {{ end }}
</ul>

<!-- As an option, somewhere in the end of the page import delete-confirm-modal from goerp components and use it -->
<!-- to delete one or many entities. Or write your own deletion logic -->
{{ template "delete-confirm-partial" .}}

Multi-entity form

GOERP now supports multiple entities definitions in one form, which allows to save data of many different, unrelated entities at once.

Note

Multi-entity form supports only one postAction type for all scoped entities. For example, it cannot be used to delete one and create another entity at once. Only delete for all related entities OR create/update for all related entities.

Let’s say we need to create warehouse and point of sale records by submitting them in one form, then code would look like this:

<form method="POST">
  
  {{/* Define entity names that should be processed */}}
  <input type="hidden" name="postActionEntity" value="WarehouseInput">
  <input type="hidden" name="postActionEntity" value="PointOfSale">

  {{/* Warehouse input data */}}
  <fieldset>
    <legend>Warehouse:</legend>
    <label for="name-eng">Name eng:</label>
    <input type="text" id="name-eng" name="AccountAdminApi.WarehouseInput.Name.en"
           value="{{ .Data.AccountAdminApi.WarehouseInput.Name.en }}">
    <label for="name-est">Name est:</label>
    <input type="text" id="name-est" name="AccountAdminApi.WarehouseInput.Name.et"
           value="{{ .Data.AccountAdminApi.WarehouseInput.Name.et }}">
  </fieldset>

  {{/* Point of sale input data */}}
  <fieldset>
    <legend>Point of sale:</legend>
    <label for="name-pos">Name:</label>
    <input type="text" id="name-pos" name="AccountAdminApi.PointOfSale.Name"
           value="{{ .Data.AccountAdminApi.PointOfSale.Name }}">
    <label for="name-shop">Shop name:</label>
    <input type="text" id="name-shop" name="AccountAdminApi.PointOfSale.ShopName"
           value="{{ .Data.AccountAdminApi.PointOfSale.ShopName }}">
  </fieldset>
</form>

Bulk-entity form

Some input entities in GOERP may be submitted as a bulk (having multiple records in scope of one form submit), allowing to create or update multiple records at once. Such inputs have array types in data source definition - []string (e.g. ErplyApi.ProductInSupplierPriceList). Also, bulk input fields may be a part of some complex input entities (e.g. ErplyApi.SalesDocumentInput) accepts many Row’s as part of the input.

Warning
  1. Every row in the bulk should always have same order of inputs as others (check samples).
  2. All rows in the bulk should always have same amount of inputs. For example, goerp will fail if one row contains Name and Code and second one have ID, Name and Code. If ID undefined, then pass empty value with an input.

Bulk-entity form sample

<form method="POST">

   {{/* Define entity name that should be processed */}}
   <input type="hidden" name="postActionEntity" value="ProductInSupplierPriceList">

   {{/* Empty row (to add new) */}}
   <fieldset>
      <legend>Create row:</legend>
      <label for="spl-id">Supplier price list ID:</label>
      <input type="text" id="spl-id" 
             name="ErplyApi.ProductInSupplierPriceList.SupplierPriceListID">
      <label for="product-id">Product ID:</label>
      <input type="text" id="product-id" 
             name="ErplyApi.ProductInSupplierPriceList.ProductID">
   </fieldset>

   <h2>Existing rows</h2>
   {{/* Populate existing rows for update */}}
   {{ range $i, $el := .Data.ErplyApi.ProductInSupplierPriceListList }}
   <fieldset>
      <legend>Row {{$i}}:</legend>
      <label for="spl-id-{{$i}}">Supplier price list ID:</label>
      <input type="text" id="spl-id-{{$i}}"
             name="ErplyApi.ProductInSupplierPriceList.SupplierPriceListID"
             value="{{$el.SupplierPriceListID}}">
      <label for="product-id-{{$i}}">Product ID:</label>
      <input type="text" id="product-id-{{$i}}"
             name="ErplyApi.ProductInSupplierPriceList.ProductID"
             value="{{$el.ProductID}}">
   </fieldset>
   {{ end }}
</form>

Subsections of Bulk-entity form

Sales document sample

<!-- Display possible api errors -->
<div>
  {{ range .Data.Errors }}
  <span>{{ . }}</span>
  {{ end }}
</div>

<form method="post">
  <!-- Field used by goErp to state what we want to save -->
  <input type="hidden" name="postActionEntity" value="SalesDocumentInput"/>

  <!-- Need to set the ID of the existing document -->
  <input type="hidden" name="ErplyApi.SalesDocumentInput.ID"
         value="{{ .Data.ErplyApi.SalesDocumentInput.ID }}">

  <table>
    <thead>
    <tr>
      <th>Product ID</th>
      <th>Amount</th>
      <th>Price</th>
    </tr>
    </thead>

    <tbody>
    {{ range $row := .Data.ErplyApi.SalesDocument.Rows }}
    <tr>
      <td>
        <!-- Stable row id is used by erply api to determine existing rows
        the api always replaces all rows so adding a single row means all rows need to be resaved -->
        <input type="hidden" name="ErplyApi.SalesDocumentInput.RowStableRowID"
               value="{{ $row.StableRowID }}">
        <input name="ErplyApi.SalesDocumentInput.RowProductID" value="{{ $row.ProductID }}">
      </td>
      <td><input name="ErplyApi.SalesDocumentInput.RowAmount" value="{{ $row.Amount }}"></td>
      <td><input name="ErplyApi.SalesDocumentInput.RowPrice" value="{{ $row.Price }}"></td>
    </tr>
    {{ end }}
    <tr>
      <td>
        <input type="hidden" name="ErplyApi.SalesDocumentInput.RowStableRowID" value="0">
        <input name="ErplyApi.SalesDocumentInput.RowProductID" value="" placeholder="Product ID">
      </td>
      <td><input name="ErplyApi.SalesDocumentInput.RowAmount" value="0"></td>

      <!-- Manual pricing allowed? -->
      <td><input name="ErplyApi.SalesDocumentInput.RowPrice" value="0"></td>
    </tr>
    </tbody>
  </table>

  <!-- Erply api returns this boolean as a string 0 or 1 for some reason -->
  {{ if eq .Data.ErplyApi.SalesDocument.Confirmed "1" }}
  <h2>Confirmed documents cannot be edited</h2>
  {{ else }}
  <button type="submit">Save</button>
  {{ end }}
</form>