2016-07-22 46 views
1

私はToDoリストを作成するためにSymfony 2.7で作業しています。Symfonyフォーム - CollectionType要素の並べ替え/並べ替え

class TodoType extends AbstractType { 
    public function getName() { 
     return 'todo_list'; 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) { 
     $resolver->setDefaults(array(
      'data_class' => 'AppBundle\Entity\TodoList', 
     )); 
    } 

    public function buildForm(FormBuilderInterface $builder, array $options) { 
     $builder 
      ->add('name', 'text', array(
       'label' => 'Name', 
       ... 
      )) 
      ->add('create', 'submit', array(
       'label' => 'Save', 
       ... 
      )); 

      $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { 
       $todoList = $event->getData(); 
       $form = $event->getForm(); 

       $form 
        ->add('items', 'collection', array(
         'type' => 'todo_list_item_type', 
         'allow_add' => true, 
         'allow_delete' => true, 
         //'by_reference' => false, 
         'data' => ($todoList != null ? $todoList->getItems() : null), 
        )); 

      }); 
     } 
    } 
} 

これは正常に動作します:Form、リスト名とitemsの収集のための単純なテキストフィールドが含まれています。

<form ...> 
    ... 
    <ul class="sortable"> 
     <li> 
      <input id="todo_list_items_0_name" class="item-name form-control" type="text" value="Shopping" placeholder="Name" required="required" name="todo_list[items][0][name]"> 
     </li> 
     <li> 
      <input id="todo_list_items_1_name" class="item-name form-control" type="text" value="Wash car" placeholder="Name" required="required" name="todo_list[items][1][name]"> 
     </li> 
     ... 
    <ul> 

今、私はアイテムを並べ替えるためにjQuery Sortable Pluginを使用したい:items配列は、「アレイのスタイル」の名前を使用してフォームに含まれています。これは正常に動作します。ユーザーは、好きなように項目を並べ替えることができます。ただし、アイテムの格納順序には影響しません。

私はこの問題は明白だと思う:ソート可能なプラグインは、同じまま、その配列インデックスが含まれ、項目名ながらDOM内のアイテムの位置を変更します。したがって、リスト内の新しい位置に関係なく、フォームが提出された時点でItem0にはまだindex = 0が残っています。

これを解決するソリューションはありますか?私が見つけた唯一の解決策は、ソート可能なプラグイン(リオーダが完了した後にトリガされる)のstopイベントを聞き、手動でいくつかのJavaScriptを使用してフィールド名内のインデックス番号を検索/置き換えることです。もちろん、これはうまくいくかもしれませんが、フィールド名の変更に対して非常に脆弱です。たとえば、symfonyの将来のバージョンがsome_field_0_nameの代わりにsome_field_name_0を使用する場合、置き換えコードはそれ以上は機能しません。

別の解決策は、追加のフィールドsortOrderItemクラスを拡張し、この情報をフォームの非表示フィールドとして含めることです。私はまだJSを使用して手動でこのインデックスを更新する必要がありますが、少なくとも私はフォーマットをより詳細に制御するでしょう。

しかし、もっと簡単な方法がないかと思います。コレクション型のソートは特別なものではありません。だから、おそらく箱の解決策がありますか?

答えて

1

あなたのアプローチは私には合理的です(ただし、さらに別のオプションについて説明します)。すぐに使用できるソリューションはありません。収集フォームのタイプは、データの「自然な」順序に依存しています。

最後の問題の解決策は、「プロトタイプ」オプションを使用することです。 Twigビューでは、プロトタイプを表示することができます。これは、コレクション内の任意の(新しい)フォームのHTMLを意味します。
あなたがform_widgetform_rowを使用している場合これはそうでなければ、(ドキュメントhereから)これを行うことができ、自動的に行われます。

<ul class="tags" data-prototype="{{ form_widget(form.tags.vars.prototype)|e('html_attr') }}"> 
    ... 
</ul> 

次にあなたが容易かつ確実にフォーム名を取得できます。

// Get the data-prototype explained earlier 
var prototype = $('.tags').data('prototype'); 

// I assume we use jQuery 
var $prototype = $(prototype); 

// Get the item name 
// by convention, instad of a numeric index it will contain __name__ 
var itemName = $prototype.attr('name'); 

// We can replace '__name__' it to whatever you like 
var nameFor1 = itemName.replace(/__name__/g, 1); 

別のアプローチ

もう1つの方法は、に[position]フィールドを追加することです要素。 Doctrineエンティティであると仮定すると、ソート可能なDoctrine拡張を使用することができます。マニュアルでDoctrine拡張を手動で有効にする必要はありませんが、hereのすべての詳細を見つけることができます。StofDoctrineExtensionBundleを使用できます。

単純なデータ配列の場合(拡張子を追加したくない、またはデータベースに位置を保存したくない場合)、setItemsメソッド内から項目を並べ替えることができます。

+0

ありがとうございました! '__name__'をインデックス番号を再設定するときに簡単に特定できるカスタムコンテンツに置き換えるのは良い選択です。私は既にプロトタイプを使って新しい項目をフォームに動的に追加しています。この段階で '__name__'値を簡単に変更できます。しかし、私は既に存在し、したがってフォームにロードされているアイテムのために、これがどのように機能するのか理解していません。私はこれらの価値/品目に影響を与えません。 –

+0

あなたが見つけた解決策を見つけ、フィールドの名前を変更して正しい順序がSymfonyに "送られ"て、新しい名前を生成するためのテンプレートが得られます。したがって、あなたが言及したように、ソリューションをSymfonyのアップグレード/変更から免れることができます。 – romaricdrigon

関連する問題