<p>Of course it clears all the existing matrix elements if you update an entry. For craft it's like you delete the existing matrix blocks and create a new one. In order to keep all of them you have to send them in the form or create a custom controller to do it.
You can insert all current matrix blocks in hidden fields, so users won't see them but craft will not delete them.</p>

<p>The following code is totally untested (I don't have much time) it is just to show you the direction</p>

<pre><code>{% for block in entry.measurement %}
    &lt;input type="hidden" name="fields[measurement][{{ block.id }}][type]" value="{{ block.getType().handle }}"&gt;
    &lt;input type="hidden" name="fields[measurement][{{ block.id }}][enabled]" value="1"&gt;
    &lt;input type="hidden" name="fields[measurement][{{ block.id }}][fields][length]" value="{{ block.length }}" &gt;
{% endfor %}
</code></pre>

<p>Important note: your new matrix element's should not have the id of the latest+1. Your new matrix elements index should be <code>newX</code> with X = the number of the new element. So if you want to insert 1 new block your index would be <code>new1</code>, your second block would be <code>new2</code></p>

<pre><code>&lt;input type="number" name="fields[measurement][new1][fields][length]"&gt;
</code></pre>

<p>you can inspect the backend form in your cp to get to know the structure craft need. It should look like this:</p>

<pre><code>&lt;!-- existing block --&gt;
&lt;div class="matrixblock" data-id="7" data-type="block"&gt;
    &lt;input type="hidden" name="fields[contentMatrix][7][type]" value="block"&gt;
    &lt;input type="hidden" name="fields[contentMatrix][7][enabled]" value="1"&gt;
    &lt;!-- some fields here --&gt;
&lt;/div&gt;

&lt;!-- new block --&gt;
&lt;div class="matrixblock" data-id="new1" data-type="newBlock" style="opacity: 1;"&gt;
    &lt;input type="hidden" name="fields[contentMatrix][new1][type]" value="newBlock"&gt;
    &lt;input type="hidden" name="fields[contentMatrix][new1][enabled]" value="1"&gt;
    &lt;!-- some fields here --&gt;
&lt;/div&gt;
</code></pre>

<p>If you do't want to render the entire matrix as hidden fields for any reason let me know and I'll provide you a custom controller action to add the matrix block instead of overwriting it</p>

<p><strong>Update</strong><br>
This is your controller action</p>

<pre><code>/**
 * @throws Exception
 */
public function actionSaveEntryMatrix(){
    $this-&gt;requirePostRequest();
    // check for the entries id, throw an exception if there is none (eg user manipulated the form)
    if(!$entryId = craft()-&gt;request-&gt;getParam('entryId')){
        throw new Exception('could not find EntryId');
    }
    if(!$entry = craft()-&gt;elements-&gt;getElementById($entryId)){
        throw new Exception('Could not find entry with id');
    }

    // get all attributes
    $attributes = $entry-&gt;getContent()-&gt;getAttributes();
    $entryData = craft()-&gt;request-&gt;getParam('fields');

    // just in case you want to update other fields of the entry
    if($entryData &amp;&amp; is_array($entryData)){
        foreach ($entryData as $k =&gt; $v){
            if(array_key_exists($k, $attributes)){
                $attributes[$k] = $v;
            }
        }
    }

    // now the fun starts...
    // insert your field Handle of your matrix field here to get the field
    $measurementField = craft()-&gt;fields-&gt;getFieldByHandle('measurement');
    // fetch all available blocktypes for that field
    $blockTypes = craft()-&gt;matrix-&gt;getBlockTypesByFieldId($measurementField-&gt;id, 'handle');

    // get all measurements from post request
    $measurements = craft()-&gt;request-&gt;getParam('measurement');
    // this array will contain all your matrixblocks
    $measurementsBlocks = [];

    // fetch all old/existing matrix blocks
    $criteria = craft()-&gt;elements-&gt;getCriteria(ElementType::MatrixBlock);
    $criteria-&gt;fieldId = $measurementField-&gt;id;
    $criteria-&gt;ownerId = $entry-&gt;id;
    $criteria-&gt;limit = null;
    $criteria-&gt;status = null;
    $criteria-&gt;localeEnabled = null;
    $criteria-&gt;locale = $entry-&gt;locale;
    $oldBlocks = $criteria-&gt;find();

    // Index them by ID
    foreach ($oldBlocks as $oldBlock) {
        $measurementsBlocks[$oldBlock-&gt;id] = $oldBlock;
    }

    // start the new sortOrder
    $sortOrder = count($measurementsBlocks);
    foreach ($measurements as $blockId =&gt; $blockData) {
        $blockType = $blockTypes[$blockData['type']];
        // Is this new a new block or an existing?
        if (strncmp($blockId, 'new', 3) === 0){
            $block = new MatrixBlockModel();
            $block-&gt;fieldId = $measurementField-&gt;id;
            $block-&gt;typeId  = $blockType-&gt;id;
            $block-&gt;ownerId = $entry-&gt;id;
            $block-&gt;locale  = $entry-&gt;locale;

            $isNew = true;
            // Preserve the collapsed state, which the browser can't remember on its own for new blocks
            $block-&gt;collapsed = !empty($blockData['collapsed']);
        }else{
            // if it is an existing block just load it
            $block = $measurementsBlocks[$blockId];
            $isNew = false;
        }

        // get content from Post
        if(isset($blockData['fields'])){
            $block-&gt;setContentFromPost($blockData['fields']);
        }

        // if it is a new block increase the sortOrder and add it to the array
        if($isNew){
            $sortOrder++;
            $block-&gt;sortOrder = $sortOrder;
            $measurementsBlocks[] = $block;
        }else{
            // otherwise just update the array
            $measurementsBlocks[$block-&gt;id] = $block;
        }
    }

    // add the matrix elements + all updated field to the entries content
    $attributes['measurement'] = $measurementsBlocks;
    $entry-&gt;getContent()-&gt;setAttributes($attributes);

    // finally save the entry
    if(craft()-&gt;elements-&gt;saveElement($entry)){
        // redirect to your preferred url
        $this-&gt;redirect(craft()-&gt;request-&gt;getParam('redirect'));
    }else{
        // if there are errors add the entry to the route variables so you can display errors in twig via
        // entry.getErrors()
        craft()-&gt;urlManager-&gt;setRouteVariables(array(
            'entry' =&gt; $entry
        ));
    }
}
</code></pre>

<p>And this will be your form</p>

<pre><code>&lt;form method="post" accept-charset="UTF-8"&gt;
    {{ getCsrfInput() }}
    &lt;!-- change your action value to your one... my plugin has the handle test --&gt;
    &lt;input type="hidden" name="action" value="test/saveEntryMatrix"&gt;
    &lt;!--
        set your redirect value to your needs
        as you said if you want to add a field
        `/{{ entry.url }}/add-data`
        or
        `/{{ entry.url }}/edit-data?id=yourId`
    --&gt;
    &lt;input type="hidden" name="redirect" value="{{ entry.url }}"&gt;
    &lt;input type="hidden" name="sectionId" value="3"&gt;
    &lt;input type="hidden" name="enabled" value="1"&gt;
    &lt;input type="hidden" name="entryId" value="{{ entry.id }}"&gt;

    &lt;!-- in case you want to edit an existing block note: 50 was my id to test things --&gt;
    &lt;input type="hidden" name="measurement[50][type]" value="measurement"&gt;

    &lt;div class="legend"&gt;
        &lt;h2&gt;Tumour Volume&lt;/h2&gt;
        &lt;p&gt;All entries should be submitted in (mm)&lt;/p&gt;
    &lt;/div&gt;
    &lt;div class="fields"&gt;
        &lt;div class="field"&gt;
            &lt;label for=""&gt;Length&lt;/label&gt;
            &lt;input type="number" name="measurement[50][fields][length]"&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;!-- endcase --&gt;

    &lt;!-- in case you want to add a new one --&gt;
    &lt;input type="hidden" name="measurement[new1][type]" value="measurement"&gt;

    &lt;div class="legend"&gt;
        &lt;h2&gt;Tumour Volume&lt;/h2&gt;
        &lt;p&gt;All entries should be submitted in (mm)&lt;/p&gt;
    &lt;/div&gt;
    &lt;div class="fields"&gt;
        &lt;div class="field"&gt;
            &lt;label for=""&gt;Length&lt;/label&gt;
            &lt;input type="number" name="measurement[new1][fields][length]"&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;!-- endcase --&gt;

    &lt;input type="submit" value="Save"&gt;
&lt;/form&gt;
</code></pre>

<p>About the redirect: do you know how craft rooting works?
It seems like you have to make use of the <code>public function registerSiteRoutes()</code> function: in case you don't know how that works, please open another question to keep this one clean or read the documentation</p>

CC BY-SA 3.0
2017-11-11T08:09:56.693Z
Hi Robin - thanks again for responding - I'd ideally not want to add all the matrix entries over again - i'd love to see that controller! Thanks!
Graham Winston
CC BY-SA 3.0
2017-11-11T08:15:13.240Z
Also would this be the same case for editing a specific matrix block?
Graham Winston
CC BY-SA 3.0
2017-11-11T08:19:14.567Z
Yes. The behavior of the default `entries/saveEntry` is fetching all matrix elements from your form, inserting new one + updating existing one and deleting the rest. I'll update my answer with the controller as soon as I can but it could take a few hours, sry for that.
Robin Schambach
CC BY-SA 3.0
2017-11-11T08:25:19.773Z
Thanks Robin - I really appreciate the time you are spending just a few points:

1. I'm trying to build it so that I can add and edit single blocks within the matrix field
2. The form is going to be in a separate URL eg.
(/<rodent-url>/add-data)
(/rodents-url/edit-data?id=<matrix-block-id>)
Graham Winston
CC BY-SA 3.0
2017-11-11T10:42:19.280Z
I updated my answer.. With this function you can add and update as many blocks as you like. When you index it with a current matrix id it is going to be updated, if you insert a `newX` it is going to be inserted. Old matrix blocks won't be deleted. As for the url: you just have to insert the url you wish to be redirected to the `redirect` field.
Robin Schambach
CC BY-SA 3.0
2017-11-11T16:31:16.647Z
Robin I just want to say thank you so much - I've begun to extend your first controller you wrote for me and I'm getting pretty comfortable - I've been using https://github.com/pixelandtonic/Craft-Release/blob/master/app/controllers/EntriesController.php as a terrific resource to help me through!
Graham Winston
CC BY-SA 3.0
2017-11-11T16:49:29.377Z
Glad I could help you. This git repo is a very good resource for learning craft and it is a smart idea to look up in different sources since I didn't include much error handling to not overload the templates.
Robin Schambach
CC BY-SA 3.0
2017-11-11T07:56:46.993Z
2017-11-11T10:39:30.043Z
2017-11-11T10:39:30.043Z
Robin Schambach
<p>I'm trying to post a public entry form in a matrix field. I've added a count so that the block id is unique. However it's just clearing the matrix field and saving a single entry.</p>

<pre><code>{% set matrix = entry.measurement | length %}
{% set count = matrix + 1 %}
{% set matrix_count = 'new' ~ count %}

&lt;form method="post" accept-charset="UTF-8"&gt;
    {{ getCsrfInput() }}
    &lt;input type="hidden" name="action" value="entries/saveEntry"&gt;
    &lt;input type="hidden" name="redirect" value="{{ entry.url }}"&gt;
    &lt;input type="hidden" name="sectionId" value="3"&gt;
    &lt;input type="hidden" name="enabled" value="1"&gt;
    &lt;input type="hidden" name="entryId" value="{{ entry.id }}"&gt;

    &lt;input type="hidden" name="fields[measurement][{{ matrix_count }}][type]" value="measurement"&gt;

    &lt;div class="legend"&gt;
      &lt;h2&gt;Tumour Volume&lt;/h2&gt;
      &lt;p&gt;All entries should be submitted in (mm)&lt;/p&gt;
    &lt;/div&gt;
    &lt;div class="fields"&gt;
      &lt;div class="field"&gt;
        &lt;label for=""&gt;Length&lt;/label&gt;
        &lt;input type="number" name="fields[measurement][{{ matrix_count }}][fields][length]"&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;input type="submit" value="Save"&gt;
&lt;/form&gt;
</code></pre>

<p>Thanks!</p>

<matrix><entry><entry-form>
Matrix Entry form
# Matrix Entry form

(Asked by: username_0 on 2017-11-10)

I'm trying to post a public entry form in a matrix field. I've added a count so that the block id is unique. However it's just clearing the matrix field and saving a single entry.
{% set matrix = entry.measurement | length %}
{% set count = matrix + 1 %}
{% set matrix_count = 'new' ~ count %}


    {{ getCsrfInput() }}
    
    
    
    
    

    

    
      Tumour Volume
      All entries should be submitted in (mm)
    
    
      
        Length
        
      
    

    


Thanks!

**Tags:** matrix, entry, entry-form

---

## 1 answers

### Answer by username_1 on 2017-11-11. Score: 3 | Accepted answer

Of course it clears all the existing matrix elements if you update an entry. For craft it's like you delete the existing matrix blocks and create a new one. In order to keep all of them you have to send them in the form or create a custom controller to do it.
You can insert all current matrix blocks in hidden fields, so users won't see them but craft will not delete them.
The following code is totally untested (I don't have much time) it is just to show you the direction
{% for block in entry.measurement %}
    
    
    
{% endfor %}

Important note: your new matrix element's should not have the id of the latest+1. Your new matrix elements index should be newX with X = the number of the new element. So if you want to insert 1 new block your index would be new1, your second block would be new2


you can inspect the backend form in your cp to get to know the structure craft need. It should look like this:


    
    
    




    
    
    


If you do't want to render the entire matrix as hidden fields for any reason let me know and I'll provide you a custom controller action to add the matrix block instead of overwriting it
Update
This is your controller action
/**
 * @throws Exception
 */
public function actionSaveEntryMatrix(){
    $this->requirePostRequest();
    // check for the entries id, throw an exception if there is none (eg user manipulated the form)
    if(!$entryId = craft()->request->getParam('entryId')){
        throw new Exception('could not find EntryId');
    }
    if(!$entry = craft()->elements->getElementById($entryId)){
        throw new Exception('Could not find entry with id');
    }

    // get all attributes
    $attributes = $entry->getContent()->getAttributes();
    $entryData = craft()->request->getParam('fields');

    // just in case you want to update other fields of the entry
    if($entryData && is_array($entryData)){
        foreach ($entryData as $k => $v){
            if(array_key_exists($k, $attributes)){
                $attributes[$k] = $v;
            }
        }
    }

    // now the fun starts...
    // insert your field Handle of your matrix field here to get the field
    $measurementField = craft()->fields->getFieldByHandle('measurement');
    // fetch all available blocktypes for that field
    $blockTypes = craft()->matrix->getBlockTypesByFieldId($measurementField->id, 'handle');

    // get all measurements from post request
    $measurements = craft()->request->getParam('measurement');
    // this array will contain all your matrixblocks
    $measurementsBlocks = [];

    // fetch all old/existing matrix blocks
    $criteria = craft()->elements->getCriteria(ElementType::MatrixBlock);
    $criteria->fieldId = $measurementField->id;
    $criteria->ownerId = $entry->id;
    $criteria->limit = null;
    $criteria->status = null;
    $criteria->localeEnabled = null;
    $criteria->locale = $entry->locale;
    $oldBlocks = $criteria->find();

    // Index them by ID
    foreach ($oldBlocks as $oldBlock) {
        $measurementsBlocks[$oldBlock->id] = $oldBlock;
    }

    // start the new sortOrder
    $sortOrder = count($measurementsBlocks);
    foreach ($measurements as $blockId => $blockData) {
        $blockType = $blockTypes[$blockData['type']];
        // Is this new a new block or an existing?
        if (strncmp($blockId, 'new', 3) === 0){
            $block = new MatrixBlockModel();
            $block->fieldId = $measurementField->id;
            $block->typeId  = $blockType->id;
            $block->ownerId = $entry->id;
            $block->locale  = $entry->locale;

            $isNew = true;
            // Preserve the collapsed state, which the browser can't remember on its own for new blocks
            $block->collapsed = !empty($blockData['collapsed']);
        }else{
            // if it is an existing block just load it
            $block = $measurementsBlocks[$blockId];
            $isNew = false;
        }

        // get content from Post
        if(isset($blockData['fields'])){
            $block->setContentFromPost($blockData['fields']);
        }

        // if it is a new block increase the sortOrder and add it to the array
        if($isNew){
            $sortOrder++;
            $block->sortOrder = $sortOrder;
            $measurementsBlocks[] = $block;
        }else{
            // otherwise just update the array
            $measurementsBlocks[$block->id] = $block;
        }
    }

    // add the matrix elements + all updated field to the entries content
    $attributes['measurement'] = $measurementsBlocks;
    $entry->getContent()->setAttributes($attributes);

    // finally save the entry
    if(craft()->elements->saveElement($entry)){
        // redirect to your preferred url
        $this->redirect(craft()->request->getParam('redirect'));
    }else{
        // if there are errors add the entry to the route variables so you can display errors in twig via
        // entry.getErrors()
        craft()->urlManager->setRouteVariables(array(
            'entry' => $entry
        ));
    }
}

And this will be your form

    {{ getCsrfInput() }}
    
    
    
    
    
    
    

    
    

    
        Tumour Volume
        All entries should be submitted in (mm)
    
    
        
            Length
            
        
    
    

    
    

    
        Tumour Volume
        All entries should be submitted in (mm)
    
    
        
            Length
            
        
    
    

    


About the redirect: do you know how craft rooting works?
It seems like you have to make use of the public function registerSiteRoutes() function: in case you don't know how that works, please open another question to keep this one clean or read the documentation

> **Comments:**
> **username_0**: Hi Robin - thanks again for responding - I'd ideally not want to add all the matrix entries over again - i'd love to see that controller! Thanks!  
> **username_0**: Also would this be the same case for editing a specific matrix block?  
> **username_1**: Yes. The behavior of the default `entries/saveEntry` is fetching all matrix elements from your form, inserting new one + updating existing one and deleting the rest. I'll update my answer with the controller as soon as I can but it could take a few hours, sry for that.  
> **username_0**: Thanks Robin - I really appreciate the time you are spending just a few points:  1. I'm trying to build it so that I can add and edit single blocks within the matrix field 2. The form is going to be in a separate URL eg. (/<rodent-url>/add-data) (/rodents-url/edit-data?id=<matrix-block-id>)  
> **username_1**: I updated my answer.. With this function you can add and update as many blocks as you like. When you index it with a current matrix id it is going to be updated, if you insert a `newX` it is going to be inserted. Old matrix blocks won't be deleted. As for the url: you just have to insert the url you wish to be redirected to the `redirect` field.  
> **username_0**: Robin I just want to say thank you so much - I've begun to extend your first controller you wrote for me and I'm getting pretty comfortable - I've been using https://github.com/pixelandtonic/Craft-Release/blob/master/app/controllers/EntriesController.php as a terrific resource to help me through!  
> **username_1**: Glad I could help you. This git repo is a very good resource for learning craft and it is a smart idea to look up in different sources since I didn't include much error handling to not overload the templates.  

---

