Dynatree - javascript Add Edit & Delete node - javascript

Need your help and Thanks alot in advance.
I am trying to do the Add, Edit and delete the node using Dyna tree. Following things am trying.
When i click Add button by selecting any node then new node with textbox to be added and should take node name & on blur it should set value
If no name entered then textbox should disappear from tree node.
If existing nodes then edit the node - This is working.
Some functionalities i have achieved please review below jsfiddle and help me please
Below is my jsfiddle URL , Please help
$(function(){
$("#tree").dynatree({
onActivate: function(node) {
$("#info").text("You activated " + node);
},
children: [
{title: "Item 1"},
{title: "Folder 2", isFolder: true,
children: [
{title: "Sub-item 2.1"},
{title: "Sub-item 2.2"}
]
},
{title: "Item 3"}
],selectMode: 1,
checkbox: true,
onSelect: function(select, node) {
// Display list of selected nodes
var s = node.tree.getSelectedNodes().join(", ");
selectedNode = node;
},
onClick: function(node, event) {
if( event.shiftKey ){
editNode(node);
return false;
}
},
onDblClick: function(node, event) {
editNode(node);
return false;
},
onKeydown: function(node, event) {
switch( event.which ) {
case 113: // [F2]
editNode(node);
return false;
case 13: // [enter]
if( isMac ){
editNode(node);
return false;
}
}
}
});
var nodeExists = false;
var selectedNode = null;
function validateForm(){
if( selectedNode == null){
alert("Please select node to add folder");
return false;
}
if(selectedNode != null){
nodeExists = findNodeByTitle(selectedNode,$("#newFolderName").val());
return nodeExists;
}
}
function findNodeByTitle(tree, title){
var match = true;
tree.visit(function(node){
if(node.data.title == title) {
//match = node.data.title;
alert("Folder : "+title +" already exists")
match = false;
return false;
}
}, true);
return match;
}
function editNode(node){
var prevTitle = node.data.title,
tree = node.tree;
// Disable dynatree mouse- and key handling
tree.$widget.unbind();
// Replace node with <input>
$(".dynatree-title", node.span).html("<input id='editNode' value='" + prevTitle + "'>");
// Focus <input> and bind keyboard handler
$("input#editNode")
.focus()
.keydown(function(event){
switch( event.which ) {
case 27: // [esc]
// discard changes on [esc]
$("input#editNode").val(prevTitle);
$(this).blur();
break;
case 13: // [enter]
// simulate blur to accept new value
$(this).blur();
break;
}
}).blur(function(event){
// Accept new value, when user leaves <input>
var title = $("input#editNode").val();
console.log("onblur",title);
console.log("prevTitle",prevTitle);
if(title == ''){
openChildFunction(selectedNode);
}else{
node.setTitle(title);
// Re-enable mouse and keyboard handlling
tree.$widget.bind();
node.focus();
}
});
}
$("#btnAddCode").click(function(event){
// Sample: add an hierarchic branch using code.
// This is how we would add tree nodes programatically
event.preventDefault();
var node = $("#tree").dynatree("getActiveNode");
if( validateForm()){
var rx = /[<>:"\/\\|?*\x00-\x1F]|^(?:aux|con|clock\$|nul|prn|com[1-9]|lpt[1-9])$/i;
if(rx.test($("#newFolderName").val())) {
alert("Error: Input contains invalid characters!");
return false;
}
var node = $("#tree").dynatree("getActiveNode");
var childNode = selectedNode.addChild({
title: '',
});
$(".dynatree-title", childNode.span).html("<input id='editNode' value=''>");
var dict = $("#tree").dynatree("getTree").toDict();
}
});
});
Code
Jsfiddle tried example

Add removeNode function like this to delete the selected node if its empty:
function removeNode(node){
node.remove();
}
change the blur event like this to call removeNode on empty titles:
.blur(function(event){
var title = $("input#editNode").val();
//removes the node if title is empty
if(title == ""){
removeNode(node);
tree.$widget.bind();
return;
}
....
});
finally change btnAddCode's click event like this to manage adding:
get the selected node using selectedNode = $("#tree").dynatree("getActiveNode")
add child element using addChild method
expand the parent node like this :selectedNode.expand(true)
and finally call the editNode function for newly added node
The btnAddCode's click event should look like this:
$("#btnAddCode").click(function(event){
event.preventDefault();
selectedNode = $("#tree").dynatree("getActiveNode");
if( validateForm()){
var rx = /[<>:"\/\\|?*\x00-\x1F]|^(?:aux|con|clock\$|nul|prn|com[1-9]|lpt[1-9])$/i;
if(rx.test($("#newFolderName").val())) {
alert("Error: Input contains invalid characters!");
return false;
}
var childNode = selectedNode.addChild({
title: "My new node",
tooltip: "This folder and all child nodes were added programmatically."
});
selectedNode.expand(true);
editNode(childNode);
}
});
Edit:
you should change the blur event to prevent a tree category having multiple nodes with the same title.get child list of the parent node and check if any of them except the editing node,has same title as the editing node or not,if so, let the user know and return.
so adding this code to blur event should do the trick:
var parentChilds = node.parent.childList;
var titleAvalible = false;
$.each(parentChilds,function(_index){
if(this.data.key != node.data.key && this.data.title == title){
titleAvalible = true;
}
});
if(titleAvalible){
alert("A node with same title is avalible");
return;
}
I also updated the fiddle.
hope that helps.

Related

Select2 deselect on enter press

I've implemented the select2 plugin with some customization to hide selected tags (I build them in a separated box), custom search (words between ( and ) shouldn't be in search scope) and avoid close dropdown when an element is selected or unselected.
The last features I would like to implement is that when an user use arrow keys to navigate inside dropdown and press enter on an element already selected, I would like to deselect it, and leave dropdown open.
I tried by listening all events fired by select2 but I can't deselect and prevent dropdown closing when user select the element by hit enter button on an already selected item.
But with mouse all is working fine!
var availableData = [{
"id": 38,
"text": "Test [38] (coding)"
},
{
"id": 62,
"text": "banana [62] (fruit)"
},
{
"id": 63,
"text": "apple [63] (fruit)"
},
{
"id": 65,
"text": "dog [65] (animal)"
},
];
// Init select 2
$('.js-example-basic-multiple').select2({
// Set multiple element select
multiple: true,
// Set a placeholder
placeholder: 'Select',
// It's better to set a static width, otherwise use bootstrap grids
// on container parent and set 100% width
width: '300px',
// Init plugin with data
data: availableData,
closeOnSelect: false,
templateSelection: function(ev, elem) {
// Hide selected elements
elem.hide();
},
matcher: function(params, data) {
// If there are no search terms, return all of the data
if ($.trim(params.term) === '') return data;
// Do not display the item if there is no 'text' property
if (typeof data.text === 'undefined') return null;
// Regex that exclude all what is inside ()
const regex = /^(.+)\s\[([0-9]+)\]\s\((.+)\)$/gm;
// Apply regex
var matches = data.text.matchAll(regex).next();
// If no matches, return null
if (!matches) return null;
// If no groups was found, return null
if (!matches.value || matches.value.length === 0) return null;
// If on the first group was match, return it! (name)
if (matches.value[1].toLowerCase().indexOf(
params.term.toLowerCase()
) > -1) return data;
// If on the second group was match, return it! (id)
if (matches.value[2].toLowerCase().indexOf(
params.term.toLowerCase()
) > -1) return data;
// Return `null` if the term should not be displayed
return null;
}
});
$('.js-example-basic-multiple').on('select2:select', function(e) {
console.log("=> It's me, select2:select");
});
$('.js-example-basic-multiple').on('select2:closing', function(e) {
console.log("=> It's me, select2:closing", e);
});
$('.js-example-basic-multiple').on('select2:close', function(e) {
console.log("=> It's me, select2:close", e);
});
$('.js-example-basic-multiple').on('select2:opening', function(e) {
console.log("=> It's me, select2:opening");
});
$('.js-example-basic-multiple').on('select2:open', function(e) {
console.log("=> It's me, select2:open");
});
$('.js-example-basic-multiple').on('select2:selecting', function(e) {
console.log("=> It's me, select2:selecting");
});
$('.js-example-basic-multiple').on('select2:unselecting', function(e) {
console.log("=> It's me, select2:unselecting");
});
$('.js-example-basic-multiple').on('select2:unselect', function(e) {
console.log("=> It's me, select2:unselect");
});
$('.js-example-basic-multiple').on('select2:clearing', function(e) {
console.log("=> It's me, select2:clearing");
});
$('.js-example-basic-multiple').on('select2:clear', function(e) {
console.log("=> It's me, select2:clear");
});
// Select2 event: triggered whenever an option is selected or removed.
$('.js-example-basic-multiple').on('change', function(e) {
// If almost 1 id was selected, join with ',', otherwise blank string
var ids = $(this).val() ? $(this).val().join(',') : "";
console.log("TODO: Create elements with ids: ", ids);
// Append to the paragraph
$(".the-paragraph").empty().append("Your ids: " + ids);
});
<p>This is my HTML5 Boilerplate.</p>
<p>
<div>
<select class="js-example-basic-multiple"></select>
</div>
<p class="the-paragraph"></p>
</p>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2#4.0.13/dist/js/select2.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/select2#4.0.13/dist/css/select2.min.css" rel="stylesheet" />

How to reset or unselect multi select box using jQuery?

I have one bootstrap tab and i create multi select box using jQuery and the all functions are working properly but the RESET button only not working.
i try my all ways but its waste, anyone can you help me..
Please check my full code on fiddle,
MY FULL CODE IS HERE
Just want how to reset the field using jQuery
(function($) {
function refresh_select($select) {
// Clear columns
$select.wrapper.selected.html('');
$select.wrapper.non_selected.html('');
// Get search value
if ($select.wrapper.search) {
var query = $select.wrapper.search.val();
}
var options = [];
// Find all select options
$select.find('option').each(function() {
var $option = $(this);
var value = $option.prop('value');
var label = $option.text();
var selected = $option.is(':selected');
options.push({
value: value,
label: label,
selected: selected,
element: $option,
});
});
// Loop over select options and add to the non-selected and selected columns
options.forEach(function(option) {
var $row = $('<a tabindex="0" role="button" class="item"></a>').text(option.label).data('value', option.value);
// Create clone of row and add to the selected column
if (option.selected) {
$row.addClass('selected');
var $clone = $row.clone();
// Add click handler to mark row as non-selected
$clone.click(function() {
option.element.prop('selected', false);
$select.change();
});
// Add key handler to mark row as selected and make the control accessible
$clone.keypress(function() {
if (event.keyCode === 32 || event.keyCode === 13) {
// Prevent the default action to stop scrolling when space is pressed
event.preventDefault();
option.element.prop('selected', false);
$select.change();
}
});
$select.wrapper.selected.append($clone);
}
// Add click handler to mark row as selected
$row.click(function() {
option.element.prop('selected', 'selected');
$select.change();
});
// Add key handler to mark row as selected and make the control accessible
$row.keypress(function() {
if (event.keyCode === 32 || event.keyCode === 13) {
// Prevent the default action to stop scrolling when space is pressed
event.preventDefault();
option.element.prop('selected', 'selected');
$select.change();
}
});
// Apply search filtering
if (query && query != '' && option.label.toLowerCase().indexOf(query.toLowerCase()) === -1) {
return;
}
$select.wrapper.non_selected.append($row);
});
}
$.fn.multi = function(options) {
var settings = $.extend({
'enable_search': true,
'search_placeholder': 'Search...',
}, options);
return this.each(function() {
var $select = $(this);
// Check if already initalized
if ($select.data('multijs')) {
return;
}
// Make sure multiple is enabled
if (!$select.prop('multiple')) {
return;
}
// Hide select
$select.css('display', 'none');
$select.data('multijs', true);
// Start constructing selector
var $wrapper = $('<div class="multi-wrapper">');
// Add search bar
if (settings.enable_search) {
var $search = $('<input class="search-input" type="text" />').prop('placeholder', settings.search_placeholder);
$search.on('input change keyup', function() {
refresh_select($select);
})
$wrapper.append($search);
$wrapper.search = $search;
}
// Add columns for selected and non-selected
var $non_selected = $('<div class="non-selected-wrapper">');
var $selected = $('<div class="selected-wrapper">');
$wrapper.append($non_selected);
$wrapper.append($selected);
$wrapper.non_selected = $non_selected;
$wrapper.selected = $selected;
$select.wrapper = $wrapper;
// Add multi.js wrapper after select element
$select.after($wrapper);
// Initialize selector with values from select element
refresh_select($select);
// Refresh selector when select values change
$select.change(function() {
refresh_select($select);
});
});
}
})(jQuery);
$(document).ready(function() {
$('select').multi({
search_placeholder: 'Search',
});
});
/* Reset button */
function DeselectListBox() {
var ListBoxObject = document.getElementById("firstData")
for (var i = 0; i < ListBoxObject.length; i++) {
if (ListBoxObject.options[i].selected) {
ListBoxObject.options[i].selected = false
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
You can trigger the click of your reset button and clear the whole div in your document ready function. After this you can remove the class "selected" so its completely reset.
Like this
$(document).ready(function() {
$('select').multi({
search_placeholder: 'Search',
});
$('#tabReset').click(function() {
$('.selected-wrapper').empty();
$('a').removeClass('selected');
});
});
attach an event to reset button. empty the selected-wrapper and remove the selected class from non-selected-wrapper
$("button.alltabreset").click(function(){
$(".selected-wrapper").empty();
$(".item").removeClass("selected");
});
solution: https://jsfiddle.net/zuov3wmb/

Cannot seem to add Node to Kendo UI TreeView

I was trying to add Node from textbox to the existing treeview
Input
<input id="appendNodeText" value="Node" class="k-textbox">
Button
<button type="button" class="btn btn-blue" id="addTopLevel">Add Top Level Menu</button>
javascript
<script>
// button handler
$("#addTopLevel").click(append);
handleTextBox = function (callback) {
return function (e) {
if (e.type != "keypress" || kendo.keys.ENTER == e.keyCode) {
callback(e);
}
};
};
var append = handleTextBox(function (e) {
var selectedNode = treeview.select();
console.log(selectedNode);
// passing a falsy value as the second append() parameter
// will append the new node to the root group
if (selectedNode.length == 0) {
selectedNode = null;
}
treeview.append({
text: $("#appendNodeText").val()
}, selectedNode);
});
So I end up having this click event in which it passes in "append"
To be honest I don't understand the handleTextBox , nor the append
The treeview does "work" but I wonder if it is part of the issue
var treeview = $("#treeview").kendoTreeView({
expanded: true,
dragAndDrop: true,
dataSource: homogeneous,
dataTextField: "ReportGroupName" //"name" //"id" // "FullName"
,
change: function(e) {
console.log("Change", this.select());
}
});
PER an Answer:
I tried this
$("#addTopLevel").click(function () {
console.log('in this');
if (treeview.select().length) {
console.log('1');
treeview.append({
text: $("#appendNodeText").val()
}, treeview.select());
} else {
//alert("please select tree node");
console.log('2');
}
});
console.log writes out 'in this' then '1'
So i'm not even selecting any node .... something must be wrong
here is my json
[{"Id":1,"ReportGroupName":"Standard Reports","ReportGroupNameResID":null,"SortOrder":1},{"Id":2,"ReportGroupName":"Custom Reports","ReportGroupNameResID":null,"SortOrder":2},{"Id":3,"ReportGroupName":"Retail Reports","ReportGroupNameResID":null,"SortOrder":3},{"Id":4,"ReportGroupName":"Admin Reports","ReportGroupNameResID":null,"SortOrder":5},{"Id":5,"ReportGroupName":"QA Reports","ReportGroupNameResID":null,"SortOrder":4}]
As i understood you want to append the textbox value as a node to selected node in the treeview. i have created a jsfiddle for the same with working functionality:-
http://jsfiddle.net/GHdwR/468/
click event for button:-
$("#addTopLevel").click(function() {
if (treeview.select().length) {
treeview.append({
text: $("#appendNodeText").val()
}, treeview.select());
} else {
alert("please select tree node");
}
});

Navigating (traversing) with jquery

I have a simple jq code to create autosuggestions (google like). It works fine and I just want to add keyboard events handlers. However I have some problems with it. When I want to choose the next suggestion with event 40 (arrow down) it get all the suggestions instead of just the next one. Any idea how to fix it?
$(document).ready(function(){
var people = ['Peter Bishop', 'Nicholas Brody', 'Gregory House', 'Hank Lawson', 'Tyrion Lannister', 'Nucky Thompson'];
var cache = {};
var drew = false;
$("#search").on("keyup", function(event){
var query = $("#search").val()
if($("#search").val().length){
//Check if we've searched for this term before
if(query in cache){
results = cache[query];
}
else{
//Case insensitive search for our people array
var results = $.grep(people, function(item){
return item.search(RegExp(query, "i")) != -1;
});
//Add results to cache
cache[query] = results;
}
//First search
if(drew == false){
//Create list for results
$("#search").after('<div id="res"></div>');
//Prevent redrawing/binding of list
drew = true;
//Bind click event to list elements in results
$("#res").on("click", "div", function(){
$("#search").val($(this).text());
$("#res").empty();
});
$("#search" ).keydown(function( event ) {
if ( event.which == 40 ) {
$("#search").val($(".suggestions").next().text());
}
});
}
//Clear old results
else{
$("#res").empty();
}
//Add results to the list
for(term in results){
$("#res").append("<div class = 'sugestions'>" + results[term] + "</div>");
}
}
//Handle backspace/delete so results don't remain
else if(drew){
$("#res").empty();
}
});
});
<input id="search" type="text">
You need to keep track of the currently selected suggestion. Simplest approach is probably to add/remove a className, something like this :
if(drew == false){
//Prevent redrawing/binding of list
drew = true;
//Create list for results, and bind click event to list elements in results
var $res = $('<div id="res"></div>').insertAfter("#search")
.on("click", "div", function() {
$(".suggestions").removeClass('selected');
$("#search").val($(this).addClass('selected').text());
$("#res").empty();
});
var $search = $("#search").keydown(function(event) {
var $suggestions, $selected, index;
if (event.which == 40) {
$suggestions = $(".suggestions");
$selected = $suggestions.find('.selected').eq(0);//.eq(0) shouldn't be necessary, but just in case ...
if($selected.length) {
index = ($selected.index() + 1) % $suggestions.length;//assuming the suggestions are siblings
} else {
index = 0;
}
$(".suggestions").removeClass('selected');
$search.val($(".selected").eq(index).addClass('selected').text());
}
});
} else { //Clear old results
$("#res").empty();
}
Not sure if that's 100% correct as I've had to make a couple of assumptions, but the approach should be about right.

Can't make TAB change the editor on dgrid

I'm trying to make the TAB key navigate on my dGrid. I have used as a base the solution found at Dgrid set focus on cell, but there are a couple of issues I'm running into which I couldn't solve so far.
Below you can find the block I'm using now; Not all columns have editors, so for I added a var do the element definition to select the next column instead of doing a right. I also added support for SHIFT+TAB to make backwards navigation possible. MT4.prje.grids[gridId]is the dGrid instance. There might be various on the page.
The grid is created with
MT4.prje.grids[gridId] = new (declare([OnDemandGrid, Keyboard, Selection, CellSelection]))(gridInfo, gridId);
where gridInfo has the column definitions and the store. The store is created as:
new Observable(new Memory({'data': {}, 'idProperty': 'id'}));
The editors are usually TextBox, NumberTextBox and Select dijit widgets, all set to autoSave.
aspect.after(MT4.prje.grids[gridId], "edit", function (promise, cellNode) {
if (promise === null) return;
promise.then(function (widget) {
if (!widget._editorKeypressHandle) {
widget._editorKeypressHandle = on(widget, "keypress", function (e) {
for (var rowId in MT4.prje.grids[gridId].selection) {
break;
}
for (var columnId in MT4.prje.grids[gridId].selection[rowId]) {
break;
}
if (e.charOrCode == keys.TAB) {
e.preventDefault();
var cellToEdit = null,
cellEdited = MT4.prje.grids[gridId].cell(rowId, columnId);
if (e.shiftKey) {
if (cellEdited.column.previousEditor === undefined) {
rowId = parseInt(rowId) - 1;
if (MT4.prje.grids[gridId].row(rowId).element !== null) {
for (var lastColumnId in MT4.prje.grids[gridId].columns) {}
cellToEdit = MT4.prje.grids[gridId].cell(rowId, lastColumnId);
}
} else {
cellToEdit = MT4.prje.grids[gridId].cell(rowId, cellEdited.column.previousEditor);
}
} else {
if (cellEdited.column.nextEditor === undefined) {
var firstColumnId = null;
rowId = parseInt(rowId) + 1;
if (MT4.prje.grids[gridId].row(rowId).element === null) {
var fields = {};
for (var cId in MT4.prje.grids[gridId].columns) {
if ((cId != 'excluir') && (firstColumnId === null)) {
firstColumnId = cId;
}
fields[cId] = '';
}
MT4.prje.addRowToGrid(gridId, fields);
} else {
for (var cId in MT4.prje.grids[gridId].columns) {
if (cId != 'excluir') {
firstColumnId = cId;
break;
}
}
}
cellToEdit = MT4.prje.grids[gridId].cell(rowId, firstColumnId);
} else {
cellToEdit = MT4.prje.grids[gridId].cell(rowId, cellEdited.column.nextEditor);
}
}
if (cellToEdit) {
MT4.prje.grids[gridId].deselect(cellEdited);
MT4.prje.grids[gridId].select(cellToEdit);
MT4.prje.grids[gridId].edit(cellToEdit);
}
}
});
}
});
});
Even ignoring the new line part, there are a couple of errors that happen. First of all, the editor barely pops into existence and them disappears, together with the selection. Sometimes when tabbing to an empty column, the editor will be filled with the values of the previous editor. Is there a way to do it more consistently?
What I'm figuring is that there is a race condition happening on the sharedEditor (they are set to editOn: focus). I tried wrapping the deselect/select on a dojo.on('blur') and emit it. But that doesn't get consistently correct with the dijit/form/Select widgets. Is there a better event that I can call for it?
I also tried changing the final block to:
if (cellToEdit) {
on(cellToEdit.element, 'focus', function(){
MT4.prje.grids[gridId].select(cellToEdit);
});
on(cellEdited.element, 'blur', function(){
MT4.prje.grids[gridId].deselect(cellEdited);
on.emit(cellToEdit.element, 'focus', {'bubble': true, 'cancelable': false});
});
on.emit(cellEdited.element, 'blur', {'bubble': true, 'cancelable': false});
}
But that gives two errors:
If I do make changes to a cell it does not go to the next editor. Does not even select it.
The first time I move from an empty cell to another empty cell it doesn't work either.
Anyone got any ideas?
This fix works on dgrid 0.3.11.
Add to your dgrid's postCreate.
postCreate: function() {
var that = this;
this.inherited(arguments);
this.on('dgrid-datachange', function(evt) {
that._selectedCell = that.cell(evt);
});
aspect.after(this, 'save', function(dfd) {
dfd.then(function() {
var nextCell = that.right(that.cell(that._selectedCell.row.id, that._selectedCell.column.id));
that.edit(nextCell);
// Bonus Fix. Workaround dgrid bug that blocks field text to be selected on focus.
nextCell.element.widget && nextCell.element.widget.textbox && nextCell.element.widget.textbox.select();
});
});
}

Categories