JSTree: move all child nodes - javascript

I'm using JSTree, and this is my setup for the contextmenu plugin:
"contextmenu":{
"items": function($node) {
return {
"Remove": {
"separator_before": false,
"separator_after": false,
"label": "Delete group",
"action": function (obj) {
$tree.jstree("get_children_dom", $node).each(function(child){
$tree.jstree("move_node", $tree.jstree("get_node", child, true), "#", "last", function(node, parent, pos){
alert(1);
});
});
$tree.jstree("delete_node", $node);
}
}
};
}
}
basically, I want the children of the group that's being deleted to be moved upwards. The function I've currently got should place the nodes at the end, but how can I place them on the deleted node's place? Also, the current code doesn't work - what am I doing wrong?
Last but not least, how can I check the node type before removing?
Thanks in advance

basically, I want the children of the group that's being deleted to be moved upwards.
If by upwards you mean get into the position of the node that got deleted, check the following example:
var data = [{
'text': 'item 1',
'children': [{
text: 'item 1-1',
children: [{
text: 'item 1-1-1',
children: [{
text: 'item 1-1-1-1'
}, {
text: 'item 1-1-1-2'
}]
}, {
text: 'item 1-1-2'
}, {
text: 'item 1-1-3'
}]
}, {
text: 'item 1-2',
children: [{
text: 'item 1-2-1'
}, {
text: 'item 1-2-2'
}]
}, {
text: 'item 1-3',
children: [{
text: 'item 1-3-1'
}, {
text: 'item 1-3-2'
}]
}, {
text: 'item 1-4',
children: [{
text: 'item 1-4-1'
}, {
text: 'item 1-4-2'
}]
}]
}, {
'text': 'item 2',
children: [{
text: 'item 2-1',
children: [{
text: 'item 2-1-1'
}, {
text: 'item 2-1-2'
}]
}, {
text: 'item 2-2',
children: [{
text: 'item 2-2-1'
}, {
text: 'item 2-2-1'
}]
}, {
text: 'item 2-3'
}]
}, {
'text': 'item 3',
children: [{
text: 'item 3-1',
children: [{
text: 'item 3-1-1'
}, {
text: 'item 3-1-2'
}]
}, {
text: 'item 3-2'
}]
}, {
'text': 'item 4 (you cannot delete this one)',
'disableDelete': true,
children: [{
text: 'item 4-1'
}, {
text: 'item 4-2'
}, {
text: 'item 4-3'
}]
}];
var $tree = $('#jstree_demo').jstree({
'plugins': ['contextmenu'],
'core': {
'animation': 0,
'check_callback': true,
'themes': {
'stripes': true
},
'data': data
},
'contextmenu': {
'items': function($node) {
return {
'Remove': {
'separator_before': false,
'separator_after': false,
'label': 'Delete group',
'action': function(obj) {
if ($node.original.disableDelete) {
document.write('deletion is forbidden for this node');
return;
}
var nodes = $node.children.slice(0); // jstree behaves erratic if we try to move using $node.children directly, so we will clone the array to prevent this issue
var $row = $(obj.reference[0].closest('li'));
$tree.jstree('move_node', nodes, $node.parent, $row.index());
$tree.jstree('delete_node', $node);
}
}
};
}
}
});
<div id="jstree_demo"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css">
Last but not least, how can I check the node type before removing?
I´ve added a small sample to show you how you can accomplish it. Check the declaration of a custom attribute disableDeletion to a node:
var data = [{'text': 'item 4 (you cannot delete this one)', 'disableDelete': true}]
And the validation in the context menu action:
if ($node.original.disableDelete) {
document.write('deletion is forbidden for this node');
return;
}

Related

Bootstrap-table Toggle Column with colspan=1

When a grouped header (aka nested) has 1 nested level (like "Price" and "Total" in the example) there is a strange behaviour: I would expect a way to hide the whole column, yet when I hide "Total", "Price" remains visible. Is there a way to hide that?
You can see it works fine in case the 2nd level header has more than 1 element: I hide "Id" and "Name" and "Key" is automatically hidden.
https://live.bootstrap-table.com/code/antonioaltamura/6940
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table#1.19.1/dist/bootstrap-table.min.css">
<script src="https://unpkg.com/bootstrap-table#1.19.1/dist/bootstrap-table.min.js"></script>
<table id="table" border=1>
</table>
<button onclick="togglePrice()">
togglePrice
</button>
<button onclick="toggleKey()">
toggleKey
</button>
<script>
var $table = $('#table')
var priceVisible = true;
var keyVisible = true;
$(function() {
var data = [
{
'id': 0,
'name': 'Item 0',
'price': '$0'
},
{
'id': 1,
'name': 'Item 1',
'price': '$1'
},
{
'id': 2,
'name': 'Item 2',
'price': '$2'
},
{
'id': 3,
'name': 'Item 3',
'price': '$3'
},
{
'id': 4,
'name': 'Item 4',
'price': '$4'
},
{
'id': 5,
'name': 'Item 5',
'price': '$5'
}
]
$table.bootstrapTable({
data: data,
columns: [
[
{
title: "Key",
colspan:2
},
{
title: "Price",
field: "h_price"
},
],
[
{title: "Id", field:"id"},
{title: "Name", field:"name"},
{title: "Total", field:"price"}
]
]})
})
function togglePrice() {
$table.bootstrapTable(priceVisible ? "hideColumn" : "showColumn", "price")
priceVisible = !priceVisible
}
function toggleKey() {
$table.bootstrapTable(keyVisible ? "hideColumn" : "showColumn", "id")
$table.bootstrapTable(keyVisible ? "hideColumn" : "showColumn", "name")
keyVisible = !keyVisible
}
</script>

Extjs - Tree Panel collapse and expand based on condition

I want to collapse or expand a node based on a condition in tree.panel in extjs 4.2.1
tree.on("beforeitemexpand",function(node) {
if (booleanFlag === true) {
//allow to expand
} else {
//donot allow to expand
}
});
I have tried the beforeitemExpand then return false if booleanFlag is false, but it is not working.
The event "beforeitemexpand" appears to have a bug in Extjs 4.2.1, its not ideal but you could use "beforeitemclick" and "beforeitemdblclick" to achieve the functionality that you want:
Ext.application({
name: 'Fiddle',
launch: function () {
var enableHomeExpand = false;
var enableBookExpand = false;
var store = Ext.create('Ext.data.TreeStore', {
root: {
children: [{
text: 'homework',
expanded: false,
children: [{
text: 'book report',
children: [{
text: 'test',
leaf: true
}, {
text: 'test 2',
leaf: true
}]
}, {
text: 'algebra',
leaf: true
}]
}, {
text: 'homework',
children: [{
text: 'book report',
children: [{
text: 'test',
leaf: true
}, {
text: 'test 2',
leaf: true
}]
}]
}]
}
});
var handleClick = function (node,rec,item){
if ((rec.data.text =="book report")&&(enableBookExpand)){
return true;
}
if ((rec.data.text =="homework")&&(enableHomeExpand)){
return true;
}
return false;
}
var treepanel = Ext.create('Ext.tree.Panel', {
title: 'Simple Tree',
width: 400,
height: 200,
store: store,
rootVisible: false,
renderTo: Ext.getBody(),
listeners:{
beforeitemdblclick: handleClick,
beforeitemclick: handleClick
},
buttons:[{
text:'Enable Expand "homework"',
handler: function(){ enableHomeExpand = true; }
},
{
text:'Enable Expand "book report"',
handler: function(){ enableBookExpand = true; }
}]
});
}
});
Here is the FIDDLE

Sencha 6.5 (modern) how to dynamically change the items in a menu in a title bar?

Well considering a grid I create in my application:
{
xtype: 'ordergrid',
itemId: 'ordergrid',
titleBar: {
shadow: false,
items: [{
align: 'right',
xtype: 'button',
text: 'Update status',
stretchMenu: true,
menu: {
itemId: 'status_menu',
defaults: {
handler: 'updateStatus'
},
indented: false,
items: [{
text: 'test1',
value: 'test1'
}, {
text: 'test2',
value: 'test2'
}, {
text: 'test3',
value: 'test4'
}]
}
}]
},
With ordergrid being defined with:
extend: 'Ext.grid.Grid',
xtype: 'ordergrid',
I wish to modify the items of the menu dynamically. I've first tried doing this through a store:
menu: {
itemId: 'status_menu',
defaults: {
handler: 'updateStatus'
},
indented: false,
store: { type: 'status' }
Though this doesn't seem to work. Then I tried accessing this menu through a component query, during the init function of some controller:
Ext.define('BinkPortalFrontend.view.main.OrderController', {
extend: 'Ext.app.ViewController',
alias: 'controller.order',
init: function () {
console.log('..... initializing ......');
const menus = Ext.ComponentQuery.query('ordergrid #status_menu');
const menu = menus[0];
menu.setItems([{
text: 'some',
value: 'some'
}, {
text: 'new',
value: 'mew'
}]);
},
};
However this returns an error: "Cannot read property 'setItems' of undefined"
Debugging shows the obvious problem: it doesn't find any menu.
What's more, even a "catch all" query like
Ext.ComponentQuery.query('menu');
or
Ext.ComponentQuery.query('#status_menu');
Shows an empty array: so what's going on? (I most definitely see the menu from its initial load).
There is one reason your menu is not created. Menu will created whenever button will tap or whenever getMenu() method get called.
If you want to get your menu using Ext.ComponentQuery.query(), so for this you need to do use initialize event of button and forcefully create menu using getMenu() method like below :-
{
xtype: 'button',
text: 'Update status',
stretchMenu: true,
menu: {
itemId: 'status_menu',
indented: false,
items: [{
text: 'test1',
value: 'test1'
}, {
text: 'test2',
value: 'test2'
}, {
text: 'test3',
value: 'test4'
}]
},
listeners: {
initialize: function(btn) {
Ext.defer(function() {
// This will print undefined because menu have not created
console.log(Ext.ComponentQuery.query('#status_menu')[0]);
//When we use getMenu method it will create menu item
btn.getMenu().hide();
// This will print menu component
console.log(Ext.ComponentQuery.query('#status_menu')[0]);
}, 10)
}
}
}
Another way you can use getMenu() method of button. It will return the menu component.
In this FIDDLE, I have created a demo using grid, button and menu. I hope this will help/guide you to achieve your requirement.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
var store = Ext.create('Ext.data.Store', {
fields: ['name', 'email', 'phone'],
data: [{
'name': 'Lisa',
"email": "lisa#simpsons.com",
"phone": "555-111-1224"
}, {
'name': 'Bart',
"email": "bart#simpsons.com",
"phone": "555-222-1234"
}, {
'name': 'Homer',
"email": "home#simpsons.com",
"phone": "555-222-1244"
}, {
'name': 'Marge',
"email": "marge#simpsons.com",
"phone": "555-222-1254"
}]
});
Ext.create('Ext.grid.Grid', {
title: 'Change menu items dynamically',
titleBar: {
shadow: false,
items: [{
align: 'right',
xtype: 'button',
text: 'Update status',
stretchMenu: true,
itemId: 'statusbtn',
menu: {
itemId: 'status_menu',
defaults: {
// handler: 'updateStatus'
},
indented: false,
items: [{
text: 'test1',
value: 'test1'
}, {
text: 'test2',
value: 'test2'
}, {
text: 'test3',
value: 'test4'
}]
},
listeners: {
initialize: function (btn) {
Ext.defer(function () {
// This will undefined because menu has not been created
console.log(Ext.ComponentQuery.query('#status_menu')[0]);
//When we use getMenu method it will create menu item
btn.getMenu().hide();
// This will menu component
console.log(Ext.ComponentQuery.query('#status_menu')[0]);
}, 10)
}
}
}, {
xtype: 'button',
align: 'right',
text: 'Change Items',
handler: function (btn) {
var newItems = [];
store.each(rec => {
newItems.push({
text: rec.get('name'),
value: rec.get('name')
})
});
/*
* You can also get menu using button
* btn.up('titlebar').down('#statusbtn').getMenu().setItems(newItems);
*/
Ext.ComponentQuery.query('#status_menu')[0].setItems(newItems);
Ext.toast('Menu items has been change. Please check', 2000);
}
}]
},
store: store,
columns: [{
text: 'Name',
dataIndex: 'name',
width: 200
}, {
text: 'Email',
dataIndex: 'email',
width: 250
}, {
text: 'Phone',
dataIndex: 'phone',
width: 120
}],
height: 200,
layout: 'fit',
fullscreen: true
});
}
});
For more details about component you can also see this ComponentManager

How to remove treeview child node using jquery

I have a treeview like below, i need to remove one child from the list based on the user. Can any one tell me how to remove the child from the treeview.
var treedata = [
{
label: 'Floor', type: 'Country',
children: [
{
label: 'Bangalore', type: 'Location',
children: [{ label: 'Technopolis', type: 'facility', id: 1 }, { label: 'Ecity Tower-2', type: 'facility', id: 2 }, { label: 'Bagmane', type: 'facility', id: 3 }, { label: 'Cyber Park', type: 'facility', id: 4 }]
},
{
label: 'Hyderabad', type: 'Location',
children: [{ label: 'Hitech City ', type: 'facility', id: 5 }, { label: 'Cyber City', type: 'facility', id: 6 }]
},
{
label: 'Chennai', type: 'Location',
children: [{ label: 'XXX', type: 'facility', id: 7 }]
},
{
label: 'Mumbai', type: 'facility', id: 8
}
]
},
{
label: 'Role Administration', type: 'Role',
children: [{ label: 'Assign Role', type: 'Role', id: 1 }]
},
{
label: 'Hoteling Admin', type: 'Hoteling',
children: [{ label: 'Hoteling', type: 'Hoteling', id: 1 }]
}
];
The above is my jquery tree data. I want to remove the role administration if the user is a normal user by checking the user role.
Anyone help me how to do using jquery.
Thanks
You can use $.grep() to filter the array to a new array based on whatever conditions you want.
var userRole='normal';
if( userRole === 'normal'){
treeview = $.grep(treeview, function(item){
return item.label != 'Role Administration';
});
}
grep() API docs

Working with subset of Angular JS model

Here is my model:
var nav = [{
label: 'Pages',
value: '#',
toggle: 'dropdown', // set this to '' when the menu has no children
children: [{
label: 'Home',
value: 'home'
}, {
label: 'Left Nav',
value: 'leftnav'
}, {
label: 'Two-Panel Selector',
value: 'two_panel_selector'
}]
}, {
label: 'Components',
value: '#',
toggle: 'dropdown',
children: [{
label: 'Lists & Tables',
value: 'lists_tables'
}]
}, {
label: 'Elements',
value: '#',
toggle: 'dropdown',
children: [{
label: 'Text',
value: 'elements?section=Text'
}, {
label: 'Buttons',
value: 'elements?section=Buttons'
}, {
label: 'Alerts',
value: 'elements?section=Alerts'
}, {
label: 'Inputs',
value: 'elements?section=Inputs'
}, {
label: 'Icons',
value: 'elements?section=Icons'
}, {
label: 'Sample Grid',
value: 'elements?section=Grid'
}, ]
}];
return {
getNavData: function() {
return nav;
}
};
I would like to work with the "Elements" children in a list. This works fine, but I am wondering if there's a way without using the array index as I have done:
div class="list-group">
<a class="list-group-item" ng-repeat="l in navData[2].children" ng-class="{'active': l.label == submenu}" ng-click="select(l.label)">{{l.label}}</a>
</div>
You could search for the element in your array like this:
<a ng-repeat="l in elementsChildren()"></a>
and in your controller:
$scope.elementsChildren() = function() {
for(var i = 0; i < nav.length; i++) {
if (nav[i].label === 'Elements')
return nav[i].children;
return [];
}
This means that if 'Elements' is moved within the array, your view won't break. However, this is more expensive. You will now be iterating over the array to find 'elements' (O(n)), as opposed to indexing directly into your array (O(1)).

Categories

Resources