2012年5月6日日曜日

Form CollectionType ~ prototype

Formにcollection type ってのがあります。このprototypeについての説明 詳しくは コチラ(How to Embed a Collection of Forms)を見てもらえればよいのですが、簡単にここでもまとめておこうかと思います。

そもそも collection type ってなんなのか

まぁ、これは名前のままなんですが、typeの集合ですね。 例えば、「あなたの好きな曲はなんですか?」って項目に、TextType(テキストフィールド)が複数ぶら下がる場合を考えれば、 そのTextTypeを集めるのがCollectionTypeとなります。

もうちょっとわかりやすく説明しますと、UserにSongがぶら下がるとしましょう。これはOneToManyでUserがすきな曲は複数もてます。
こんなとき、UserTypeのEmbedでSongTypeを埋め込みたいですよね。でも1つのUserに対してSongTypeのフィールドたちをいっぱいもたなくてはならない。それってどうすんの? => ここで使うのが CollectionTypeなわけです。
EntityでもOneToManyの場合、Doctrine\Common\Collections\Collection が使用されますが、このCollectionと同じことなのかな。このCollectionを扱うためのTypeがCollectionType的な。

動的に項目増やしたい場合ってあるよね?

Collectionはなんとなくわかった。ちょっと疑問なんだけど、一般的にSongが上図のように3つしかぶら下がらないとは限らないよね? サービスによっては、Javacript とかで項目を動的に追加したりしたい場合ってあるとおもう。
その場合もCollection使うと思うんだけど、どうなのよ?

このために、prototypeがあるわけです。prototypeを使えばフォームの項目のHTML内容をプロトタイプとして持ってくれるので、あとはJavascriptでそれをベースにどんどん増やしてね☆ って話。
  1. // src/Hoge/UserBundle/Form/Type/UserType.php  
  2. // ...  
  3.   
  4. public function buildForm(FormBuilder $builderarray $options)  
  5. {  
  6.     $builder->add('username');  
  7.   
  8.     $builder->add('songs''collection'array(  
  9.         'type' => new SongType(),  
  10.         'allow_add' => true,  
  11.         'allow_delete' => true,  
  12.         'by_reference' => false,  
  13.         'prototype' => true,  
  14.     ));  
  15. }  
以下のようにするとdata-prototype に、エスケープされたプロトタイプのHTMLが入ります
  1. <ul class="songs" data-prototype="{{ form_widget(form.songs.get('prototype')) | e }}">  
  2. <li></li>  
  3. </ul>  
で、javascriptで以下のように$$name$$を数字に置き換えれば、動的に追加できます。 例えば、ボタンのクリックイベントで addTagForm() を呼べばOK
  1. $(function(){  
  2.     var collectionHolder = $('ul.songs');  
  3.   
  4.     var addTagForm = function() {  
  5.         // Get the data-prototype we explained earlier  
  6.         var prototype = collectionHolder.attr('data-prototype');  
  7.   
  8.         // Replace '$$name$$' in the prototype's HTML to  
  9.         // instead be a number based on the current collection's length.  
  10.         var newForm = prototype.replace(/\$\$name\$\$/g, collectionHolder.children().length);  
  11.   
  12.         collectionHolder.append('<li>'+newForm+'</li>');  
  13.     };  
  14.   
  15. });  
ざっくりだけど、こんなかんじです。

0 コメント:

コメントを投稿

Share

Twitter Delicious Facebook Digg Stumbleupon Favorites More