読者です 読者をやめる 読者になる 読者になる

心魅 - cocoromi -

半角スペース時々全角

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だよね。

XMLListにノードを削除するAPIはない

ないでしょ?
http://livedocs.adobe.com/flex/3_jp/langref/XMLList.html



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は使わない方が身のため。