Brittany Layne Rapheal
Brittany Layne Rapheal

Reputation: 752

Handling multiple dynamic forms (not inputs) in one view - Laravel

I have a page with a form that has dynamic inputs, where the user can add and "remove" lines. (By "removes," I mean that it removes from the front end but doesn't actually remove from the database.) The functionality works, as far as updating existing rows and adding new rows. The problem I'm having is with deleting rows.

I'd like to have a modal popup that confirms that they want to delete the row before it deletes it. My first thought was to loop through the existing rows and create a corresponding modal per row with a form, but I'm stuck on setting up the controller to recognize which form/row it's looking to delete - so to recap there's going to be one form with dynamic fields (this is the one that works right now), and there's going to be multiple dynamic forms for deleting rows.

Here's my HTML:

<form action="{{route('preliminary-children.updateChildren')}}" method="POST">
    @csrf
    <!-- Content Row -->
    <div class="row" id="childInfo">
        <!-- About Process -->
        <div class="col-xl-12 col-lg-12">
            <div class="card shadow mb-4">
                <!-- Card Header - Dropdown -->
                <div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
                    <h6 class="m-0 font-weight-bold text-secondary">Family Information - Children</h6>
                </div>

                <div id="dynamic_field"> 
                    @foreach($children as $i => $child)
                    <div class="card-body" id="row{{$i+1}}">
                        @if ($i != 0)
                        <hr/> 
                        <div class="text-right px-2 my-2 child-{{$i+1}}"> 
                            <a href="#" class="text-decoration-none" data-toggle="modal" data-target="#remove{{$i+1}}">
                                <button type="button" class="px-0 btn btn-circle btn-danger"> 
                                    <i class="fal fa-times"></i> 
                                </button> 
                            </a>
                        </div>
                        <div class="modal fade" id="remove{{$i+1}}" tabindex="-1" role="dialog" aria-labelledby="label{{$i+1}}" aria-hidden="true">
                            <div class="modal-dialog" role="document">
                                <div class="modal-content">
                                    <div class="modal-header">
                                        <h5 class="modal-title" id="label{{$i+1}}">Delete Row</h5>
                                        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
                                            <span aria-hidden="true">×</span>
                                        </button>
                                    </div>
                                    <div class="modal-body">Are you sure you want to remove this row?</div>
                                    <div class="modal-footer">
                                        <button class="btn bg-gray-300" type="button" data-dismiss="modal">Cancel</button>
                                        <form id="remove-form{{$i+1}}" name="formrow[]" action="{{route('preliminary-children.updateChildren')}}" method="POST" class="d-inline-block">
                                            <input type="text" name="removeID[]" id="removeID{{$i+1}}" value="{{$child->id}}" hidden="hidden">
                                            <button type="submit" id="{{$i+1}}" name="removerow[]" class="btn btn-danger text-decoration-none btn_remove">Remove</button>
                                        </form>
                                    </div>
                                </div>
                            </div>
                        </div>
                        @endif

                        <input type="text" name="userID[]" id="userID{{$i+1}}" value="{{ $user->id }}" hidden="hidden"> 
                        <input type="text" name="ID[]" id="childID{{$i+1}}" value="{{$child->id}}" hidden="hidden">
                        <input type="text" name="rel[]" id="rel{{$i+1}}" value="child" hidden="hidden"> 

                        <div class="form-row"> 
                            <div class="form-group col-md-6"> 
                                <label for="first">First Name</label> 
                                <input name="first[]" type="text" class="form-control" id="first{{$i+1}}" value="{{$child->first_name}}" placeholder="First Name"> 
                            </div> 
                            <div class="form-group col-md-6"> 
                                <label for="last">Last Name</label> 
                                <input name="last[]" type="text" class="form-control" id="last{{$i+1}}" value="{{$child->last_name}}" placeholder="Last Name"> 
                            </div> 
                        </div> 
                        <div class="form-row"> 
                            <div class="form-group col-md-6"> 
                                <label for="inputSSN">SSN</label> 
                                <input data-inputmask="'mask': '999-99-9999'" value="{{$child->ssn}}" type="text" class="form-control" name="inputSSN[]" id="SSN{{$i+1}}" placeholder="SSN"> 
                            </div> 
                            <div class="form-group col-md-6"> 
                                <label for="dob">Date of Birth</label> 
                                <input data-inputmask="'mask': '99/99/9999'" type="datepicker" value="{{$child->dob}}" class="form-control" name="dob[]" id="do{{$i+1}}B" placeholder="Date of Birth"> 
                            </div> 
                        </div> 
                        <div class="form-row"> 
                            <div class="form-group col-md"> 
                                <label for="inputGender">Gender</label> 
                                <br/> 
                                <select class="form-control d-inline-block w-25 mr-1" name="inputGender[]" id="Gender{{$i+1}}" placeholder="Gender"> 
                                    @foreach($genders as $gender)
                                    <option value="{{$gender}}" @if($child){{ ($child->gender == $gender) ? 'selected' : ''}} @endif>{{$gender}}</option>
                                    @endforeach
                                </select> 
                            </div> 
                            <div class="form-group col-md"> 
                                <label for="primaryHeight">Height</label> 
                                <br/> 
                                <select class="form-control d-inline-block w-25 mr-1" name="primaryFeet[]" id="primaryFeet{{$i+1}}"> 
                                    @foreach($feet as $foot)
                                    <option value="{{$foot}}" @if($child){{($child->height_feet == $foot) ? 'selected' : ''}} @endif>{{$foot}}</option>
                                    @endforeach
                                </select> 
                                <span class="d-inline-block w-10 mr-3">ft</span> 
                                <select class="form-control d-inline-block w-25 mr-1" name="primaryInches[]" id="primaryInches{{$i+1}}"> 
                                    @foreach($inches as $inch)
                                    <option value="{{$inch}}" @if($child){{($child->height_inch == $inch) ? 'selected' : ''}} @endif>{{$inch}}</option>
                                    @endforeach
                                </select> 
                                <span class="d-inline-block w-10">in</span> 
                            </div> 
                            <div class="form-group col-md"> 
                                <label for="primaryWeight">Weight (lbs)</label> 
                                <br/> 
                                <input type="number" min="0" step=".1" class="form-control d-inline-block w-75 mr-1" id="primaryWeight{{$i+1}}" value="{{$child->weight_lbs}}" name="primaryWeight[]" placeholder="Weight (lbs)"> 
                                <span class="d-inline-block w-10">lbs</span> 
                            </div> 
                        </div> 
                    </div>  
                    @endforeach
                </div>
                <hr/>
                <div class="text-center my-4">
                    <button type="button" name="add" id="add" class="btn btn-success">Add More</button>
                </div>
            </div>
        </div>
    </div>

    <div class="form-row mb-4 text-center">
        <div class="form-group col-md-12 mt-4">
            <a href="{{ route('preliminary-spouse') }}" class="btn bg-gray-300">Go Back</a> <button type="submit" name="savecontinue" class="btn btn-info">Save and Continue</button>
        </div>
    </div>

</form>

And here's my controller:

public function updateChildren(Request $request) 
    {
            $id = Auth::user()->id;
            $user = Auth::user();
            $family = UserFamily::where(['user_id'=> $id, 'rel' => 'child'])->get();
            $count = count($family);
            $children = ($count > 0 ? $family : '');

            $input = $request->all();
                $rules = [
                    'first[*]' => 'required',
                    'userID[*]' => 'required',
                    'rel[*]' => 'required',
                    'first[*]' => 'required',
                    'last[*]' => 'required',
                    'inputSSN[*]' => 'required',
                    'dob[*]' => 'required',
                    'inputGender[*]' => 'required',
                    'primaryFeet[*]' => 'required',
                    'primaryInches[*]' => 'required',
                    'primaryWeight[*]' => 'required',
                ];

                $validator = Validator::make($request->all(), $rules);

                if ($validator->passes()) {

                        foreach($input['userID'] as $index => $value) {

                            $feet = $input['primaryFeet'][$index];
                            $inch = $input['primaryInches'][$index];
                            $weight = $input['primaryWeight'][$index];
                            $inches = ($feet * 12) + $inch;

                           $bmi = number_format(((703 * $weight) / ($inches * $inches)), 2, '.', ''); 

                           if(isset($input['ID'][$index])){
                            $famid = $input['ID'][$index];
                           }else {
                            $famid = '';
                           }

                           if($famid > 0 || $famid != '') {
                             $user = UserFamily::firstOrNew(['user_id'=> $id, 'rel' => 'child', 'id' => $famid]);
                           }else{
                            $user = UserFamily::create(['user_id'=> $id, 'rel' => 'child']);
                           }

                           $user->user_id = $id;
                           $user->bmi = $bmi;
                           $user->first_name = $input['first'][$index];
                           $user->dob = $input['dob'][$index];
                           $user->last_name = $input['last'][$index];
                           $user->rel = $input['rel'][$index];
                           $user->ssn = $input['inputSSN'][$index];
                           $user->gender = $input['inputGender'][$index];
                           $user->height_feet = $input['primaryFeet'][$index];
                           $user->height_inch = $input['primaryInches'][$index];
                           $user->weight_lbs = $input['primaryWeight'][$index];
                           $user->save();
                       }

                       return redirect()->route('preliminary-review');

                     }

                return redirect()->route('preliminary-children')->withErrors($validator);
    }

The only thing I've tried is setting up an if/else if($request->has('savecontinue'){ ... } and wrapping my existing controller in that. The else{} would handle all the modals, but it kept kicking back errors as if all my syntax was incorrect.

Thoughts? I'm also not opposed to approaching this differently if there's a better way.

PS, there's JS for the remove and add buttons, but I didn't think it was necessary for this question. If you need me to update this with it, I can. :)

Upvotes: 1

Views: 333

Answers (1)

miken32
miken32

Reputation: 42683

Deleting a child is a different operation than updating a child, so you should have a different method for it in your controller. Not sure about how you've got anything named, but this should give you an idea.

Define a new route:

Route::delete('/whatever/{child}', [ChildController::class, 'deleteChild'])
    ->name('preliminary-children.deleteChild');

Note we'll use the delete HTTP method to access this route, and the ID is passed as part of the URL.

Update your view to point to this new route:

<div class="modal-dialog" role="document">
    <div class="modal-content">
        <div class="modal-header">
            <h5 class="modal-title" id="label{{$i+1}}">Delete Row</h5>
            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
                <span aria-hidden="true">×</span>
            </button>
        </div>
        <div class="modal-body">Are you sure you want to remove this row?</div>
        <div class="modal-footer">
            <button class="btn bg-gray-300" type="button" data-dismiss="modal">Cancel</button>
            <form id="remove-form{{$i+1}}" name="formrow[]" action="{{route('preliminary-children.deleteChild', $child->id)}}" method="POST" class="d-inline-block">
                <input name="_method" value="DELETE" type="hidden"/>
                <button type="submit" id="{{$i+1}}" name="removerow[]" class="btn btn-danger text-decoration-none btn_remove">Remove</button>
            </form>
        </div>
    </div>
</div>

A web browser can't send a delete request, so we spoof the method with a hidden input.

And then we make the method:

public function deleteChild(UserFamily $child)
{
    $child->delete();
    return response()->json("success");
}

By type hinting the parameter, Laravel automatically looks up the relevant record in the database for you. Of course you'll want to do some error checking there too.

Upvotes: 1

Related Questions