Treeコンポーネントの葉部分を削除する
前置きをしなければならない。
だいぶ怒りにまかせてこのエントリーを書いた。
書いたコードは記憶を頼りに雰囲気を再現しているだけだし、詳細な状況再現もされていない。
ただ1つ言えるのはXMLListを使うと不幸になりそうだ、ということだ。
まえおきおわり。
XMLが嫌いだ。だから今までdataProviderにはArrayCollectionを使ってきた。
ただどうしてもTreeコンポーネントが使いたくて、XMLListとXMLListCollectionを使ってみた。
今回の要件としては、ユーザ操作により、クリックしたノードに子ノードを追加する、もしくはそのノード自体を削除すると言う物だった。
ノードの追加はすんなり出来た
XMLのノード追加なんだからDOM操作だろキリッ
var leaf : XML = new XML( "<node/>" ); clickedNode.appendChild( leaf );
コレで追加された。
ここからが地獄の始まりだった。
XML.removeChildが無い
信じられるか?Dom操作なのにremoveChildが無いんだぜ・・・。
調べたらdeleteをつかえってさ。
http://livedocs.adobe.com/flex/3_jp/langref/operators.html#delete_(XML)
delete clickedNode ;
詳しいことは忘れたけどdelete演算子で変数は消せないみたいなエラーがでた。
プロパティを消すんだってさ。
delte clickedNode.parent().children()[ clickedNode.childIndex() ];
今度はdelete演算子はXMLListに対応してないってさ!!!!!!
ふざけんな!!!!!!!
え。っていうかXMLListなの?
XMLList オブジェクトに XML エレメントが 1 つしかない場合は、XMLList オブジェクトに対して XML クラスのメソッドを直接使用できます。次の例で、example.two は長さ 1 の XMLList オブジェクトです。そのため、このオブジェクトにはどのような XML メソッドをも呼び出すことができます。
http://livedocs.adobe.com/flex/3_jp/langref/XMLList.html
XMLListのインスタンスは内包するXMLがただ1つの時、XMLクラスのAPIを受け付ける仕様。
なので、なんやかんやで取得したXMLノードが実はXMLListという事は良くある。
まぁ冷静に考えればXMLListだよね。
XMLListCollectionにもない
ListCollectionViewを継承してるからremoveItemAtがきっとやってくれる!
やってくれません。
第一階層のindexしか見てくれないので、たとえば以下のような事をしても、
検討違いなノードが消えるし、すぐOutOfBoundsになる。
xmlListCollection.removeItemAt( event.rowIndex );
調べると絶対やりたくない実装方法が良く見つかる
private function removeEmployee():void
{
var node:XML = XML(tree.selectedItem);
if( node == null ) return;
if( node.localName() != "employee" ) return;
var children:XMLList = XMLList(node.parent()).children();
for(var i:Number=0; i < children.length(); i++) {if( children[i].@name == node.@name ) {
delete children[i];
}
}
}
http://livedocs.adobe.com/flex/3_jp/html/help.html?content=dpcontrols_8.html
ねーよ。属性nameが一意じゃなかったらバグっちゃうじゃねーか。
詳しい話は抜きだ。
色々調べた結果、Tree.dataDescriptorというのがいて、デフォルトだとDefaultDataDescriptorが入ってる。
でDefaultDataDescriptorのremoveChildAtでようやくノードの削除が出来ましたとさ。
tree.dataDescriptor.removeChildAt( node.parent() , node , 0 ) ;
ぶっちゃけXMLListの設計おかしくね?
今回はたまたまTreeコンポーネントを使っていたのでDefaultDataDescriptor経由のノード削除が出来た。
もしXMLListやXMLListCollectionを単体で使っていたらどうやって消すのだろうか。
ループで全子供を走査するの?ありえなくね?
このremoveChildAtにしたって、インターフェースのITreeDataDescriptor2で定義されてる物じゃなく、DefaultDataDescriptorが実装している。
XMLのノード削除にdelete演算子とかも、おかしい気がするし。
XMLListやXMLListCollectionが削除のインターフェースを持たないのもおかしいと思う。
まとめ
追加はXML.appendChild
削除はTree.dataDesctipter.removeChildAt
XMLListは使わない方が身のため。