JsTree delete_node() 删除子节点
JsTree delete_node() to delete child nodes
我使用 jQuery 树插件 JSTree、PHP 和 MySQL 创建了一个树视图,并带有上下文菜单来创建、重命名和删除节点。
树视图的所有节点都取决于服务器端处理。
这是我数据库中的 table 结构:
CREATE TABLE IF NOT EXISTS `treeview_items` (
`id` int(11) NOT NULL,
`name` varchar(200) NOT NULL,
`text` varchar(200) NOT NULL,
`parent_id` varchar(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
这是我 index.html 上的 JsTree 方法(在 div 容器内)
$(document).ready(function() {
$('#tree-container').jstree({
'plugins' : ['dnd', 'state', 'contextmenu', 'json_data' , 'types', 'wholerow', 'theme', 'search', 'sort', 'changed', 'search'],
'core' : {
'data' : {
'url' : 'response.php?operation=get_node',
'data' : function (node) {
return { 'id' : node.id };
},
"dataType" : "json"
},
'check_callback' : true,
'themes' : {
'responsive' : false
}
},
'types': {
"child": {
"icon": "glyphicon glyphicon-leaf"
},
"root": {
"icon": "glyphicon glyphicon-folder-close"
},
"default": {
"icon": "glyphicon glyphicon-folder-close"
}
} // , 'contextmenu': {items: context_menu}
}).on('create_node.jstree', function (e, data) {
$.get('response.php?operation=create_node', {'id' : data.node.parent, 'text' : data.node.text})
.done(function (d) {
data.instance.set_id(data.node, d.id);
})
.fail(function () {
data.instance.refresh();
});
}).on('move_node.jstree', function (e, data) {
$.get('response.php?operation=move_node', {'id' : data.node.id, 'new_parent_id' : data.node.parent})
.done(function (d) {
// ...
// alert(data.node.parent);
data.instance.refresh();
})
.fail(function () {
data.instance.refresh();
});
}).on('rename_node.jstree', function (e, data) {
$.get('response.php?operation=rename_node', {'id' : data.node.id, 'text' : data.node.text})
.done(function (d) {
// ...
data.instance.refresh();
})
.fail(function () {
data.instance.refresh();
});
}).on('delete_node.jstree', function (e, data) {
$.get('response.php?operation=delete_node', {'id' : data.node.id})
.done(function (d) {
// ...
data.instance.refresh();
})
.fail(function () {
data.instance.refresh();
});
})
});
这是 response.php 文件,用于将节点信息更新到 mysql 数据库
<?php
// THIS IS AN EXAMPLE DATABASE CONNECTION
$servername = "localhost";
$database = "myDatabase";
$username = "root";
$password = "password";
try {
$db = new PDO("mysql:host=$servername;dbname=$database", $username, $password);
// set the PDO error mode to exception
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
/* echo "Connected successfully"; */
} catch(PDOException $e) {
/* echo "Connection failed: " . $e->getMessage() . "\n"; */
header('Location: /public/error_page');
exit;
}
$table_name = "`treeview_items`";
// CREATE, RENAME, DELETE NODE
if(isset($_GET['operation'])) {
try {
$result = null;
switch($_GET['operation']) {
case 'get_node':
$node = isset($_GET['id']) && $_GET['id'] !== '#' ? (int)$_GET['id'] : 0;
$sql = "SELECT * FROM " . $table_name;
$res = $db->prepare($sql);
$res->execute();
// Iterate on results row and create new index array of data
while($row = $res->fetch(PDO::FETCH_ASSOC)) {
$data[] = $row;
}
$itemsByReference = array();
// Build array of item references:
foreach($data as $key => &$item) {
$itemsByReference[$item['id']] = &$item;
// Children array:
$itemsByReference[$item['id']]['children'] = array();
// Empty data class (so that json_encode adds "data: {}" )
$itemsByReference[$item['id']]['data'] = new StdClass();
}
// Set items as children of the relevant parent item.
foreach($data as $key => &$item) {
if($item['parent_id'] && isset($itemsByReference[$item['parent_id']])) {
$itemsByReference [$item['parent_id']]['children'][] = &$item;
}
}
// Remove items that were added to parents elsewhere:
foreach($data as $key => &$item) {
if($item['parent_id'] && isset($itemsByReference[$item['parent_id']])) {
unset($data[$key]);
}
}
$result = $data;
break;
case 'create_node':
$node = isset($_GET['id']) && $_GET['id'] !== '#' ? (int)$_GET['id'] : -1;
if($node == -1) break;
$node_text = isset($_GET['text']) && $_GET['text'] !== '' ? $_GET['text'] : '';
$sql = "INSERT INTO " . $table_name . " (`name`, `text`, `parent_id`) VALUES('" . $node_text . "', '" . $node_text . "', '" . $node . "')";
$res = $db->prepare($sql);
$res->execute();
$result = array('id' => $db->lastInsertId());
break;
case 'move_node':
$node = isset($_GET['id']) && $_GET['id'] !== '#' ? (int)$_GET['id'] : -1;
$node_new_parent = isset($_GET['new_parent_id']) && $_GET['new_parent_id'] !== '#' ? (int)$_GET['new_parent_id'] : -1;
if($node == -1 || $node_new_parent == -1) break;
$sql ="UPDATE " . $table_name . " SET `parent_id` = '" . $node_new_parent . "' WHERE `id` = '" . $node . "'";
$res = $db->prepare($sql);
$res->execute();
break;
case 'rename_node':
$node = isset($_GET['id']) && $_GET['id'] !== '#' ? (int)$_GET['id'] : 0;
$node_text = isset($_GET['text']) && $_GET['text'] !== '' ? $_GET['text'] : '';
$sql = "UPDATE " . $table_name . " SET `name`='" . $node_text . "',`text`='" . $node_text . "' WHERE `id`= '" . $node . "'";
$res = $db->prepare($sql);
$res->execute();
break;
case 'delete_node':
$node = isset($_GET['id']) && $_GET['id'] !== '#' ? (int)$_GET['id'] : 0;
$sql ="DELETE FROM " . $table_name . " WHERE `id`= '" . $node ."'";
$res = $db->prepare($sql);
$res->execute();
break;
default:
throw new Exception('Unsupported operation: ' . $_GET['operation']);
break;
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode($result);
} catch (Exception $e) {
header($_SERVER["SERVER_PROTOCOL"] . ' 500 Server Error');
header('Status: 500 Server Error');
echo $e->getMessage();
}
die();
}
?>
例如,我创建了这个树视图结构:
img1.png
这是 phpMyAdmin 上的树视图结构:
img2.png
创建和重命名工作正常,但如果删除节点我会遇到问题
当我 select 节点删除它时,我的代码只删除 selected 节点而不是子节点。例如,如果我删除节点 "Folder 5" 我的代码只删除节点 "Folder 5" 而不是 "Folder 6" 并且当我刷新树视图时,显然,我没有得到正确的树视图,因为节点 "Folder 6" 有 "parent_id" = 18 已经不存在了。
我该如何解决这个问题?我会删除 selected 节点和所有子节点。
谢谢!抱歉我的英语不好
您可以添加一个新案例:
case 'delete_node_with_children':
$node = isset($_GET['id']) && $_GET['id'] !== '#' ? (int)$_GET['id'] : 0;
$sql = "DELETE FROM {$table_name} WHERE id = :node OR parent_id = :node";
$res = $db->prepare($sql);
$res->execute(['node' => $node]);
break;
或,作为更好的方式,我建议你使用MYSQL Trigger。
顺便说一句,你应该使用准备好的语句来避免像我的代码中那样SQL注入。更多信息:How can I prevent SQL injection in PHP?
我使用 jQuery 树插件 JSTree、PHP 和 MySQL 创建了一个树视图,并带有上下文菜单来创建、重命名和删除节点。 树视图的所有节点都取决于服务器端处理。
这是我数据库中的 table 结构:
CREATE TABLE IF NOT EXISTS `treeview_items` (
`id` int(11) NOT NULL,
`name` varchar(200) NOT NULL,
`text` varchar(200) NOT NULL,
`parent_id` varchar(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
这是我 index.html 上的 JsTree 方法(在 div 容器内)
$(document).ready(function() {
$('#tree-container').jstree({
'plugins' : ['dnd', 'state', 'contextmenu', 'json_data' , 'types', 'wholerow', 'theme', 'search', 'sort', 'changed', 'search'],
'core' : {
'data' : {
'url' : 'response.php?operation=get_node',
'data' : function (node) {
return { 'id' : node.id };
},
"dataType" : "json"
},
'check_callback' : true,
'themes' : {
'responsive' : false
}
},
'types': {
"child": {
"icon": "glyphicon glyphicon-leaf"
},
"root": {
"icon": "glyphicon glyphicon-folder-close"
},
"default": {
"icon": "glyphicon glyphicon-folder-close"
}
} // , 'contextmenu': {items: context_menu}
}).on('create_node.jstree', function (e, data) {
$.get('response.php?operation=create_node', {'id' : data.node.parent, 'text' : data.node.text})
.done(function (d) {
data.instance.set_id(data.node, d.id);
})
.fail(function () {
data.instance.refresh();
});
}).on('move_node.jstree', function (e, data) {
$.get('response.php?operation=move_node', {'id' : data.node.id, 'new_parent_id' : data.node.parent})
.done(function (d) {
// ...
// alert(data.node.parent);
data.instance.refresh();
})
.fail(function () {
data.instance.refresh();
});
}).on('rename_node.jstree', function (e, data) {
$.get('response.php?operation=rename_node', {'id' : data.node.id, 'text' : data.node.text})
.done(function (d) {
// ...
data.instance.refresh();
})
.fail(function () {
data.instance.refresh();
});
}).on('delete_node.jstree', function (e, data) {
$.get('response.php?operation=delete_node', {'id' : data.node.id})
.done(function (d) {
// ...
data.instance.refresh();
})
.fail(function () {
data.instance.refresh();
});
})
});
这是 response.php 文件,用于将节点信息更新到 mysql 数据库
<?php
// THIS IS AN EXAMPLE DATABASE CONNECTION
$servername = "localhost";
$database = "myDatabase";
$username = "root";
$password = "password";
try {
$db = new PDO("mysql:host=$servername;dbname=$database", $username, $password);
// set the PDO error mode to exception
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
/* echo "Connected successfully"; */
} catch(PDOException $e) {
/* echo "Connection failed: " . $e->getMessage() . "\n"; */
header('Location: /public/error_page');
exit;
}
$table_name = "`treeview_items`";
// CREATE, RENAME, DELETE NODE
if(isset($_GET['operation'])) {
try {
$result = null;
switch($_GET['operation']) {
case 'get_node':
$node = isset($_GET['id']) && $_GET['id'] !== '#' ? (int)$_GET['id'] : 0;
$sql = "SELECT * FROM " . $table_name;
$res = $db->prepare($sql);
$res->execute();
// Iterate on results row and create new index array of data
while($row = $res->fetch(PDO::FETCH_ASSOC)) {
$data[] = $row;
}
$itemsByReference = array();
// Build array of item references:
foreach($data as $key => &$item) {
$itemsByReference[$item['id']] = &$item;
// Children array:
$itemsByReference[$item['id']]['children'] = array();
// Empty data class (so that json_encode adds "data: {}" )
$itemsByReference[$item['id']]['data'] = new StdClass();
}
// Set items as children of the relevant parent item.
foreach($data as $key => &$item) {
if($item['parent_id'] && isset($itemsByReference[$item['parent_id']])) {
$itemsByReference [$item['parent_id']]['children'][] = &$item;
}
}
// Remove items that were added to parents elsewhere:
foreach($data as $key => &$item) {
if($item['parent_id'] && isset($itemsByReference[$item['parent_id']])) {
unset($data[$key]);
}
}
$result = $data;
break;
case 'create_node':
$node = isset($_GET['id']) && $_GET['id'] !== '#' ? (int)$_GET['id'] : -1;
if($node == -1) break;
$node_text = isset($_GET['text']) && $_GET['text'] !== '' ? $_GET['text'] : '';
$sql = "INSERT INTO " . $table_name . " (`name`, `text`, `parent_id`) VALUES('" . $node_text . "', '" . $node_text . "', '" . $node . "')";
$res = $db->prepare($sql);
$res->execute();
$result = array('id' => $db->lastInsertId());
break;
case 'move_node':
$node = isset($_GET['id']) && $_GET['id'] !== '#' ? (int)$_GET['id'] : -1;
$node_new_parent = isset($_GET['new_parent_id']) && $_GET['new_parent_id'] !== '#' ? (int)$_GET['new_parent_id'] : -1;
if($node == -1 || $node_new_parent == -1) break;
$sql ="UPDATE " . $table_name . " SET `parent_id` = '" . $node_new_parent . "' WHERE `id` = '" . $node . "'";
$res = $db->prepare($sql);
$res->execute();
break;
case 'rename_node':
$node = isset($_GET['id']) && $_GET['id'] !== '#' ? (int)$_GET['id'] : 0;
$node_text = isset($_GET['text']) && $_GET['text'] !== '' ? $_GET['text'] : '';
$sql = "UPDATE " . $table_name . " SET `name`='" . $node_text . "',`text`='" . $node_text . "' WHERE `id`= '" . $node . "'";
$res = $db->prepare($sql);
$res->execute();
break;
case 'delete_node':
$node = isset($_GET['id']) && $_GET['id'] !== '#' ? (int)$_GET['id'] : 0;
$sql ="DELETE FROM " . $table_name . " WHERE `id`= '" . $node ."'";
$res = $db->prepare($sql);
$res->execute();
break;
default:
throw new Exception('Unsupported operation: ' . $_GET['operation']);
break;
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode($result);
} catch (Exception $e) {
header($_SERVER["SERVER_PROTOCOL"] . ' 500 Server Error');
header('Status: 500 Server Error');
echo $e->getMessage();
}
die();
}
?>
例如,我创建了这个树视图结构:
img1.png
这是 phpMyAdmin 上的树视图结构:
img2.png
创建和重命名工作正常,但如果删除节点我会遇到问题
当我 select 节点删除它时,我的代码只删除 selected 节点而不是子节点。例如,如果我删除节点 "Folder 5" 我的代码只删除节点 "Folder 5" 而不是 "Folder 6" 并且当我刷新树视图时,显然,我没有得到正确的树视图,因为节点 "Folder 6" 有 "parent_id" = 18 已经不存在了。
我该如何解决这个问题?我会删除 selected 节点和所有子节点。
谢谢!抱歉我的英语不好
您可以添加一个新案例:
case 'delete_node_with_children':
$node = isset($_GET['id']) && $_GET['id'] !== '#' ? (int)$_GET['id'] : 0;
$sql = "DELETE FROM {$table_name} WHERE id = :node OR parent_id = :node";
$res = $db->prepare($sql);
$res->execute(['node' => $node]);
break;
或,作为更好的方式,我建议你使用MYSQL Trigger。
顺便说一句,你应该使用准备好的语句来避免像我的代码中那样SQL注入。更多信息:How can I prevent SQL injection in PHP?