JavaScript options : hide Up and Down buttons on useless elements

Use hide_useless_buttons option to display or not the up button on the first item, and the down button on the last one.

This can be useful if you want to style useless buttons by yourself, instead of display:none.

Test it live:

Add, move, remove values and press Submit.
Value
Value
Value

Value :a

Value :b

Value :c


Code used:

    <script type="text/javascript">

        $('.form-collection').collection({
            hide_useless_buttons: false,
            max: 5
        });

        $('#test-it').on('click', function() {

            // only useful for the demo
            $('.collection-up, .collection-down').css('display', '');

            $('.form-collection').collection({
                hide_useless_buttons: $('#test-it').is(':checked'),
                max: 5
            });
        });

    </script>
File: Base/BaseController.php
<?php

namespace Fuz\AppBundle\Base;

use Fuz\AppBundle\Entity\Value;
use Fuz\AppBundle\Form\ValueType;
use Fuz\QuickStartBundle\Base\BaseController as QuickStartBase;
use Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\HttpFoundation\Request;

class BaseController extends QuickStartBase
{
    protected function createContextSample(Request $request, $name = 'form', $values = ['a', 'b', 'c'])
    {
        $data = ['values' => $values];

        $form = $this
           ->get('form.factory')
           ->createNamedBuilder($name, Type\FormType::class, $data)
           ->add('values', Type\CollectionType::class, [
               'entry_type'    => Type\TextType::class,
               'label'         => 'Add, move, remove values and press Submit.',
               'entry_options' => [
                   'label' => 'Value',
               ],
               'allow_add'    => true,
               'allow_delete' => true,
               'prototype'    => true,
               'attr'         => [
                   'class' => "{$name}-collection",
               ],
           ])
           ->add('submit', Type\SubmitType::class)
           ->getForm()
        ;

        $form->handleRequest($request);
        if ($form->isValid()) {
            $data = $form->getData();
        }

        return [
            $name         => $form->createView(),
            "{$name}Data" => $data,
        ];
    }

    protected function createAdvancedContextSample(Request $request, $name = 'advancedForm')
    {
        $a = new Value('a');
        $b = new Value('b');
        $c = new Value('c');

        $data = ['values' => [$a, $b, $c]];

        $form = $this
           ->get('form.factory')
           ->createNamedBuilder($name, Type\FormType::class, $data)
           ->add('values', Type\CollectionType::class, [
               'entry_type'   => ValueType::class,
               'label'        => 'Add, move, remove values and press Submit.',
               'allow_add'    => true,
               'allow_delete' => true,
               'prototype'    => true,
               'required'     => false,
               'attr'         => [
                   'class' => "{$name}-collection",
               ],
           ])
           ->add('submit', Type\SubmitType::class)
           ->getForm()
        ;

        $form->handleRequest($request);
        if ($form->isValid()) {
            $data = $form->getData();
        }

        return [
            $name         => $form->createView(),
            "{$name}Data" => $data,
        ];
    }
}
File: Base/BaseController.php
File: Controller/OptionsController.php
<?php

namespace Fuz\AppBundle\Controller;

use Fuz\AppBundle\Base\BaseController;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;

/**
 * @Route("/options")
 */
class OptionsController extends BaseController
{

    /**
     * JavaScript options
     *
     * An overview of almost all options that you
     * can enable/disable/customize on the fly.
     *
     * @Route("/overview", name="overview")
     * @Template()
     */
    public function overviewAction(Request $request)
    {
        return $this->createContextSample($request);
    }

    /**
     * JavaScript options
     *
     * Customized buttons
     *
     * @Route("/customButtons", name="customButtons")
     * @Template()
     */
    public function customButtonsAction(Request $request)
    {
        return $this->createContextSample($request);
    }

    /**
     * JavaScript options
     *
     * Disable buttons you don't want
     *
     * @Route("/enableButtons", name="enableButtons")
     * @Template()
     */
    public function enableButtonsAction(Request $request)
    {
        return array_merge(
           $this->createContextSample($request), $this->createAdvancedContextSample($request)
        );
    }

    /**
     * JavaScript options
     *
     * Control the minimum and maximum of allowed number of elements
     *
     * @Route("/numberCollectionElements", name="numberCollectionElements")
     * @Template()
     */
    public function numberCollectionElementsAction(Request $request)
    {
        return array_merge(
           $this->createContextSample($request), $this->createAdvancedContextSample($request)
        );
    }

    /**
     * JavaScript options
     *
     * Add the button close to each collection elements or only at the bottom
     *
     * @Route("/addButtonAtTheBottom", name="addButtonAtTheBottom")
     * @Template()
     */
    public function addButtonAtTheBottomAction(Request $request)
    {
        return array_merge(
           $this->createContextSample($request, 'enabled'), $this->createContextSample($request, 'disabled')
        );
    }

    /**
     * JavaScript options
     *
     * Run a callback before or after adding, deleting and moving elements
     *
     * @Route("/eventCallbacks", name="eventCallbacks")
     * @Template()
     */
    public function eventCallbacksAction(Request $request)
    {
        return array_merge(
           $this->createContextSample($request, 'eventsBefore'), $this->createContextSample($request, 'eventsAfter')
        );
    }

    /**
     * JavaScript options
     *
     * Use this plugin without the attached form-theme
     *
     * @Route("/withoutFormTheme", name="withoutFormTheme")
     * @Template()
     */
    public function withoutFormThemeAction(Request $request)
    {
        return $this->createContextSample($request);
    }

    /**
     * JavaScript options
     *
     * Initialize a collection with a given minimum number of elements
     *
     * @Route("/givenMinimumElements", name="givenMinimumElements")
     * @Template()
     */
    public function givenMinimumElementsAction(Request $request)
    {
        return $this->createContextSample($request, 'form', []);
    }

    /**
     * JavaScript options
     *
     * Hide move-up on the first item and move-down on the last one
     *
     * @Route("/hideMoveUpDown", name="hideMoveUpDown")
     * @Template()
     */
    public function hideMoveUpDownAction(Request $request)
    {
        return $this->createContextSample($request, 'form');
    }

    /**
     * JavaScript options
     *
     * Drag & Drop allow to get rid of "move up" and "move down" buttons
     *
     * @Route("/dragAndDrop", name="dragAndDrop")
     * @Template()
     */
    public function dragAndDropAction(Request $request)
    {
        return [
            'disabled'    => $this->createAdvancedContextSample($request, 'disabled'),
            'nobuttons'   => $this->createAdvancedContextSample($request, 'nobuttons'),
            'moreoptions' => $this->createAdvancedContextSample($request, 'moreoptions'),
            'startupdate' => $this->createAdvancedContextSample($request, 'startupdate'),
        ];
    }

    /**
     * JavaScript options
     *
     * Run a callback before and after collection initialization
     *
     * @Route("/initCallbacks", name="initCallbacks")
     * @Template()
     */
    public function initCallbacksAction(Request $request)
    {
        return $this->createContextSample($request);
    }

    /**
     * JavaScript options
     *
     * Put buttons to custom locations in your page.
     *
     * @Route(
     *      "/buttons-custom-location",
     *      name = "buttonsCustomLocation"
     * )
     * @Template()
     */
    public function buttonsCustomLocationAction(Request $request)
    {
        return array_merge(
           $this->createContextSample($request, 'collectionA'), $this->createContextSample($request, 'collectionB'), $this->createContextSample($request, 'collectionC')
        );
    }

    /**
     * JavaScript options
     *
     * Enable / disable fade animation when adding / removing
     * collection elements.
     *
     * @Route("/fadeInFadeOut", name="fadeInFadeOut")
     * @Template()
     */
    public function fadeInFadeOutAction(Request $request)
    {
        return $this->createContextSample($request);
    }
}
File: Controller/OptionsController.php
File: Resources/views/Options/hideMoveUpDown.html.twig
{% extends 'FuzAppBundle::layout.html.twig' %}

{% block extra_js %}
    <script src="{{ asset('js/jquery.collection.js') }}"></script>
{% endblock %}

{% block title %}JavaScript options : hide Up and Down buttons on useless elements{% endblock %}

{% block body %}

    <h2>{{ block('title') }}</h2>

    <p>Use <code>hide_useless_buttons</code> option to display or not the up button on the first item, and the down button on the last one.</p>

    <p>This can be useful if you want to style useless buttons by yourself, instead of <code>display:none</code>.</p>

    <p>Test it live: <input type="checkbox" id="test-it" /></p>

    {% form_theme form 'jquery.collection.html.twig' %}
    {{ form(form) }}

    <hr/>

    {% for value in formData.values %}
        <p>Value : {{ value }}</p>
    {% endfor %}

    <hr/>

    <p>Code used:</p>
    <pre>{{ block('script') | e }}</pre>

    {{
        tabs([
            'Base/BaseController.php',
            'Controller/OptionsController.php',
            'Resources/views/Options/hideMoveUpDown.html.twig',
            'Resources/views/Options/options-theme.html.twig',
        ])
    }}

{% endblock %}

{% block script %}

    <script type="text/javascript">

        $('.form-collection').collection({
            hide_useless_buttons: false,
            max: 5
        });

        $('#test-it').on('click', function() {

            // only useful for the demo
            $('.collection-up, .collection-down').css('display', '');

            $('.form-collection').collection({
                hide_useless_buttons: $('#test-it').is(':checked'),
                max: 5
            });
        });

    </script>

{% endblock %}
File: Resources/views/Options/hideMoveUpDown.html.twig
File: Resources/views/Options/options-theme.html.twig

{% block ValueType_label %}{% endblock %}
{% block ValueType_errors %}{% endblock %}

{% block ValueType_widget %}

    <div class="row">
        <div class="col-md-5">
            {{ form_widget(form.value) }}
        </div>
        <div class="col-md-3">
            <a href="#" class="collection-up btn btn-default" title="Move element up"><span class="glyphicon glyphicon-arrow-up"></span></a>
            <a href="#" class="collection-down btn btn-default" title="Move element down"><span class="glyphicon glyphicon-arrow-down"></span></a>
        </div>
        <div class="col-md-3">
            <a href="#" class="collection-remove btn btn-default" title="Delete element"><span class="glyphicon glyphicon-trash"></span></a>
            <a href="#" class="collection-add btn btn-default" title="Add element"><span class="glyphicon glyphicon-plus-sign"></span></a>
        </div>
        <div class="col-md-1">
            <a href="#" class="collection-duplicate btn btn-default" title="Duplicate element"><span class="glyphicon glyphicon-th-large"></span></a>
        </div>
    </div>

{% endblock %}
File: Resources/views/Options/options-theme.html.twig