Skip to content
Niko edited this page Jan 15, 2024 · 17 revisions

A collection can contain either primitives (i.e. String, Number) or whole object structures. These have to be handled in the ui and the data structures.

A collection needs two tags: a wrapper with the collection marker, and a container that is used as template.

<div class="collection" data-field="data.links"> <!-- the wrapper -->
	<div> <!--the container -->
		... stuff to be repeated for each element of the collection ...
		<input name="links.name"/>
	</div>
</div>

<div class="collection" data-field="data.simplearray"> <!-- the wrapper for a simple array field -->
	<div>
		<span class="field">simplearray.$idx</span>
		<input name="simplearray."/> <!-- since there are no "fields" in a simple type - just reference without a real name (stop at .) -->
	</div>
</div>

Note: it does not matter what kind of tags are used for wrapper/container. It can be ul/li, tbody/tr, div/span.

IMPORTANT: If you want to get data edited within a collection you must make sure that there is only ONE DIRECT CHILD after the collection, otherwise JsForm cannot generate the correct object structure.

Collection Sorting

attributes Description
data-sort die name of the field to use for sorting
data-sorttype the type. default is Number [number,alpha,alphainsensitiv]
data-sortdesc add this tosort descending instead of ascending
<div class="collection sort" data-field="data.groups" data-sort="priority" data-sorttype="number">
<fieldset>
	<legend>Group: <span class="field">groups.name</span></legend>
</fieldset>
</div>

Note: you can have controls to change the sorting. These work only if sorttype=Number and if it is sorted ascending because it will automatically overwrite the given sort-field with an ascending position value (1st element=0)

Special fieldnames

You can show the "index" of each entry within a collection by using [nameOfCollection].$idx:

<div class="collection sort" data-field="data.groups">
     <div>Group <span class="field">groups.$idx</span>: <span class="field">groups.name</span></div>
</div>

Collection Editing

You can add simple controls for modifying the collection (adding/removing elements). This is accomplished by adding specific classes to tags within the collection:

<table>
<tbody class="collection" data-field="data.links"> <!-- the wrapper -->
	<tr> <!--the container -->
		<td><input name="links.href"/></td>
		<td><span class="ui-icon ui-icon-trash delete"></span></td> <!-- class="delete" this control will delete the row -->
	</tr>
</tbody>
</table>
<span class="ui-icon ui-icon-plusthick add" data-field="data.links"></span> <!-- class="add" this control will create a new empty row -->

If you omit the "tbody" and add the collection directly in the table, it will not work in i.e. firefox, because firefox automatically adds the tbody element!

Initial Values

you might want to have initial values to prefilll a new collection entry. To do this you can set the data-prefill attribute:

...
	<tbody class="collection" data-field="data.tasks" data-prefill='{"state":"open"}'>
...

You can also use javascript to set the prefill data attribute or even have a function call:

	<tbody class="collection" data-field="data.tasks" id="taskCollection">
$("#taskCollection").data().prefill = function(obj, $line) {
	obj.state = 'open';
	obj.dueDate = new Date().getTime() + 24*3600*1000;  // close by tomorrow
}

This also allows modifying the data element or loading a completely different one.

Collection Controls

  • class="delete": any element with this class within the container will get a click event that removes the current element.
  • class="add" data-field="data.collection": any element OUTSIDE of the wrapper with the class add will act as a trigger for adding a new element
  • class="sortUp": only available in sortable collection with type=number. This will move the current entry up.
  • class="sortDown": only available in sortable collection with type=number. This will move the current entry down.
$(".collection").on("deleteCollection", function(ev, line, data) {
	// additional code when removing an element in the collection
	alert("deleted: " + data.href);
});

$(".collection").on("addCollection", function(ev, line, data) {
   // additional code when add an element to the collection, i.e. init the data
   data.href = "http://www.example.com";
   data.name = "unknown";
   $(line).find("input[name='title']").autcomplete();
});

$(".collection").on("postAddCollection", function(ev, line, data) {
   // do something after an element has been rendered
   $(line).find("input[name='title']").focus();
});

Edit collection sorting

You can use drag'n drop using http://jqueryui.com/sortable/ . To enable this simply add "sortable" to the collection element:

<div class="collection sort sortable" data-field="data.groups" data-sort="priority" 
     data-sortable='{"placeholder":"ui-state-highlight"}'>
<fieldset>
	<legend>Group: <span class="field">groups.name</span></legend>
</fieldset>
</div>

Note: The options for the sortable control will be read from the "data-sortable" attribute. see JqueryUI#sortable. The options must be json!!!

Here an example with a handle:

<ul class="collection sort sortable" data-field="data.groups" data-sort="priority" 
     data-sortable='{"placeholder":"ui-state-highlight", "handle":".handle"}'>
   <li>
       <span class="action ui-icon ui-icon-arrowthick-2-n-s handle "></span>
	Group: <span class="field">groups.name</span>
   </li>
</ul>

collection events

triggered from the collection

There are a few events you can bind on in the collection.

  • addCollection: data is not yet filled with anything (allows to edit either the dom or data object)
  • postAddCollection: after the data is appended and filled
  • deleteCollection: when an element is removed

Note: The event is not triggered on the form, but rather on the actual class="collection" entity.

$(".collection", $detail).on("postAddCollection", function(ev, line, data){
   alert("added new collection");
});

refreshed

This is called after the data within a collection is filled. This event is part of each row so it should be created in the postAddcollection event

$(".collection", $detail).on("postAddCollection", function(ev, line, data){
   $(line).on("refreshed", (_ev, line, pojo) {
      alert("refreshed");
   });
});

trigger the collection

These allow custom controls to be used to execute common functions. Note that the events described above will be triggered in combination as well.

add

Creates a new row.

This has to be triggered on the element with the "collection" class (the display list).

  $("#mycollection").trigger("add");
  $("#mycollection").trigger("add", [{id:12, name: "asdf"]);

You can pass an object to the trigger which will be used to fill the new "row".

Note: you need to create an array to add a data element (it's handled internally as an array of parameter) the input requires the data-field attribute to know where to insert the new entry to

insert

Creates a new row AND fills it with the given data. This has to be triggered on the input field with the "insert" class not the list.

  $("#someinput").trigger("insert", [{type:"test", value:123}] );

Note: you need to create an array to add a data element (it's handled internally as an array of parameter) the input requires the data-field attribute to know where to insert the new entry to

delete

Delete a given row. This must be triggered on the "entry" element underneath the collection (i.e. the tr under tbody):

  $("#mycollection tr.selected").trigger("delete");

refresh

Refreshes/repaints the entry. This must be triggered on the "line" and will use the data().pojo of this element to repaint:

  $("#mycollection tr.selected").data().pojo = { name: "new name" };
  $("#mycollection tr.selected").trigger("refresh");

Note: postAddCollection is not triggered by a refresh.

sort

Sort a given row. This must be triggered on the "entry" element underneath the collection (i.e. the tr under tbody):

  $("#mycollection tr.selected").trigger("sortUp");
  $("#mycollection tr.selected").trigger("sortDown");

Access to data of a single element

You can access the (original) data object by simply accessing the pojo data-attribute.

  $("#mycollection tr:first").data().pojo

If you want to get the data with updates done via editing in the form you can use "getCollection":

  const firstElement = $("#myForm").jsForm("getCollection", [$("#mycollection tr:first")]);

Note that you need to pass an array with the element as the only entry.

Templates

Collections are handled by taking the content of the "collection" element as a template (sub-)DOM. It is stored away in the container element as "template" data.

You can post-initialisation modify it and all subsequent "adds" will use the new template:

  var template = $("#mycollection").data().template;
  // now access the template as "root" for your dom operations:
  $("span",template).addClass("highlight");