Ext.tree.Panel. Деревья

Для представления элементов в виде дерева используется класс Ext.tree.Panel. Создадим простейшее дерево:

Ext.onReady(function(){
     Ext.create('Ext.tree.Panel', {
        title: 'Страны СНГ',
        width: 200,
        height: 200,
		rootVisible: true,
        renderTo: Ext.getBody(),
		root: {
			text: 'Страны СНГ',
			expanded: true,
			children:
			[{
				text: "Россия",
				children: [{
					text: "Москва",
					leaf: true
				}, {
					text: "Санкт-Петербург",
					leaf: true
				}, {
					text: "Волгоград",
					leaf: true
				}],
				leaf: false,
				"expanded": true
			},
			{
				text: "Украина",
				leaf: false
			},
			{
				text: "Белоруссия"
			}]
		}
    });
});

В данном случае все узлы дерева задаются с помощью свойства root, которое по сути представляет узел и может содержать дочерние узлы в свойстве children. Дочерние узлы в свою очередь также могут содержать другие узлы.

Узлы дерева

Узлы дерева реализуют ряд свойств, которые помогают настроить их поведение:

В узлах у нас определено несколько свойств. Свойство text показывает заголовок узла в дереве. Свойство leaf указывает, как будет отображен узел - как единичный узел, если "leaf": true, либо как поддерево, если "leaf": false.

Еще одно использованное свойство expanded показывает, будет ли узел раскрыт при загрузке дерева.

TreeStore и загрузка узлов из внешнего источника

Кроме статического задания схемы узлов дерева, мы можем использовать загрузку через внешнее хранилище, например, в формате json. Во-первых, создадим хранилище данных, из которого мы будем брать данные в дерево:

var store = Ext.create('Ext.data.TreeStore', {
		proxy:{
			type: 'ajax',
			url: 'treeData.json'
		}
	});

В данном случае объект proxy содержит два свойства. Поскольку мы будем получать данные с сервера в формате json, то для свойства type имеет значение ajax. Свойство url указывает на источник , который будет посылать приложению данные в json-формате. В данном случае это файл json. Но это также может быть и любое другое приложение, например, на php.

Теперь определим саму панель, в которую будет загружено дерево:

Ext.create('Ext.tree.Panel', {
		title: 'Страны СНГ',
		width: 200,
		height: 200,
		store: store,
		rootVisible: false,
		renderTo: Ext.getBody()
	});

Панель Ext.tree.Panel получает в свойстве store ранее определенное хранилище. Свойство rootVisible: false делает невидимым корневой узел, в данном случае он нам не нужен.

Теперь перейдем к самим данным. Они у нас находятся в файле treeData.json, который имеет следующее содержание:

[{
	"text": "Россия",
	"children": [{
		"text": "Москва",
		"leaf": true
	}, {
		"text": "Санкт-Петербург",
		"leaf": true
	}, {
		"text": "Волгоград",
		"leaf": true
	}],
	"leaf": false,
	"expanded": true
	},
	{
		"text": "Украина",
		"leaf": true
	},
	{
		"text": "Белоруссия",
		"leaf": true
}]

Объекты в формате json подчиняются определенным правилам: каждый объект заключается в фигурные скобки, а массив таких объектов - в квадратные.

Мы также в хранилище можем задать используем корневой узел, для этого используем rootVisible: true и изменим определение хранилища следующим образом:

var store = Ext.create('Ext.data.TreeStore', {
		proxy:{
			type: 'ajax',
			url: 'treeData.json'
		},
		root: {
			text: 'Все страны',
			expanded: true
		}
		Ext.create('Ext.tree.Panel', {
		title: 'Страны СНГ',
		width: 200,
		height: 200,
		store: store,
		rootVisible: true,
		renderTo: Ext.getBody()
	});
	});

Результат будет тем же, что и в первом случае.

Кроме того, мы можем не получать данные со стороны сервера, а закодировать их в самом хранилище, указав в корневом узле все подузлы:

	var store1 = Ext.create('Ext.data.TreeStore', {
		root: {
			text:"Страны-участники",
			expanded: true,
			children: [{
			text: "Россия",
			leaf: true
			},{
			text: "Англия",
			leaf: true
			},{
			text: "Франция",
			leaf: true
			}]
		}
	});

Сортировка дерева

Для установки у хранилища способа сортировки нам надо применить класс Ext.util.Sorter через свойство sorters. Оно содержит определения сортировщиков, которые упорядочивают все узлы дерева. Сортировщик в качестве ключа сортировки приминает свойство узла, которое указывается в свойстве property. Затем в свойстве direction мы задаем порядок сортировки: прямой ('ASC') или обратный ('DESC').

Теперь изменим код хранилища store и дерева следующим образом:

Ext.onReady(function(){
	var store = Ext.create('Ext.data.TreeStore', {
		root: {
			text: 'Страны СНГ',
			expanded: true,
			children:
			[{
				text: "Россия",
				children: [{
					text: "Москва",
					leaf: true
				}, {
					text: "Санкт-Петербург",
					leaf: true
				}, {
					text: "Волгоград",
					leaf: true
				}],
				leaf: false,
				"expanded": true
			},
			{
				text: "Украина",
				leaf: false
			},
			{
				text: "Белоруссия"
			}]
		},
		sorters: [{
			property: 'text',
			direction: 'ASC'
		}]
	});
     Ext.create('Ext.tree.Panel', {
        title: 'Страны СНГ',
        width: 200,
        height: 200,
        rootVisible: false,
		store: store,
        renderTo: Ext.getBody()
    });
});

Таким образом, при загрузке все узлы будут отсортированы по свойству text:

К примеру отсортируем узлы по свойству leaf:

		sorters: [{
			property: 'leaf',
			direction: 'DESC'
		}]

Динамическая сортировка

Что если нам надо сортировать данные по сигналу от другого источника, например, по нажатию кнопки. В этом случае мы можем использовать метод sort класса Ext.data.TreeStore. Этот метод принимает параметры сортировки - свойство, по которому сортируем, и направление. Добавим кнопку в приложение и определим обработчик нажатия:

var store = Ext.create('Ext.data.TreeStore', {
		root: {
			text: 'Страны СНГ',
			expanded: true,
			children:
			[{
				text: "Россия",
				children: [{
					text: "Москва",
					leaf: true
				}, {
					text: "Санкт-Петербург",
					leaf: true
				}, {
					text: "Волгоград",
					leaf: true
				}],
				leaf: false,
				"expanded": true
			},
			{
				text: "Украина",
				leaf: false
			},
			{
				text: "Белоруссия"
			}]
		}
	});
	Ext.create('Ext.Button', {
		margin:'10 0 0 30',
		text: 'Сортировать',
		renderTo: Ext.getBody(),
		handler: function(){
			store.sort('text', 'ASC');
		}
	});

	Ext.create('Ext.tree.Panel', {
		title: 'Страны СНГ',
		width: 200,
		height: 200,
		store: store,
		rootVisible: true,
		renderTo: Ext.getBody()
	});

Перенос узлов.

Ext JS 4 имеет встроенную поддержку drag-drop или ручного переноса узлов дерева как внутри самого дерева, так и между деревьями. За реализацию подобной функциональности отвечает специальный плагин Ext.tree.plugin.TreeViewDragDrop. А для его включения в панели дерева нам надо задействовать секцию viewConfig:

viewConfig: {
	plugins: {
			ptype: 'treeviewdragdrop'
	}
}

Итак, определим два дерева, в которых мы сможем перетаскивать узлы:

Ext.onReady(function(){
	var store1 = Ext.create('Ext.data.TreeStore', {
		root: {
			text:"Страны-участники",
			expanded: true,
			children: [{
			text: "Россия",
			leaf: true
			},{
			text: "Англия",
			leaf: true
			},{
			text: "Франция",
			leaf: true
			}]
		}
	});
	var tree1 = Ext.create('Ext.tree.Panel', {
		title: 'Антанта',
		store: store1,
		width: 200,
		height: 150,
		viewConfig: {
			plugins: {
				ptype: 'treeviewdragdrop'
			}
		}
	});

	var store2 = Ext.create('Ext.data.TreeStore', {
		root: {
			text:"Страны-участники",
			expanded: true,
			children: [{
				text: "Германия",
				leaf: true
			},{
				text: "Австро-Венгрия",
				leaf: true
			},{
				text: "Италия",
				leaf: true
			}]
		}
	});

	var tree2 = Ext.create('Ext.tree.Panel', {
		title: 'Тройственный Союз',
		width: 200,
		height: 150,
		store: store2,
		viewConfig: {
			plugins: {
				ptype: 'treeviewdragdrop'
			}
		}
	});
	Ext.create('Ext.panel.Panel', {
		title: 'Блоки накануне Первой мировой войны',
		width: 420,
		padding:10,
		height: 180,
		layout: {
                type: 'hbox',
                align: 'stretch'
            },
		items: [tree1, tree2],
		renderTo: Ext.getBody()
	});
});

Мы можем также более детально настроить конфигурацию переноса узлов, воспользовавшись следующими опциями:

Так, если бы мы использовали в вышеприведенном примере эти опции, то они бы имели следующие значения:

        viewConfig: {
			plugins: {
				ptype: 'treeviewdragdrop',
				enableDrop: true,
				enableDrag: true,
				allowContainerDrop: true
			}
		},

Добавление и удаление узлов дерева

Компонент Ext.panel.Panel представляет нам достаточную функциональность для добавления или удаления динамически новых узлов дерева.

В зависимости от задачи мы можем реализовать данную функциональность различными способами, используя методы компонента. Рассмотрим один из способов. Допустим, в левой части у нас определено дерево, а в правой части панель. На панели находятся кнопки для добавления и удаления. Чтобы добавить новый узел, надо сначала ввести текст узла в текстовое поле и нажать на соответствующую кнопку:

Ext.onReady(function(){
	var menustore = Ext.create('Ext.data.TreeStore', {
		root: {
			text:"Языки программирования",
			expanded: true,
			children: [{
			text: "C#",
			leaf: true
			},{
			text: "C++",
			leaf: true
			},{
			text: "Java",
			leaf: true
			}]
		}
	});
	var tree = Ext.create('Ext.tree.Panel', {
		title: 'Языки программирования',
		store: menustore,
		width: 170,
		rootVisible: false,
		region: 'west'
	});
	var centerPanel=Ext.create('Ext.panel.Panel', {
		title: 'Добавить/Удалить узел',
		region: 'center',
		bodyPadding:10,
		items:[{
            xtype: 'textfield',
			id: 'txt',
			height: 20,
         },{
			xtype: 'button',
			width:60,
			height: 20,
			text:'Добавить',
			handler: function() {
				// получаем введенное в текстовое поле значение
				var newNode=centerPanel.getComponent('txt').getValue();
				// Используем метод appendChild для добавления нового объекта
				tree.getRootNode().appendChild({
					text: newNode,
					leaf: true
				});
			}
		},{
			xtype: 'button',
			width:60,
			height: 20,
			margin: '0 0 0 20',
			text:'Удалить',
			handler: function() {
				// получаем выделенный узел для удаления
				var selectedNode=tree.getSelectionModel().getSelection()[0];
				// если таковой имеется, то удаляем
				if(selectedNode)
				{
					selectedNode.remove(true);
				}
			}
		}]
	});
	Ext.create('Ext.panel.Panel', {
		layout : 'border',
		width: 400,
		height: 180,
		padding:10,
		items : [tree, centerPanel],
		renderTo: Ext.getBody()
	});
});

Обработка выбора узла. Древовидное меню

При использовании дерева нередко возникает необходимость получить выделенный узел или произвести какие-то действия после выбора узла. В частности, на это строятся интерфейсы с помощью древовидного меню.

Обработка выбора узла дерева ложится на функцию itemclick:

itemclick : function(this, record, item, index, e, options) {}

Эта функция принимает следующие параметры:

Поэтому создадим дерево в левой части, по нажатию на узлы которого в правой части будет отображаться выбранная опция:

Ext.onReady(function(){
	var menustore = Ext.create('Ext.data.TreeStore', {
		root: {
			text:"Языки программирования",
			expanded: true,
			children: [{
			text: "C#",
			leaf: true
			},{
			text: "C++",
			leaf: true
			},{
			text: "Java",
			leaf: true
			}]
		}
	});
	var treemenu = Ext.create('Ext.tree.Panel', {
		title: 'Языки программирования',
		store: menustore,
		width: 170,
		rootVisible: false,
		region: 'west',
		listeners: {
			itemclick : function(tree, record, item, index, e, options) {
				var nodeText = record.data.text;
				centerPanel.update('<h3>Вы выбрали: '+nodeText+'</h3>');
			}
		}
	});
	var centerPanel=Ext.create('Ext.panel.Panel', {
		title: 'Выбранный язык',
		region: 'center'
	});
	Ext.create('Ext.panel.Panel', {
		layout : 'border',
		width: 400,
		height: 180,
		padding:10,
		items : [treemenu, centerPanel],
		renderTo: Ext.getBody()
	});
});

Для компонента Ext.tree.Panel мы добавляем обработчик события itemclick, которое возникает при нажатии на узел дерева. Чтобы обработать это событие, в обработчик передается ряд параметров, из которых в данном случае мы используем только параметр record. Этот параметр представляет объект Ext.data.Model и дает нам доступ к данным объекта, на котором было произведено нажатие.

Так, в строке var nodeText = record.data.text мы получаем текст нажатого узла и выводим его в html правой панели.

    Поддержать сайт на родительском проекте КГБ