JavaScript options: choose the features to enable

Use allowe_up, allow_down, allow_add and allow_remove options to disable some buttons

Warning: if you're using the plugin's form theme, allow_add and allow_remove are taken from your form type configuration.

Enable or disable collection's actions :

A simple collection

Value : a

Value : b

Value : c

A collection of themed types

Value : a

Value : b

Value : c


Code used:

    <!-- The name_prefix option is generated, please read at -->

    <script type="text/javascript">

      function reloadCollectionButtons() {
        $('.form-collection').collection({
           name_prefix:  'form[values]',
           allow_up: $('#up').is(':checked'),
           allow_down: $('#down').is(':checked'),
           allow_add: $('#add').is(':checked'),
           allow_remove: $('#remove').is(':checked'),
           allow_duplicate: $('#duplicate').is(':checked')
        });

        $('.advancedForm-collection').collection({
           name_prefix:  'advancedForm[values]',
           allow_up: $('#up').is(':checked'),
           allow_down: $('#down').is(':checked'),
           allow_add: $('#add').is(':checked'),
           allow_remove: $('#remove').is(':checked'),
           allow_duplicate: $('#duplicate').is(':checked')
        });
      }

      reloadCollectionButtons();

      $('.reload-collection').click(function() {
         reloadCollectionButtons();
      });

    </script>

<?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,
        ];
    }
}
<?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);
    }
}
{% extends 'FuzAppBundle::layout.html.twig' %}

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

{% block title %}JavaScript options: choose the features to enable{% endblock %}

{% block body %}

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

    <p>Use <code>allowe_up</code>, <code>allow_down</code>, <code>allow_add</code> and <code>allow_remove</code> options to disable some buttons</p>

    <p><b>Warning</b>: if you're using the plugin's form theme, <code>allow_add</code> and <code>allow_remove</code> are taken from your form type configuration.</p>

    <form class="form-inline">
      <strong>Enable or disable collection's actions : </strong>
      <div class="checkbox">
         <label>
           <input id="up" class="reload-collection" type="checkbox" checked/> Enable Move up
         </label>
       </div>
      <div class="checkbox">
         <label>
           <input id="down"  class="reload-collection" type="checkbox" checked/> Enable Move down
         </label>
       </div>
      <div class="checkbox">
         <label>
           <input id="add"  class="reload-collection" type="checkbox" checked/> Enable Add
         </label>
       </div>
      <div class="checkbox">
         <label>
           <input id="remove"  class="reload-collection" type="checkbox" checked/> Enable Remove
         </label>
       </div>
      <div class="checkbox">
         <label>
           <input id="duplicate"  class="reload-collection" type="checkbox" checked/> Enable Duplicate
         </label>
       </div>
    </form>

    <br/>

    <div class="row">

       <div class="col-md-6">
          <h3>A simple collection</h3>

             {{ form(form) }}

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

       </div>
       <div class="col-md-6">
          <h3>A collection of themed types</h3>

            {% form_theme advancedForm 'FuzAppBundle:Options:options-theme.html.twig' %}
            {{ form(advancedForm) }}

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

       </div>

    </div>

    <hr/>

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

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

{% endblock %}

{% block script %}

    <!-- The name_prefix option is generated, please read at -->

    <script type="text/javascript">

      function reloadCollectionButtons() {
        $('.form-collection').collection({
           name_prefix:  '{{ form.values.vars.full_name }}',
           allow_up: $('#up').is(':checked'),
           allow_down: $('#down').is(':checked'),
           allow_add: $('#add').is(':checked'),
           allow_remove: $('#remove').is(':checked'),
           allow_duplicate: $('#duplicate').is(':checked')
        });

        $('.advancedForm-collection').collection({
           name_prefix:  '{{ advancedForm.values.vars.full_name }}',
           allow_up: $('#up').is(':checked'),
           allow_down: $('#down').is(':checked'),
           allow_add: $('#add').is(':checked'),
           allow_remove: $('#remove').is(':checked'),
           allow_duplicate: $('#duplicate').is(':checked')
        });
      }

      reloadCollectionButtons();

      $('.reload-collection').click(function() {
         reloadCollectionButtons();
      });

    </script>

{% endblock %}

{% 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 %}