1
votes

I've implemented an extend form function that also generates unique field names as a form is cloned.

Because of how the js works, the field names in the extend form base (#readroot) are not Cake-compatible until the script is run and corrects them.

Names in base: age, grade, school
What it looks like after js is run:

data[Student][1][age]

data[Student][1][grade]

data[Student][1][school]

So I expect $this->request->data would receive an array like this:

Array ( 
[Post] => Array ( 
    [title] => Mr 
    [contact_person] => Sam 
    [home_tel] => 1234567 
    [mobile] => 1234567 
    [email] => [email protected] 
    [relationship] => family 
    [frequency] => once per week 
    [duration] => 1hr 
    [user_id] => 1 
) 
[Student] => Array ( 
    [0] => Array ( 
        [age] => 10
        [grade] => 1 
        [gender] => 1
        [school] => ABC
    ) 
    // This is where the extend form starts.
    [1] => Array (
        [age] => 11
        [grade] => 2
        [gender] => 0
        [school] => ABC2
    )
)
)

However, $this->request->data reads this:

Array ( 
[age] => 11
[grade] => 2 
[gender] => 0
[school] => ABC2 
[Post] => Array ( 
    [title] => Mr 
    [contact_person] => Sam
    [home_tel] => 1234567 
    [mobile] => 1234567 
    [email] => [email protected] 
    [relationship] => family 
    [frequency] => once per week
    [duration] => 1hr 
    [user_id] => 1 
) 
[Student] => Array ( 
    [0] => Array ( 
        [age] => 10 
        [grade] => 1 
        [gender] => 1
        [school] => ABC 
    ) 
) )

It appears it reads the field names prior to the change. I'm new to Javascript and hopefully someone can save me...

The simplified version of the form html and javascript:

<?php 
echo $this->Form->create('Post');
echo $this->Form->input('title');
echo $this->Form->input('contact_person');
echo $this->Form->input('home_tel');
echo $this->Form->input('mobile');
echo $this->Form->input('email'); 
echo $this->Form->input('relationship'); 
echo $this->Form->input('Student.0.age');       
echo $this->Form->input('Student.0.grade');         
echo $this->Form->input('Student.0.school'); 
?>
<!-- Extend Form Reference -->
<span id="readroot" style="display: none">
    <input class="btn btn-default" type="button" value="Remove review" onclick="this.parentNode.parentNode.removeChild(this.parentNode);" /><br /><br />
    <?php 
    echo $this->Form->input('Student.1.age', array(
        'name' => 'age',
    ); 
    echo $this->Form->input('Student.1.grade', array(
        'name' => 'grade',
        'options' => array(
            '1' => __('Grade 1'),   
            '2' => __('Grade 2')
        )
    )); 
    echo $this->Form->input('Student.1.school', array(
        'name' => 'school'
    )); 
    ?>
</span>
<!-- Extend Form Reference End-->
<span id="writeroot"></span>
<input class="btn btn-default" type="button" onclick="moreFields()" value="Give me more fields!" />
<script>
    var counter = 1;
    function moreFields() {
        counter++;
        var newField = document.getElementById('readroot').cloneNode(true);
        newField.id = '';
        newField.style.display = 'block';
        var newFields = newField.querySelectorAll('[name]');
            for (var i=0;i<newFields.length;i++) {
                var theNames = newFields[i].name
                if (theNames)
                    newFields[i].name = "data[Student][" + counter + "][" + theNames + "]";

        }
        var insertHere = document.getElementById('writeroot');
        insertHere.parentNode.insertBefore(newField,insertHere);
    }
    //window.onload = moreFields;
</script>
<?php echo $this->Form->end(); ?>
2

2 Answers

0
votes

Since I managed to make it work, not in a elegant way though, I post it as an answer.

    public function add() {
    if ($this->request->is('post')) {
        $this->Post->create();
        $this->request->data['Post']['user_id'] = AuthComponent::user('id');
        unset($this->Post->Student->validate['post_id']);
        $a = $this->request->data;
        $b = array_splice($a, 4);
        if ($this->Post->saveAssociated($b)) {
            $this->Session->setFlash(__('The post has been saved.'), 'alert_box', array('class' => 'alert-success'));
            return $this->redirect(array('action' => 'index'));
        } else {
            $this->Session->setFlash(__('The post could not be saved. Please, try again.'), 'alert_box', array('class' => 'alert-danger'));
        }
    }
    $users = $this->Post->User->find('list', array('order' => array('User.id' => 'asc')));
    $subjects = $this->Post->Subject->find('list');
    $this->set(compact('users', 'subjects'));
    }

There are 4 values up front whereas the rest of the array is exactly how I wanted, I basically just cut it off and pass the rest to save..

0
votes

Well because you override the data attribute with something else other than Student.1.grade (in your case, grade).

That's why Cake form helper is adding it to the root of the array instead of the School key.

Your code should look like:

echo $this->Form->input('Student.1.grade', array(
    'name' => 'Student.1.grade',
    'options' => array(
        '1' => __('Grade 1'),   
        '2' => __('Grade 2')
    )
)); 

OR

echo $this->Form->input('Student.1.grade', array(
    'options' => array(
        '1' => __('Grade 1'),   
        '2' => __('Grade 2')
    )
));