Integrating a Bootstrap Modal Into Your Laravel Application

  • April 11, 2016

Welcome to the incredibly popular Easy Laravel 5 companion blog. To celebrate the new edition's release (updated for Laravel 5.5!) use the discount code easteregg to receive 20% off the book or book/video package! » Buy the book

I've recently been integrating quite a few Bootstrap modals into a client project. The process is pretty straightforward however can be rather confusing the first few times around and so I thought I'd put together a blog post which outlines the various steps.

A Bootstrap modal is a dialog prompt which can be triggered programmatically or in response to a user-triggered event. This prompt appears above the current page, focusing the user's attention and typically requiring the user to take action before the prompt closes. An example modal is found in the below screenshot.

Opening a modal using Bootstrap's custom jQuery plugin is pretty trivial, accomplished by attaching specific data attributes to an HTML element which serve as cues to the jQuery plugin. When an element associated with the data attributes is clicked, a modal will open. Here is an example of an HTML button which when clicked will open a modal identified by the id favoritesModal:

<button 
   type="button" 
   class="btn btn-primary btn-lg" 
   data-toggle="modal" 
   data-target="#favoritesModal">
  Add to Favorites
</button>

The model DOM is a tad more involved, but you'll quickly come to realize that all Bootstrap modals essentially consist of the same three components: a header, body, and footer. The following example modal produces the same prompt as that depicted in the above screenshot:

<div class="modal fade" id="favoritesModal" 
     tabindex="-1" role="dialog" 
     aria-labelledby="favoritesModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" 
          data-dismiss="modal" 
          aria-label="Close">
          <span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" 
        id="favoritesModalLabel">The Sun Also Rises</h4>
      </div>
      <div class="modal-body">
        <p>
        Please confirm you would like to add 
        <b><span id="fav-title">The Sun Also Rises</span></b> 
        to your favorites list.
        </p>
      </div>
      <div class="modal-footer">
        <button type="button" 
           class="btn btn-default" 
           data-dismiss="modal">Close</button>
        <span class="pull-right">
          <button type="button" class="btn btn-primary">
            Add to Favorites
          </button>
        </span>
      </div>
    </div>
  </div>
</div>

It's at this point where the excellent Bootstrap documentation leaves the reader to sort out more complicated implementations, which brings me to the point of this post.

Passing Dynamic Data Into the Modal

Imagine an application which presents a list of books. The user can click on a button which opens the above modal dialog and confirm he would like to add the book to his favorites list. Logically we're only going to want to embed one dialog template into the page, meaning the book's title (and likely other information, such as the record ID) will need to be dynamically passed into the modal. You can easily do this using a few additional data attributes. You might be surprised to know you can call these attributes anything you please, such as data-id and data-title as I demonstrate in the following revised modal trigger button (integrated into a Laravel Blade @foreach loop just for sake of example):

@foreach ($books as $book)

    ...

    <button 
       type="button" 
       class="btn btn-primary btn-lg" 
       data-toggle="modal"
       data-id="{{ $book->id }}"
       data-title="{{ $book->title }}"
       data-target="#favoritesModal">
      Add to Favorites
    </button>

    ...

@endforeach

With the revised button in place, you'll next need to write a bit of jQuery-infused JavaScript to ensure the data-* values are inserted into the appropriate sections of the modal:

$(function() {
    $('#favoritesModal').on("show.bs.modal", function (e) {
         $("#favoritesModalLabel").html($(e.relatedTarget).data('title'));
         $("#fav-title").html($(e.relatedTarget).data('title'));
    });
});

Disregard for the moment the data-id attribute; we'll return to this in a moment. In the above example we're using jQuery's on method to attach an event handler to show.bs.modal, a custom event provided via the Bootstrap jQuery plugin. When this modal is displayed, we're going to retrieve the event's "related target" (passed into the event handler as e) to retrieve the data-title's value and assign it to the element container's represented by the favoriteModalLabel ID and fav-title class. This is done using jQuery's data method.

Implementing the Favoriting Mechanism

The "Add to Favorites" modal button presented in the earlier example was just a placeholder:

<button type="button" class="btn btn-primary">
    Add to Favorites
</button>

When the user clicks on this button, we'll want to pass the book's ID into a controller action, and associate it with the authenticated user's ID. I cover the model/database configuration necessary to store data in this fashion in the blog post, Introducing Laravel Many-to-Many Relations so in this post I'll just stick to wiring up the form, controller action, and route. Let's start with the revised button:

{!! Form::open(
  [
   'route' => 'books.favorite', 
   'class' => 'form'
  ]
) !!}
{!! Form::hidden('id', '', ['id' => 'book-id']) !!}
<button type="submit" class="btn btn-primary">
    Add to Favorites
</button>

{!! Form::close() !!}

The revised button is now responsible for submitting a form containing a single hidden id field to a route defined by the books.favorite alias. This is a POST route since we're going to create a new record (presumably in a many-to-many join table between the books and users table) which will look like this:

Route::post('/books/favorite', 
    [ 'as' => 'books.favorite', 
      'uses' => 'BooksController@favorite'
    ]);

The corresponding BooksController favorite action would look more-or-less like this:

public function favorite(Request $request)
{

    $book = Book::find($request->get('id'));

    \Auth::user()->favorites()->save($book);

    return \Redirect::route('home')->with('success', 'Book favorited!');

}

Granted, I'm taking a few shortcuts here. At a minimum, you would certainly want to validate the $request object using a form request. If you're not familiar with this feature, check out the post, Creating a Contact Form in Laravel 5 Using the Form Request Feature.

Finally, you'll need to update the on method to populate the hidden form field identified by the book-id ID. I've added the line to the conclusion of the event handler:

$(function() {
    $('#favoritesModal').on("show.bs.modal", function (e) {
         $("#favoritesModalLabel").html($(e.relatedTarget).data('title'));
         $("#fav-title").html($(e.relatedTarget).data('title'));
         $("#book-id").val($(e.relatedTarget).data('id'));
    });
});

With these pieces in place, your dynamic modal is complete, and users will be able to favorite books!

Questions

If you have any questions about this or any other post on EasyLaravelBook.com, feel free to e-mail me at wj AT wjgilmore.com.

Like My Writing?

Check out my bestselling book, Easy Laravel 5!!!

Chapter 2 shows you how to integrate Bootstrap 3, Bootstrap 4, and Tailwind CSS into your Laravel application

Buy the book