wbraganca / yii2-dynamicform

It is widget to yii2 framework to clone form elements in a nested manner, maintaining accessibility.
Other
436 stars 439 forks source link

Demo 3: Nested Dynamic Form with types of rooms #201

Open fdo36 opened 7 years ago

fdo36 commented 7 years ago

Is it possible to have differents types of rooms in the "demo 3: Nested Dynamic Form" and get the rooms separated by their type? For example, if I wanna create the same as the demo 3 shows and adding a type for each room. I want to have rooms type A, rooms type B and rooms type C. Is it possible? (types are preloaded in the database, the user doesn't have to insert a new type nor select one type. If I want to insert a "room type A", I just add it where it belongs)

I've changed the html but the room's array in the controller didn't has all the rooms (because the first ones are overwritten). So, what do I have to do to make it work fine?

In the picture you can see the approach, I want to make it work because by just editing the html didn't work.

captura

@wbraganca

fdo36 commented 7 years ago

Ok, here is my solution:

  1. Create 2 more clases extended of "Model". So I have 3 clases: Room (ActiveRecord), RoomB (Model), RoomC (Model). So I can representate the 3 types of room.
  2. The attributes of the two "Model" clases, are the "id" and the "description" of the "ActiveRecord" class (remember, we are talking about Room).
  3. In the "_form.php", I've put two "render('_form-rooms')" more, inside divs with class "col-md-4" to get the separation.
<td>
<div class="row">
<div class="col-md-4">
                    <?= $this->render('_form-rooms', [
                        'form' => $form,
                        'indexHouse' => $indexHouse,
                        'modelsRoom' => $modelsRoom[$indexHouse],
                    ]) ?>

<button type="button" class="remove-house btn btn-danger btn-xs"><span class="fa fa-minus"></span></button>
</div>
<div class="col-md-4">
                    <?= $this->render('_form-rooms', [
                        'form' => $form,
                        'indexHouse' => $indexHouse,
                        'modelsRoom' => $modelsRoomB[$indexHouse],
                    ]) ?>

<button type="button" class="remove-house btn btn-danger btn-xs"><span class="fa fa-minus"></span></button>
</div>
<div class="col-md-4">
                    <?= $this->render('_form-rooms', [
                        'form' => $form,
                        'indexHouse' => $indexHouse,
                        'modelsRoom' => $modelsRoomC[$indexHouse],
                    ]) ?>

<button type="button" class="remove-house btn btn-danger btn-xs"><span class="fa fa-minus"></span></button>
</div>
</div>
                </td>
  1. In the "actionCreate", I've made 2 extra arrays representing the 2 "Model" clases, so I have those 3 arrays: $modelsRoom = [[new Room]]; $modelsRoomB = [[new RoomB]]; $modelsRoomC = [[new RoomC]];
  2. I've changed all the logic of the code inside "actionCreate" ad hoc with the two extra arrays, so, for example, in the "isset($_POST['Room'][0][0])", I've asking for "isset($_POST['RoomB'][0][0])" and "isset($_POST['RoomC'][0][0])" as well:

    // validate person and houses models
            $valid = $modelPerson->validate();
            $valid = Model::validateMultiple($modelsHouse) && $valid;
            $valid2 = $valid3 = $valid;
    
            if (isset($_POST['Room'][0][0])) {
                foreach ($_POST['Room'] as $indexHouse => $rooms) {
                    foreach ($rooms as $indexRoom => $room) {
                        $data['Room'] = $room;
                        $modelRoom = new Room;
                        $modelRoom->load($data);
                        $modelsRoom[$indexHouse][$indexRoom] = $modelRoom;
                        $valid = $modelRoom->validate();
                    }
                }
            }
    
            if (isset($_POST['RoomB'][0][0])) {
                foreach ($_POST['RoomB'] as $indexHouse => $rooms) {
                    foreach ($rooms as $indexRoom => $room) {
                        $data['Room'] = $room;
                        $modelRoom = new Room;
                        $modelRoom->load($data);
                        $modelsRoomB[$indexHouse][$indexRoom] = $modelRoom;
                        $valid2 = $modelRoom->validate();
                    }
                }
            }
    
            if (isset($_POST['RoomC'][0][0])) {
                foreach ($_POST['RoomC'] as $indexHouse => $rooms) {
                    foreach ($rooms as $indexRoom => $room) {
                        $data['Room'] = $room;
                        $modelRoom = new Room;
                        $modelRoom->load($data);
                        $modelsRoomC[$indexHouse][$indexRoom] = $modelRoom;
                        $valid3 = $modelRoom->validate();
                    }
                }
            }

so I ask if the 2 extra "valid" variables are true to continue

if ($valid && $valid2 && $valid3) {
                $transaction = Yii::$app->db->beginTransaction();
                try {
                    if ($flag = $modelPerson->save(false)) {
                        foreach ($modelsHouse as $indexHouse => $modelHouse) {

                            if ($flag === false) {
                                break;
                            }

                            ... (continue with the same code)

and, in the render of the form, I've pass as a parameter the extra arrays created:

 return $this->render('create', [
            'modelPerson' => $modelPerson,
            'modelsHouse' => (empty($modelsHouse)) ? [new House] : $modelsHouse,
            'modelsRoom' => (empty($modelsRoom)) ? [[new Room]] : $modelsRoom,
            'modelsRoomB' => (empty($modelsRoomB)) ? [[new RoomB]] : $modelsRoomB,
            'modelsRoomC' => (empty($modelsRoomC)) ? [[new RoomC]] : $modelsRoomC,
        ]);
  1. In the "_form.php" view, you can see the code above, I've used the two extra arrays in the render of the two extra "_form-rooms".

  2. In the "_form-rooms", I've removed the code representing the model's id, because in the "actionUpdate", I've remove all the "Houses", so, all their "rooms" will be deleted too. After this, I've just do the same as in the "actionCreate" (after the post).

I hope you can understand my solution. It maybe not the best solution, but it works for me. There are more details that I've omited to not to extend too much this reply, but you can always contact me ;)

If you need more details, email me.