diff --git a/extension/qfq/qfq/AbstractBuildForm.php b/extension/qfq/qfq/AbstractBuildForm.php
index 73b1b27b330432d43a0179f21663fb8f6d8a2c7c..8f41eb176309a7611b8bc7ec2f8303f3f3c6088a 100644
--- a/extension/qfq/qfq/AbstractBuildForm.php
+++ b/extension/qfq/qfq/AbstractBuildForm.php
@@ -406,8 +406,24 @@ abstract class AbstractBuildForm {
             //In case the current element is a 'RETYPE' element: take the element name of the source FormElement. Needed in the next row to retrieve the default value.
             $name = (isset($formElement[FE_RETYPE_SOURCE_NAME])) ? $formElement[FE_RETYPE_SOURCE_NAME] : $formElement[FE_NAME];
 
-            // If there is a value explicit defined: take it
+            $value = '';
+            Support::setIfNotSet($formElement, FE_VALUE);
+
+            // If is FormElement['value'] explicit defined: take it
+            // There are two options: a) single value, b) array of values (template Group)
+//            if (is_array($formElement[FE_VALUE])) {
+//                // For Templates Groups, the 'value' has to be defined as '{{!SELECT ...' wich returns all selected records in an array.
+//                $idx = isset($formElement[FE_TEMPLATE_GROUP_CURRENT_IDX]) ? $formElement[FE_TEMPLATE_GROUP_CURRENT_IDX] - 1 : 0;
+//                if (isset($formElement[FE_VALUE][$idx]) && is_array($formElement[FE_VALUE][$idx])) {
+//                    $value = current($formElement[FE_VALUE][$idx]);
+//                    if ($value === false) {
+//                        $value = '';
+//                    }
+//                }
+//            } else {
             $value = $formElement[FE_VALUE];
+//            }
+
             if ($value === '') {
                 // Only take the default, if the FE is a real tablecolumn. See #2064
                 if ($this->store->getVar($formElement[FE_NAME], STORE_TABLE_COLUMN_TYPES) !== false) {
@@ -2961,29 +2977,38 @@ EOT;
         }
         $default = $this->store->getStore(STORE_TABLE_DEFAULT); // current defaults
 
+        // evaluate FE_VALUE on all templateGroup FormElements.
+        $maxForeignRecords = $this->templateGroupDoValue();
+
         $lastFilled = 0; // Marker if there is at least one element per copy who is filled.
         $feSpecNativeCopy = array();
-        for ($ii = 1; $ii < $max; $ii++) {
+        for ($ii = 1; $ii <= $max; $ii++) {
 
-            // Per copy, iterate over all templateGroup FormElements
+            // Per copy, iterate over all templateGroup FormElements.
             foreach ($this->feSpecNative as $fe) {
 
                 $columnName = str_replace(FE_TEMPLATE_GROUP_NAME_PATTERN, $ii, $fe[FE_NAME]);
 
                 $fe[FE_LABEL] = str_replace(FE_TEMPLATE_GROUP_NAME_PATTERN, $ii, $fe[FE_LABEL]);
                 $fe[FE_NOTE] = str_replace(FE_TEMPLATE_GROUP_NAME_PATTERN, $ii, $fe[FE_NOTE]);
+                // Column of primary table?
                 if (isset($record[$columnName])) {
                     if ($record[$columnName] != $default[$columnName]) {
-                        $lastFilled = $ii;
+                        $lastFilled = max($ii, $lastFilled);
                     }
+                    $fe[FE_NAME] = $columnName;
+
                 } else {
-                    throw new UserFormException("Not implemented: templateGroup FormElement-columns not found in primary table.", ERROR_NOT_IMPLEMENTED);
+                    $lastFilled = max($maxForeignRecords, $lastFilled);
+                    if (is_array($fe[FE_VALUE]) && isset($fe[FE_VALUE][$ii - 1])) {
+                        $fe[FE_VALUE] = current($fe[FE_VALUE][$ii - 1]); // replace array with current value
+                    }
+//                    $fe[FE_TEMPLATE_GROUP_CURRENT_IDX] = $ii;
                 }
-                $fe[FE_NAME] = $columnName;
                 $feSpecNativeCopy[$ii - 1][] = $fe; // Build array with current copy of templateGroup.
             }
 
-            // Append $htmlDelete on the last element of all copies,, but not the first.
+            // Append $htmlDelete on the last element of all copies, but not the first.
             if ($ii > 1) {
                 // Count defined FormElements in the current templateGroup
                 $last = count($feSpecNativeCopy[$ii - 1]) - 1;
@@ -2999,6 +3024,7 @@ EOT;
 
         $feSpecNativeSave = $this->feSpecNative;
 
+        $lastFilled = min($lastFilled, $max); // It's possible (external records) that there are more fetched values than the maximum allows - skip those.
         $html = '';
         for ($ii = 0; $ii < $lastFilled; $ii++) {
             $this->feSpecNative = $feSpecNativeCopy[$ii];
@@ -3012,6 +3038,31 @@ EOT;
         return $html;
     }
 
+    /**
+     * Evaluate for all FormElements of the current templateGroup the field FE_VALUE.
+     * If the specific FormElement is not a real column of the primary table, than the value is probably a '{{!SELECT ...'
+     * Statement, that one will be fired. Additional the maximum count of all select rows will be determined and returned.
+     *
+     * @return int   max number of records in FormElement[FE_VALUE] over all FormElements.
+     * @throws UserFormException
+     */
+    private function templateGroupDoValue() {
+
+        // Fire 'value' statement
+        $tgMax = 0;
+        foreach ($this->feSpecNative as $key => $arr) {
+            $this->feSpecNative[$key][FE_VALUE] = $this->evaluate->parse($arr[FE_VALUE]);
+
+            if (is_array($this->feSpecNative[$key][FE_VALUE])) {
+                $cnt = count($this->feSpecNative[$key][FE_VALUE]);
+
+                $tgMax = max($cnt, $tgMax);
+            }
+        }
+
+        return $tgMax;
+    }
+
     abstract public function buildRowNative(array $formElement, $htmlElement, $htmlFormElementName);
 
 }
\ No newline at end of file
diff --git a/extension/qfq/qfq/Constants.php b/extension/qfq/qfq/Constants.php
index 92cb305fd9c8519f43d7508ac3e4db16f82f4d29..6b959577c7493d46e3c7d239f679c9487f43dde9 100644
--- a/extension/qfq/qfq/Constants.php
+++ b/extension/qfq/qfq/Constants.php
@@ -50,6 +50,7 @@ const SQL_FORM_ELEMENT_SPECIFIC_CONTAINER = "SELECT *, ? AS 'nestedInFieldSet' F
 const SQL_FORM_ELEMENT_ALL_CONTAINER = "SELECT *, ? AS 'nestedInFieldSet' FROM FormElement AS fe WHERE fe.formId = ? AND fe.deleted = 'no' AND FIND_IN_SET(fe.class, ? ) AND fe.enabled='yes' ORDER BY fe.ord, fe.id";
 const SQL_FORM_ELEMENT_SIMPLE_ALL_CONTAINER = "SELECT fe.id, fe.feIdContainer, fe.name, fe.label, fe.type, fe.checkType, fe.checkPattern, fe.mode, fe.modeSql, fe.parameter, fe.dynamicUpdate FROM FormElement AS fe, Form AS f WHERE f.name = ? AND f.id = fe.formId AND fe.deleted = 'no' AND fe.class = 'native' AND fe.enabled='yes' ORDER BY fe.ord, fe.id";
 const SQL_FORM_ELEMENT_CONTAINER_TEMPLATE_GROUP = "SELECT fe.id, fe.name, fe.label, fe.maxLength, fe.parameter FROM FormElement AS fe, Form AS f WHERE f.name = ? AND f.id = fe.formId AND fe.deleted = 'no' AND fe.class = 'container' AND fe.type='templateGroup' AND fe.enabled='yes' ORDER BY fe.ord, fe.id";
+const SQL_FORM_ELEMENT_TEMPLATE_GROUP = "SELECT * FROM FormElement AS fe WHERE fe.id = ? AND fe.deleted = 'no' AND fe.class = 'container' AND fe.type='templateGroup' AND fe.enabled='yes' ";
 
 // SANITIZE Classifier
 const SANITIZE_ALLOW_ALNUMX = "alnumx";
@@ -635,6 +636,7 @@ const FE_TEMPLATE_GROUP_REMOVE_TEXT = 'tgRemoveText';
 const FE_TEMPLATE_GROUP_CLASS = 'tgClass';
 const FE_TEMPLATE_GROUP_DEFAULT_MAX_LENGTH = 5;
 const FE_TEMPLATE_GROUP_NAME_PATTERN = '%d';
+const FE_TEMPLATE_GROUP_CURRENT_IDX = 'tgCurentIndex';
 const FE_BUTTON_CLASS = 'buttonClass';
 const FE_LDAP_SERVER = F_LDAP_SERVER;
 const FE_LDAP_BASE_DN = F_LDAP_BASE_DN;
diff --git a/extension/qfq/qfq/form/FormAction.php b/extension/qfq/qfq/form/FormAction.php
index 82c340ff428f1e89e8cc493307ec3a4cbb2ca2fc..8b66072a8554dffdf9761ad89ed3d67aab2bddac 100644
--- a/extension/qfq/qfq/form/FormAction.php
+++ b/extension/qfq/qfq/form/FormAction.php
@@ -65,13 +65,16 @@ class FormAction {
      * @throws DbException
      * @throws UserFormException
      */
-    public function elements($recordId, array $feSpecAction, $feTypeList) {
+    public function elements($recordId, array $feSpecAction, $feTypeList, $templateGroupIndex = 0) {
 
         $flagModified = false;
 
         // Iterate over all Action FormElements
         foreach ($feSpecAction as $fe) {
 
+            // Preparation for Log, Debug
+            $this->store->setVar(SYSTEM_FORM_ELEMENT, Logger::formatFormElementName($fe), STORE_SYSTEM);
+
             $fe = HelperFormElement::initActionFormElement($fe);
 
             // Only process FE elements of types listed in $feTypeList. Skip all other
@@ -79,8 +82,25 @@ class FormAction {
                 continue;
             }
 
-            // Preparation for Log, Debug
-            $this->store->setVar(SYSTEM_FORM_ELEMENT, Logger::formatFormElementName($fe), STORE_SYSTEM);
+            // Process templateGroup action elements
+            if (isset($fe[FE_ID_CONTAINER]) && $fe[FE_ID_CONTAINER] > 0) {
+
+                $feTemplateGroup = $this->db->sql(SQL_FORM_ELEMENT_TEMPLATE_GROUP, ROW_REGULAR, [$fe[FE_ID_CONTAINER]]);
+
+                if (count($feTemplateGroup) == 1) {
+                    $fe[FE_ID_CONTAINER] = 0;
+                    for ($ii = 1; $ii < $feTemplateGroup[0][FE_MAX_LENGTH]; $ii++) {
+                        $feNew = OnArray::arrayValueReplace($fe, FE_TEMPLATE_GROUP_NAME_PATTERN, $ii);
+                        if ($this->elements($recordId, [$feNew], $feTypeList, $ii)) {
+                            $flagModified = true;
+                        }
+                    }
+                } else {
+                    // At the moment 'action' elements have to point to a templateGroup - nothing else is defined. Break if there is somethin else
+                    throw new UserFormException("Expect a 'templateGroup' record in FormElement.id=", $fe[FE_ID_CONTAINER], ERROR_RECORD_NOT_FOUND);
+                }
+                continue; // skip to next FormElement
+            }
 
             switch ($fe[FE_TYPE]) {
                 case FE_TYPE_BEFORE_LOAD:
@@ -117,7 +137,7 @@ class FormAction {
 
             $this->validate($fe);
 
-            $this->doSlave($fe, $recordId);
+            $this->doSlave($fe, $recordId, $templateGroupIndex);
 
             $flagModified = true;
         }
@@ -241,14 +261,27 @@ class FormAction {
      * Create the slave record. First try to evaluate a slaveId. Depending if the slaveId > 0 choose `sqlUpdate` or `sqlInsert`
      *
      * @param array $fe
+     * @param int $recordId
+     * @param int $templateGroupIndex
      * @return int
      * @throws CodeException
+     * @throws DbException
      * @throws UserFormException
      */
-    private function doSlave(array $fe, $recordId) {
+    private function doSlave(array $fe, $recordId, $templateGroupIndex) {
 
         // Get the slaveId
         $slaveId = $this->evaluate->parse($fe[FE_SLAVE_ID]);
+        if ($templateGroupIndex > 0) {
+            if (is_array($slaveId)) {
+                // Select the n'th id of the array
+                $slaveId = isset($slaveId[$templateGroupIndex]) ? $slaveId[$templateGroupIndex] : 0;
+            } else {
+                throw new UserFormException("Result not an arry. SQL Statement for 'slaveId' in TemplateGroup should return an array with all 'slaveId's.", ERROR_EXPECTED_ARRAY);
+            }
+        } elseif (is_array($slaveId)) {
+            throw new UserFormException("Result not a single value. SQL Statement for 'slaveId' in should a single value.", ERROR_UNEXPECTED_TYPE);
+        }
 
         if ($slaveId === '' && $fe[FE_NAME] !== '') {
             // if the current action element has the same name as a real master record column: take that value as an id
diff --git a/extension/qfq/qfq/helper/OnArray.php b/extension/qfq/qfq/helper/OnArray.php
index 0d7020128d230f62c539a55ed855ef06352fd18c..b60e6fe32a6276d1ab9d8d05ed4520a853a82c1a 100644
--- a/extension/qfq/qfq/helper/OnArray.php
+++ b/extension/qfq/qfq/helper/OnArray.php
@@ -228,4 +228,21 @@ class OnArray {
         return $new;
     }
 
+    /**
+     * Iterates over an array and replaces all occurences of $search with $replace. Returns the new array.
+     *
+     * @param array $src
+     * @param $search
+     * @param $replace
+     * @return array
+     */
+    public static function arrayValueReplace(array $src, $search, $replace ) {
+        $new = array();
+
+        foreach($src AS $key => $element) {
+            $new[$key] = str_replace($search, $replace, $element);
+        }
+
+        return $new;
+    }
 }
\ No newline at end of file
diff --git a/extension/qfq/tests/phpunit/OnArrayTest.php b/extension/qfq/tests/phpunit/OnArrayTest.php
index f2bc6b44e93d2718bec9dff7a4e216fa16c3bd1e..de04a7ec2a532e1425f6544a6588955396f533b4 100644
--- a/extension/qfq/tests/phpunit/OnArrayTest.php
+++ b/extension/qfq/tests/phpunit/OnArrayTest.php
@@ -120,4 +120,19 @@ class OnArrayTest extends \PHPUnit_Framework_TestCase {
         $this->assertEquals(['a' => 'hello'], OnArray::getArrayItems(['a' => 'hello', 'b' => 'world'], ['a', 'c'], false));
         $this->assertEquals(['a' => 'hello', 'c' => ''], OnArray::getArrayItems(['a' => 'hello', 'b' => 'world'], ['a', 'c'], true));
     }
+
+    public function testArrayValueReplace() {
+        $this->assertEquals(array(), OnArray::arrayValueReplace(array(), '', ''));
+        $this->assertEquals(array(), OnArray::arrayValueReplace(array(), 'a', ''));
+        $this->assertEquals(array(), OnArray::arrayValueReplace(array(), '', 'b'));
+        $this->assertEquals(array(), OnArray::arrayValueReplace(array(), 'a', 'b'));
+
+        $src = ['fruit1' => 'apple', 'fruit2' => 'cherry', 'fruit3' => 'banana'];
+        $this->assertEquals($src, OnArray::arrayValueReplace($src, '', ''));
+        $this->assertEquals($src, OnArray::arrayValueReplace($src, 'Z', ''));
+        $this->assertEquals($src, OnArray::arrayValueReplace($src, 'Z', 'Y'));
+
+        $expected = ['fruit1' => 'Apple', 'fruit2' => 'cherry', 'fruit3' => 'bAnAnA'];
+        $this->assertEquals($expected, OnArray::arrayValueReplace($src, 'a', 'A'));
+    }
 }