Cannot seem to add Node to Kendo UI TreeView - javascript

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");
}
});

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" />

What is the simplest way of marking my "To-do" as complete?

I have a fiddle here: https://jsfiddle.net/419r62t8/1/
View.prototype.render = function (viewCmd, parameter) {
var that = this;
var viewCommands = {
showEntries: function () {
that.$todoList.innerHTML = that.template.show(parameter);
},
removeItem: function () {
that._removeItem(parameter);
},
updateElementCount: function () {
that.$todoItemCounter.innerHTML = that.template.itemCounter(parameter);
},
contentBlockVisibility: function () {
that.$main.style.display = that.$footer.style.display = parameter.visible ? 'block' : 'none';
},
setFilter: function () {
that._setFilter(parameter);
},
clearNewTodo: function () {
that.$newTodo.value = '';
},
editItem: function () {
that._editItem(parameter.id, parameter.title);
},
editItemDone: function () {
that._editItemDone(parameter.id, parameter.title);
}
};
viewCommands[viewCmd]();
};
View.prototype._itemId = function (element) {
var li = $parent(element, 'li');
return parseInt(li.dataset.id, 10);
};
View.prototype._bindItemEditDone = function (handler) {
var that = this;
$live('#todo-list li .edit', 'blur', function () {
if (!this.dataset.iscanceled) {
handler({
id: that._itemId(this),
title: this.value
});
}
});
$live('#todo-list li .edit', 'keypress', function (event) {
if (event.keyCode === that.ENTER_KEY) {
// Remove the cursor from the input when you hit enter just like if it
// were a real form
this.blur();
}
});
};
View.prototype._bindItemEditCancel = function (handler) {
var that = this;
$live('#todo-list li .edit', 'keyup', function (event) {
if (event.keyCode === that.ESCAPE_KEY) {
this.dataset.iscanceled = true;
this.blur();
handler({id: that._itemId(this)});
}
});
};
View.prototype.bind = function (event, handler) {
var that = this;
if (event === 'newTodo') {
$on(that.$newTodo, 'change', function () {
handler(that.$newTodo.value);
});
} else if (event === 'itemEdit') {
$live('#todo-list li label', 'dblclick', function () {
handler({id: that._itemId(this)});
});
} else if (event === 'itemRemove') {
$live('#todo-list .destroy', 'click', function () {
handler({id: that._itemId(this)});
});
} else if (event === 'itemEditDone') {
that._bindItemEditDone(handler);
} else if (event === 'itemEditCancel') {
that._bindItemEditCancel(handler);
} else if (even === 'itemComplete') {
that._bindItemComplete(handler);
}
};
EDIT: I am thinking I can bind a new function here to add an strike-through to the "completed" items on the todo list. Completing them on single click or by adding a checkbox for completing it.
I've got the CSS but I'm lacking the JS to tie it all together.
I am attempting to create a simple strike through on-click to show when an item has been marked as completed. Any help would be much appreciated.
You're close with the CSS, but the best bet is to replace the checkbox with an image (svg if you can) when it is checked.
text-decoration: line-through will not help here -- this only works with text.
Often the checkbox's label will get the image and the checkbox itself will be hidden (a label can be clicked and perform the same actions as the input/checkbox itself)
Check this Answer out and see if it'll help you along your path:
Pure CSS Checkbox Image replacement
Try adding a jquery event listener to the id of the checkbox. Tell id to toggle the css on click and you should be good to go. Do you know how to achieve that?

.on("DOMNodeInserted", function(e){, e.currentTarget is always #document

I'm in the process of updating a 2-year old application and part of that application has the following:
function setupListener(currentXmlHttpRequests){
debugger;
$(document).unbind("DOMNodeInserted");
$(document).bind("DOMNodeInserted", function(e){
debugger;
console.log(e.currentTarget.id);
if(e.target.id=="page-bottom"){
refreshFilterList("Last 6 Months Of Launches");
refreshQuickJump(filtered);
$("#mySelect").on('change', function() {
var val = this.value;
if(val == "")
return;
document.getElementById(val).scrollIntoView();
var element = document.getElementById('mySelect');
element.value = "";
});
$("#datacenter").SumoSelect({placeholder: "All Datacenters"});
$("#year").SumoSelect({placeholder: "All Years"});
$("#platform").SumoSelect({placeholder: "All Platforms"});
$("#tech").SumoSelect({placeholder: "No Technologies"});
$("#tech")[0].sumo.selectItem(1);
$("#tech")[0].sumo.selectItem(2);
$("#tech")[0].sumo.selectItem(3);
$("#version").SumoSelect({placeholder: "All Versions"});
$("#query").keyup(function(e) {
if(e.keyCode == 13) {
setFilters();
changeURL(scriptName);
if(checkFiltersDefault())
loadDefault();
else
filter(filteredServiceNames[env], true);
refresh(currentXmlHttpRequests);
}
});
$("#search").on("click", function(){
setFilters();
changeURL(scriptName);
if(checkFiltersDefault())
loadDefault();
else
filter(filteredServiceNames[env], true);
refresh(currentXmlHttpRequests);
});
$("#clear").on("click", function(){
clearFilters();
changeURL(scriptName);
loadDefault();
refresh(currentXmlHttpRequests);
});
}
});
}
But when this is entered, e.currentTarget is always #document and e.target.id is always blank. This results in the listeners never being applied.
page-bottom is setup in another method before this one:
function setupLast(dashboard) {
dashboard.rows.push({
title: 'Chart',
height: 25,
editable: false,
panels: [{
title: ' ',
type: 'text',
span: 0,
mode: 'html',
content: "<!DOCTYPE html><html><body><div id=\"page-bottom\" style=clear:both></div></body></html>",
height: 25,
transparent: true,
id: -1
}]
});
}
The guy who wrote this originally inserted this div as a way for us to watch for when the page has finished loading. His old docs have:
Most dashboards have an invisible panel that is added at the end of
the dashboard for the purpose of knowing when it is safe to perform
jquery event binding, among other things. This works by using jquery's
'DOMNodeInsert' event to wait for the div inside the panel to be added
to the page.
I'm not exactly sure what the issue is - if maybe when the base application was upgraded (2 years worth of upgrades) it upgraded the jquery version, or if I'm just missing something. I can see that page-bottom does actually end up in the page. When the page loads though, these listener setups never get executed.
I would just do away with that div detection mechanism and use the jQuery api method:
$(document).ready(function() {
refreshFilterList("Last 6 Months Of Launches");
refreshQuickJump(filtered);
$("#mySelect").on('change', function() {
var val = this.value;
if(val == "")
return;
document.getElementById(val).scrollIntoView();
var element = document.getElementById('mySelect');
element.value = "";
});
$("#datacenter").SumoSelect({placeholder: "All Datacenters"});
$("#year").SumoSelect({placeholder: "All Years"});
$("#platform").SumoSelect({placeholder: "All Platforms"});
$("#tech").SumoSelect({placeholder: "No Technologies"});
$("#tech")[0].sumo.selectItem(1);
$("#tech")[0].sumo.selectItem(2);
$("#tech")[0].sumo.selectItem(3);
$("#version").SumoSelect({placeholder: "All Versions"});
$("#query").keyup(function(e) {
if(e.keyCode == 13) {
setFilters();
changeURL(scriptName);
if(checkFiltersDefault())
loadDefault();
else
filter(filteredServiceNames[env], true);
refresh(currentXmlHttpRequests);
}
});
$("#search").on("click", function(){
setFilters();
changeURL(scriptName);
if(checkFiltersDefault())
loadDefault();
else
filter(filteredServiceNames[env], true);
refresh(currentXmlHttpRequests);
});
$("#clear").on("click", function(){
clearFilters();
changeURL(scriptName);
loadDefault();
refresh(currentXmlHttpRequests);
});
});
Try using e.target instead of currentTarget

Dynatree - javascript Add Edit & Delete node

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.

Filtering html fields with jQuery

I have read about filtering table plugins. What I'm searching for is like this popup window.
(source: staticflickr.com)
When the user starts typing in the search-box, the relevant channel/category (as selected on previous dropdown box) should filter up. Also some animated loading action should happen while the filter process is going on.
I am looking for jQuery plugins which will make my filter-job easier to implement.
I think it is to ambigous to have a plugin for it. Just do something like this:
function filter($rows, category, search) {
$rows.each(function() {
if (category == ($("td:eq(2)", this).text() || category == "all") && (search. === "" || $("td:eq(1)", this).text().indexOf(search) !== -1) {
$(":checkbox", this).removeAttr("disabled");
$(this).show();
}
else
$(this).hide(function(){
$(":checkbox", this).attr("disabled", "disabled");
});
});
}
$("select.category").change(function() {
filter ($(this).closest("form").find("tr"), $(this).val(), $(this).closest("form").find("input.search").val());
});
$("input.search").keyUp(function() {
filter ($(this).closest("form").find("tr"), $(this).closest("form").find("select.catagory").val(), $(this).val());
});
You may need to make a few adjustments in order to make it work with the exact format of html.
Update to make it into a PLUGIN
$.fn.filter_table = function(options) {
options = $.extend(options, {
show: $.noop(), //Callback when a row get shown
hide: $.noop(), // Callback when a row gets hidden
entries: "table tr", // Selector of items to filter.
map: {} //Required parameter
//TODO Add default ajustment parameters here to remove ambiguity and assumptions.
});
return this.each(function() {
var form = this;
function each(callback) {
for (var selector in options.map) {
var check = options.map[selector];
$(selector, form).each(function(){
callback.call(this, check);
});
}
}
function show(row) {
if (!$(row).is(":visible")) {
options.show.apply(row);
$(row).show();
}
}
function hide(row) {
if ($(row).is(":visible"))
$(row).hide(options.hide);
}
function run_filter() {
$(options.entries, form).each(function() {
var row = this, matched = true;
each(function(check) {
matched &= check.call(this, row);
});
matched ? show(this) : hide(this);
})
}
//Bind event handlers:
each(function() {
$(this).bind($(this).is(":text") ? "keyup" : "change", run_filter);
});
});
};
You can use this plugin as follows:
$("form").filter_table({
map: {
//These callback define if a row was matched:
"select.category": function(row) {
//this refers to the field, row refers to the row being checked.
return $(this).val() == "all" || $(this).val() == $("td:eq(2)", row).text();
},
"input.search": function(row) {
return $(this).val() == "" || $(this).val() == $("td:eq(1)", row).text();
}
},
entries: "tr:has(:checkbox)", //Filter all rows that contain a checkbox.
show: function() {
$(":checkbox", this).removeAttr("disabled");
},
hide: function() {
$(":checkbox", this).attr("disabled", "disabled");
}
});
Okay it should work once it was debugged. I haven't tested it. I think that part is up to you.
If your HTML looks like this:
<form id="filterForm">
<input type="text" id="filterBox">
<input type="submit" value="Filter">
</form>
<div id="checkboxContainer">
<label><input type="checkbox" id="checkbox123"> Checkbox 123</label>
</div>
You could do something like...
//Set variables so we only have to find each element once
var filterForm = $('#filterForm');
var filterBox = $('#filterBox');
var checkboxContainer = $('#checkboxContainer');
//Override the form submission
filterForm.submit(function() {
//Filter by what the label contains
checkboxContainer.find('label').each(function() {
//If the value of filterBox is NOT in the label
if ($(this).indexOf(filterBox.val()) == -1) {
//Hide the label (and the checkbox since it's inside the label)
$(this).hide();
} else {
//Show it in case it was hidden before
$(this).show();
}
});
//Prevent the form from submitting
return false;
});
You can use this tablesorterfilter plugin to achieve what you need
Working Fiddle
And also please have a look at http://datatables.net/
There are many options out there. Here is a good place to start: http://www.wokay.com/technology/32-useful-jquery-filter-and-sort-data-plugins-62033.html
Filtering like this isn't incredibly complicated. It may be worth looking at the source of a couple plugins that come close to what you want and then try to write your own. You'll learn a lot more if you do it yourself!

Categories