Extjs 4ソース解釈TreeStoreのautLoadは無効です。


この数日間問題があります。つまり、extjs 4のTreeStoreを使う時に、彼に自動的にロードさせたくないですが、autloadをfalseに設定しても役に立たないことが分かりました。追い詰められました。firebugで一歩一歩一歩進んで、重要な原因を見つけました。Extjsが持っている例で説明します。私はextjs 4.0.7を使います。http://server/ext-4.0.7-gpl/examples/tree/check-tree.html
例のTreeStoreのコードは以下の通りです。
<!-- lang: js -->
Ext.onReady(function() {
var store = Ext.create('Ext.data.TreeStore', {
    proxy: {
        type: 'ajax',
        url: 'check-nodes.json'
    },
    sorters: [{
        property: 'leaf',
        direction: 'ASC'
    }, {
        property: 'text',
        direction: 'ASC'
    }],
    autoLoad : false
});

var tree = Ext.create('Ext.tree.Panel', {
    store: store,
    rootVisible: false,
    useArrows: true,
    frame: true,
    title: 'Check Tree',
    renderTo: 'tree-div',
    width: 200,
    height: 250,
    dockedItems: [{
        xtype: 'toolbar',
        items: {
            text: 'Get checked nodes',
            handler: function(){
                var records = tree.getView().getChecked(),
                    names = [];

                Ext.Array.each(records, function(rec){
                    names.push(rec.get('text'));
                });

                Ext.MessageBox.show({
                    title: 'Selected Nodes',
                    msg: names.join('<br />'),
                    icon: Ext.MessageBox.INFO
                });
            }
        }
    }]
    });
});
上のコードはまずExt.data.TreeStoreを作成しました。これでExt.data.TreeStoreに位置決めできます。このクラスには一つの方法があります。特に注意してください。set RootNode:functionです。以下は方法の主な内容です。
<!-- lang: js -->
setRootNode: function(root) {
    ...
    Ext.data.NodeInterface.decorate(root);
    ...
    // If the user has set expanded: true on the root, we want to call the expand function
    if (!root.isLoaded() && (me.autoLoad === true || root.isExpanded())) {
        me.load({
            node: root
        });
    }

    return root;
}
上から見れば、本当にロードを出す方法はset RootNodeの方法であり、ロードを出発できる条件は!root.isLoaded()&&&(me.atoot Load==true root.isExpand()は明らかです。root.isLoaded()はfalseです。構造storeの時はまだデータをロードしていません。autloadはfalseに違いないです。これは自分で設定したものです。では唯一の問題はisExpanded方法です。これは簡単です。私達はExt.data.TreeStoreを作成してrootに加入してから間もなくなりました。はい、以下は私達が変えたコードです。
<!-- lang: js -->
var store = Ext.create('Ext.data.TreeStore', {
    proxy: {
        type: 'ajax',
        url: 'check-nodes.json'
    },
    sorters: [{
        property: 'leaf',
        direction: 'ASC'
    }, {
        property: 'text',
        direction: 'ASC'
    }],
autoLoad : false,
    root : {
        expanded : false
    }
});
そして期待に胸を膨らませて運行すると、やはり同じです。なぜですか引き続きfirebug
上の経験からexpadedは問題の鍵です。三つの場合に分けます。
  • Rootを設置し、expadedはtrue
  • に設定されています。
  • はRootを設置しません。
  • Rootを設置し、expadedは
  • を設定しません。
  • Rootを設置し、expadedをfalse
  • に設定します。
    最初の場合は自動的にロードされます。まず第二の状況を見ます。
    Rootを設置しない
    この場合コードはTreeStoreを作成した後にTreePanelのinitComponentメソッドに入りますが、この方法には重要なコードがあります。
    <!-- lang: js -->
    initComponent: function() {
        if (!me.getView().rootVisible && !me.getRootNode()) {
            me.setRootNode({
                expanded: true
            });
        }
    }
    
    上に設定されていない場合は、ME.getRootNode()が空であると、デフォルトの値を作成します。expaded:true。このようにexpand dedでtrueになります。自動的にロードされます。
    Rootを設置し、expadedはいかなる値も設定しません。
    この場合は4番目です。上のsetRootNodeの方法で見られます。Ext.data.NodeInterface.decorate。この言葉は、割り当てられていない属性にデフォルト値を割り当てるということです。標準値はfalseと見られます。次の状況の分析に直結します。
    Rootを設置し、expadedをfalseに設定します。
    この状況は複雑です。前のように、第一歩はTreeStoreを作成して、TreePanelのconstructortに入り、TreePanelのinitComponentに入り、initComponentでME.calPantを呼び出しました。この言葉は父類のinitComponentを呼び出します。これは父類Ext.panel.Table.Table.Tableのコードをご覧ください。
    <!-- lang: js -->
    initComponent: function(){
        ...
        // AbstractDataView will look up a Store configured as an object
        // getView converts viewConfig into a View instance
        view = me.getView();  
        ....
    },
    
    /**
     * Gets the view for this panel.
     * @return {Ext.view.Table}
     */
    getView: function() {
        var me = this,
            sm;
    
        if (!me.view) {
            sm = me.getSelectionModel();
            me.view = me.createComponent(Ext.apply({}, me.viewConfig, {
                deferInitialRefresh: me.deferRowRender,
                xtype: me.viewType,
                store: me.store,
                headerCt: me.headerCt,
                selModel: sm,
                features: me.features,
                panel: me
            }));
            me.mon(me.view, {
                uievent: me.processEvent,
                scope: me
            });
            sm.view = me.view;
            me.headerCt.view = me.view;
            me.relayEvents(me.view, ['cellclick', 'celldblclick']);
        }
        return me.view;
    }
    
    initComponentでget Viewのメソッドを呼び出しました。getViewの方法ではviewがすでに存在しているかどうかを先に判断します。ない場合は新たに作成します。ME.create Componentを通じて作成します。ここでは、ME.view Configを定義するときにroot属性を定義します。vieConfigのは、viefigの中のnode属性もこれほど重要ではありません。を選択します。createComponentを作成した後、Ext.tree.Viewのinit Componentメソッドに入りました。コードは以下の通りです。
    <!-- lang: js -->
    initComponent: function() {
        var me = this;
    
        if (me.initialConfig.animate === undefined) {
            me.animate = Ext.enableFx;
        }
    
        me.store = Ext.create('Ext.data.NodeStore', {
            recursive: true,
            rootVisible: me.rootVisible,
            listeners: {
                beforeexpand: me.onBeforeExpand,
                expand: me.onExpand,
                beforecollapse: me.onBeforeCollapse,
                collapse: me.onCollapse,
                scope: me
            }
        });
    
        if (me.node) {
            me.setRootNode(me.node);
        }
        me.animQueue = {};
        me.callParent(arguments);
    }
    
    ついに張本人を見つけました。
    <!-- lang: js -->
    if (me.node) {
            me.setRootNode(me.node);
    }
    
    上でnodeはnullではないと言いましたので、set RootNodeを呼び出します。set RootNodeの方法を見てください。
    <!-- lang: js -->
    setRootNode: function(node) {
        var me = this;        
        me.store.setNode(node);
        me.node = node;
        if (!me.rootVisible) {
            node.expand();
        }
    }
    
    ここではrootVisibleを判断します。デフォルトはfalseです。だからexpand()メソッドを呼び出します。この方法は一連のイベントを出発します。最終的にはTreeStoreのonBefore NodeExpand方法になります。TreeStoreのone Before NodeExpand方法を見てください。
    <!-- lang: js -->
    onBeforeNodeExpand: function(node, callback, scope) {
        if (node.isLoaded()) {
            Ext.callback(callback, scope || node, [node.childNodes]);
        }
        else if (node.isLoading()) {
            this.on('load', function() {
                Ext.callback(callback, scope || node, [node.childNodes]);
            }, this, {single: true});
        }
        else {
            this.read({
                node: node,
                callback: function() {
                    Ext.callback(callback, scope || node, [node.childNodes]);
                }
            });
        }
    },
    
    はい、見ました。最後のelse分岐に行きます。this.read.readメソッドを呼び出してajaxの要求を呼び出します。
    上のコードを分析しました。したがって、与えられたソリューションは2つあります。
    シナリオ1がTreeStoreを定義する場合は、以下のように配置されます。
    <!-- lang: js-->
    autoLoad : false,
    root: {
        expanded : false
    }
    
    TreePanelを定義するときはrootVisible:trueを配置します。
    シナリオ2 TreeStoreのsetRootNodeを書き換える方法
    <!-- lang: js -->
    Ext.override(Ext.data.TreeStore, {
    setRootNode: function(root) {
        var me = this;
    
        root = root || {};
        if (!root.isNode) {
            Ext.applyIf(root, {
                id: me.defaultRootId,
                text: 'Root',
                allowDrag: false
            });
            root = Ext.ModelManager.create(root, me.model);
        }
        Ext.data.NodeInterface.decorate(root);
    
        me.getProxy().getReader().buildExtractors(true);
    
        me.tree.setRootNode(root);
    
        //    
        //if(!root.isLoaded() && (me.autoLoad === true || root.isExpanded())){
        if (!root.isLoaded() && (me.autoLoad === true)) {
            me.load({
                node: root
            });
        }
        return root;
    }
    });
    
    この場合はTreeStoreのroot属性は設定できません。
    もちろん他の方法もあります。基本的には元のロジックを書き換えることです。今考えてみます。extjsはデータを動的にロードするために設定されたこれらの属性を実現するためのものらしいです。