Tweak the ui/ux

Default implementation looks ok, but I'm sure you'll want to tweak it to your liking.

In the Overview I mentioned where bulk actions' html gets added, let's take a look at what actually gets added.

View

DragonFly\Lists has a view called actions.blade.php and looks like this:

<div class="row" style="margin: 0; margin-bottom: 15px;">
    <div class="col-md-6">
        <form class="form form-inline">
                    <select name="perform_action" class="form-control input-sm block lists-action-select">
                        <option value="">{!!trans('lists::actions.menu_initial')!!}</option>
                        @foreach($actions as $action)
                            <option value="{{$action['slug']}}" data-url="{{$action['url']}}"
                                    data-status="{!!trans($action['status'], ['slug' => $action['slug']])!!}">
                                {{$action['title']}}
                            </option>
                        @endforeach
                    </select>
                    <button class="btn btn-sm btn-primary lists-action-perform">{!!trans('lists::actions.apply')!!}</button>
        </form>
    </div>
    <div class="col-md-6 text-right">
        <div class="pull-left lists-indicator hide"><i class="fa fa-circle-o-notch fa-spin"></i></div>
        <span class="lists-action-indicator">

        </span>
    </div>
</div>

Aside from the layout there 4 important points here:

  1. An empty option is added with the lists::actions.menu_initial translation as value.
  2. Actions get rendered as options with 2 data attributes
  • url: so the js knows where to send the data to
  • status: the message that's displayed as long as the request hasn't finished
  1. A button is added with the lists::actions.apply translation
  2. A span called lists-action-indicator is there to display a message about the status of the request

If you're changing the view, those first 3 points you should keep in mind. The list-action-indicator can be overwritten, next to that you can format it however you'd like.

Change the js plugin's behaviour

Changing the view is ok for esthetics, but changing behaviour is more fun.

There are 2 ways you can do this:

  1. Minimal by listening to events
  2. Overwriting key handlers

1. Events

Events are the quickest and easiest way tweak the user experience.

Most of the arguments they get passed are the same.

  • container: the dataTable's wrapper element (containing the dataTable & the bulk actions)
  • action: The title of the action that will be/was performed
  • option: The element of the action that will be/was performed (containing the data attributes)
  • items: An array containing ids of the records that this action will be/was performed on.

❗️

Don't forget to return false on your events to prevent the default events from happening.

You can register your event listeners in your view after you have rendered the dataTable js definition

<!-- Render the javascript definition for the table -->
    <script type="text/javascript">
        {!! $table->definition() !!}
        
        $(#{{$table->html_id}}).on('lists.spinner_start', function(e, container, action, option, items){
            // Your own event handler
          
          return false;
        });
        
        $(#{{$table->html_id}}).on('lists.spinner_stop', function(e, container, action, option, data){
            // Your own event handler
          
          return false;
        });
        
        $(#{{$table->html_id}}).on('lists.complete', function(e, container, data, action, option, items){
            // Your own event handler
          
          return false;
        });
    </script>

lists.spinner_start (e, container, action, option, items)

This event gets called right before the request is initialised.

By default it starts the spinner object and shows the action's default status.

lists.spinner_stop (e, container, action, option, data)

This is event is triggered when the request completed.

As you can see a data attribute is available at the end that contains that request's data return which consists of 4 possible keys:

  • status ('success','error')
  • type ('complete', 'empty')
  • message
  • error

The error key only gets sent if an exception was thrown when performing the action.

By default it hides the spinner, updates the action's status message and gives it a class(text-success or text-warning) and sets a timer that hides the action's status message after 7 seconds.

lists.complete (e, container, data, action, option, items)

This is event is triggered when the request completed.

As you can see a data attribute is available that contains that request's data return which consists of 4 possible keys:

  • status ('success','error')
  • type ('complete', 'empty')
  • message
  • error

The error key only gets sent if an exception was thrown when performing the action.

By default it does nothing since the spinner takes care of the status message.

2. Handlers

Next to events you can overwrite the default handlers, there are 3:

  1. initTool, a function which places the bulk actions tools & adds the actions to it
  2. spinner, an object that handles the spinner
  3. complete, a callback function that handles request completion

All these are defined on $.fn.dataTableLists

📘

It's best to define these after you've loaded the assets/js/happydemon.lists.js file.

initTool (actions, container)

As mentioned before, this function is called to place the table's bulk actions (which by default are added above the table), however, you are free to place it in any html element you'd like.

It takes 2 arguments:

  • actions: this argument holds the actions' HTML (rendered from our view)
  • container: this one's the table's wrapper element.
$.fn.dataTableLists.initTool = function (actions, container) {
        // Places actions above table
        container.prepend('<div class="row-list-tools"></div>');
        container.find('.row-list-tools').prepend(actions);
    };

spinner {}

❗️

The spinner object needs an init method that takes settings as an argument, you're free to fill the object with any methods you'd like

By default the spinner object's init method registers the lists.spinner_start and lists.spinner_stop event and describes their callbacks.

$.fn.dataTableLists.spinner = {
        init: function (settings) {
            settings.container.data('currentClass', 'text-muted');
            settings.dataTable.on('lists.spinner_start', this.start);
            settings.dataTable.on('lists.spinner_stop', this.stop);
        },
        start: function (e, container, action, option, items) {
            container.find('.lists-indicator').removeClass('hide');
            container.find('.lists-action-indicator').addClass('text-muted').text(option.data('status')).slideDown();
            container.find('.lists-indicator').show();
        },
        stop: function (e, container, action, option, data) {
            container.find('.lists-indicator').addClass('hide');

            var indicator = container.find('.lists-action-indicator');

            var addClass = '';
            var text = '';
            switch (data.status) {
                case 'success':
                    if (data.type != 'empty')
                        addClass = 'text-success';
                    else
                        addClass = 'text-warning';

                    text = data.message;
                    break;
                case 'error':
                    addClass = 'text-warning';
                    text = data.message;
                    break;
            }

            indicator.text(text);
            indicator.removeClass(container.data('currentClass')).addClass(addClass);
            container.data('currentClass', addClass);

            // Hide after 7 seconds
            setTimeout(function () {
                indicator.slideUp().removeClass(settings.container.data('currentClass')).addClass('text-muted').text('');
                container.data('currentClass', 'text-muted');
            }, 7000);
        }
    };

complete (e, container, data, action, option, items)

This is the default request completion callback. By default it does nothing.
If you'd rather overwrite instead of registering a different event callback, be my guest.

$.fn.dataTableLists.complete = function (e, container, data, action, option, items) {

    };