jstree Enable a node and its children - javascript

I am using:
jstree("disable_node", "#" + NodeID);
to disable a node in jstree. and using:
jstree("enable_node", "#" + NodeID);
to enable a node.
Is there a simple way to disable/enable a node and it's children?
thank you

You can do it with the code as below. Check demo - Fiddle.
Write a recursive function to iterate multi-level structures
function changeStatus(node_id, changeTo) {
var node = $("#tree").jstree().get_node(node_id);
if (changeTo === 'enable') {
$("#tree").jstree().enable_node(node);
node.children.forEach(function(child_id) {
changeStatus(child_id, changeTo);
})
} else {
$("#tree").jstree().disable_node(node);
node.children.forEach(function(child_id) {
changeStatus(child_id, changeTo);
})
}
}
Call function depending on what you need
changeStatus(NodeID, 'enable');
or
changeStatus(NodeID, 'disable');

I write a simple JS function based on jstree documentation about get_node function and jstree JSON data format that enable/disable the input node and all it's child in any level:
NodeToggleEnable = function (node_id, enable) {
var tree = $("#jstree-locations");
var sub_tree = [node_id.toString()];
var index = 0;
while (index < children.length) {
var child = tree.jstree("get_node", "#" + children[index]).children;
sub_tree = sub_tree.concat(child);
if (enable == false)
tree.jstree("disable_node", "#" + sub_tree[index]);
else
tree.jstree("enable_node", "#" + sub_tree[index]);
index++;
}
}
this function uses children(array of strings or objects) property of node that selected by get_node function.

Related

How to access links within repeat control via CSJS in XPages?

In my application I display a link in a repeat control. This link will open a dialog control which displays details for a chosen row in the repeat.
Now I want to make the links appear as "read" when they are clicked.
I have defined the following function that will register the link ID clicked in a cookie and change the CSS color property of the link.
I can store the link ID in a cookie but when I try to find it in the DOM and change the CSS I fail. What am I doing wrong?
// onclick
function saveId(id) {
if ($.cookie('idCookie')) {
$.cookie('idCookie', $.cookie('idCookie') + "," + id);
} else {
$.cookie('idCookie', id);
}
}
// make all links colored
function setVisited() {
if (null != $.cookie('idCookie')) {
var idArray = $.cookie('idCookie').split(',');
console.log("#ids:" + idArray.length);
for (var x = 0; x < idArray.length; x++) {
console.log("ID: " + x + "=" + idArray[x]);
if ($('#' + idArray[x]).length) {
//link exists
$('#' + idArray[x]).css('color', 'red');
}
}
}
// assign saveId()
$(document).ready(function() {
$('a').click(function() {
saveId($(this).attr('id'));
});
setVisited();
});
The problem is that you cannot use the : in your selector as described here:
How to get the element id in repeat control
so your code must look something like this:
// onclick
function saveId(id) {
if ($.cookie('idCookie')) {
$.cookie('idCookie', $.cookie('idCookie') + "," + id);
} else {
$.cookie('idCookie', id);
}
}
// make all links colored
function setVisited() {
if (null != $.cookie('idCookie')) {
var idArray = $.cookie('idCookie').split(',');
for (var x = 0; x < idArray.length; x++) {
var link = $(document.getElementById(idArray[x])).get();
if (link.length) {
$(link).css('color', 'red');
}
}
}
}
// assign saveId()
$(document).ready(function() {
$('a').click(function() {
saveId($(this).attr('id'));
});
setVisited();
});
good luck!
You probably need to use the x$ jQuery selector as your ids contains colons: https://openntf.org/XSnippets.nsf/snippet.xsp?id=x-jquery-selector-for-xpages.

How to create an element after directive element in Angular 4

I have one directive in angularjs which is working fine but it uses jQuery and now I want tot convert it in Angular 4
Old Directive (AngularJS)
app.directive('errName', function () {
return {
link: function (scope, element, attrs) {
element.bind('error', function () {
if (attrs.src != attrs.errName) {
var name = attrs.errName.split(' ');
var attr = '?';
if (name.length == 1)
{
attr = name[0].substring(1, 0);
}
if (name.length > 1)
{
attr = name[0].substring(1, 0) + name[1].substring(1, 0);
}
$(element).hide();
$(element).after('<span class="thumb-alpha"><span class="default-thumb"><span class="default-thumb-placeholder">' + attr.toUpperCase() + '</span></span></span>');
}
});
}
}
});
it simply check there's an error in image on load then it hide that element and create one span after that I changes its name in Angular 4 to show initials I'm getting value hiding element as well but can't able to create span after that
New Directive which I try to build :
export class ShowInitialsDirective {
#Input() initials;
constructor(el: ElementRef, renderer:Renderer) {
var element = el.nativeElement
renderer.listen(el.nativeElement, 'error', (event) => {
var initial_default = '?';
var name = this.initials;
name = name.split(' ');
if (name.length == 1)
{
initial_default = name[0].substring(1, 0);
}
if (name.length > 1)
{
initial_default = name[0].substring(1, 0) + name[1].substring(1, 0);
}
this.initials = initial_default;
renderer.setElementStyle(el.nativeElement,'display','none');
// element.after('<span class="thumb-alpha"><span class="default-thumb"><span class="default-thumb-placeholder">' + this.initials.toUpperCase() + '</span></span></span>');
})
}
}
Is there any way to create span in it and put this html code in it
In Angular 2+, you should create a component when you want to change html. Components are directives with html templates. The directive you are creating here is an attribute directive. Attribute directives do not contain html templates. For more information, please refer angular website.
Sure, but you might think about rewriting it all together, and creating it into a component. If you really really don't want that, you can use the insertBefore on the parent of nativeElement, and with a little trickery:
const div: HTMLDivElement = document.createElement('div');
div.innerHTML = '<span class="thumb-alpha"><span class="default-thumb"><span class="default-thumb-placeholder">' + this.initials.toUpperCase() + '</span></span></span>';
const insert: HTMLElement = div.firstChild as HTMLElement;
const before: HTMLElement = el.nativeElement.nextElementSibling;
const parent: HTMLElement = el.nativeElement.parentElement;
if (before) {
parent.insertBefore(insert, before);
} else {
parent.appendChild(insert);
}
But again, way prettier would be to create a completely new component doing all this awesome work for you

Simplify / elegantize this code?

Here's a bit of code which works fine but I think could be simplified / shortened. It's basically clicking on a list item, getting it's id and then showing / hiding / removing elements based on the id.
Suggestions on how to simplify this with a function or loop?
$("#btn_remove_event_type").click(function() {
var selectedId = $(".selected-type").attr("id");
if (selectedId == "temperature_event") {
$("#poplist_temp").show();
$(".temperature-params").hide();
$("#temperature_event").remove();
} else if (selectedId == "load_event") {
$("#poplist_load").show();
$(".load-params").hide();
$("#load_event").remove();
} else if (selectedId == "price_event") {
$("#poplist_price").show();
$(".price-params").hide();
$("#price_event").remove();
} else if (selectedId == "duty_event") {
$("#poplist_duty").show();
$(".duty-params").hide();
$("#duty_event").remove();
} else {
$("#poplist_program").show();
$(".program-params").hide();
$("#program_event").remove();
}
});
Something like this:
$("#btn_remove_event_type").click(function() {
var selectedId = $(".selected-type").attr("id");
switch(selectedId){
case "temperature_event":
$("#poplist_temp").show();
$(".temperature-params").hide();
$("#temperature_event").remove();
break;
case "load_event":
$("#poplist_load").show();
$(".load-params").hide();
$("#load_event").remove();
break;
case "price_event":
$("#poplist_price").show();
$(".price-params").hide();
$("#price_event").remove();
break;
case "duty_event"):
$("#poplist_duty").show();
$(".duty-params").hide();
$("#duty_event").remove();
break;
default:
$("#poplist_program").show();
$(".program-params").hide();
$("#program_event").remove();
}
});
Or even better:
$("#btn_remove_event_type").click(function() {
// Get id and split on "_"
var selectedId = $(".selected-type").attr("id").split("_");
// Set array of accepted input
var options = ["temperature","load","price","duty"];
// Handle default
if(options.indexOf(selectedId[0]) == -1){
selectedId = ["program"];
}
$("#poplist_" + selectedId[0]).show();
$("."+selectedId[0] + "-params").hide();
$("#"+selectedId[0] + "_event").remove();
});
For simplicity sake I would change the id of the buttons clicked to one word(tempeature,load,price,duty). You'll have to do some renaming of your reactionary ids/classes, but just looks cleaner to me. I also flipped some of your naming around to stay consistent.
You can switch it around to match your style, it just bothered me having selectors like $("#"+id+"-params").hide();
$("#btn_remove_event_type").click(function() {
var selectedId = $(".selected-type").attr("id");
var nonDefault = ["temperature","load","price","duty"];
if(nonDefault.indexOf(selectedId) > -1){
$("#poplist_"+selectedId).show();
$(".params-"+selectedId).hide();
$("#event_"+selectedId).remove();
} else {
$("#poplist_program").show();
$(".params-program").hide();
$("#event_program").remove();
}
});
I ended up changing my classes to ids and reordering them, so I ended up with this solution which doesn't require any if statements.
$("#btn_remove_event_type").click(function() {
var selectedId = $(".selected-type").attr("id").split("_");
$("#" + selectedId[0] + "_pop").show();
$("#" + selectedId[0] + "_params").hide();
$("#" + selectedId[0] + "_event").remove();
});
If you don't want to rely on the ID names matching other element names, you can use an object as a map to specify actions.
//using a map lets you easily add or remove cases without duplicating code, and doesn't require you to use standardized names for your elements and events.
var action_map = {temperature_event:{show:"#poplist_temp",
hide:".temperature-params",
remove:"#temperature_event"
},
load_event:{show:"#poplist_load",
hide:".load-params",
remove:"#load_event",
},
price_event:{show:"#poplist_price",
hide:".price-params",
remove:"#price_event",
},
duty_event:{show:"#poplist_duty",
hide:".duty-params",
remove:"#duty_event"
},
default_event:{show:"#poplist_program",
hide:".program-params",
remove:"#duty_event",
}
};
$("#btn_remove_event_type").click(function() {
var selectedId = $(".selected-type").attr("id");
if (!action_map[selectedId])
selectedId = "default_event";
$(action_map[selectedId].show).show();
$(action_map[selectedId].hide).hide();
$(action_map[selectedId].remove).remove();
}
});
Personally the cleanest and most configurable way i can see is using a map and looping of the methods. This is generic as different mappings can have different methods. You can even extend this further so you can have a method which will construct the mappings for you.. i.e. addNewType([{methodName:selector}, etc..]).
var configuration = {
temperature_event: {
show: "#poplist_temp",
hide: ".temperature-params",
remove: "#temperature_event"
},
load_event: {
show: "#poplist_load",
hide: ".load-params",
remove: "#load_event"
}
// etc etc.
};
$("#btn_remove_event_type").click(function() {
var fn, selector, typeConfig = $(".selected-type").attr("id");
for (fn in typeConfig)
$(typeConfig[fn])[fn]();
});
});

JSON Data Not Showing In Plunker

I am having trouble getting a JSON data document to appear/input into a HTML document on Plunker.
The current JS being used:
$(document).ready(function() {
//Content Viewer Information
function checkViewers() {
//Base Variables
var viewer = $('#viewed span.user');
var totalViews = $('#viewed span.user').length;
var shortenViews = $('#viewed span.user').length -1;
if (totalViews === 0) {
$('<span> 0 people have </span>').insertBefore($('#viewed span:last-child'));
}
if (totalViews === 2) {
$('<span> and </span>').insertAfter(viewer.first());
}
if (totalViews >= 3) {
viewer.slice(1).hide();
$('<span> and </span>').insertAfter(viewer.first());
$('<span class="user count"></span>').insertAfter(viewer.eq(2));
$('.count').html(shortenViews + ' more people');
}
}
checkViewers();
//JSON Data
var xhr = new XMLHttpRequest();
xhr.onload = function() {
if (xhr.status === 200) {
responseObject = JSON.parse(xhr.responseText);
var newViewers = '';
for (var i = 0; i < responseObject.profiles.length; i++) {
newViewers += '<span class="user">' + responseObject.profiles[i].firstName + ' ';
newViewers += responseObject.profiles[i].lastName + '</span>';
}
//Update Page With New Content
var viewerSection = $('#viewed');
viewerSection.innerHTML = newViewers;
}
};
xhr.open('GET', 'data.json', true);
xhr.send(null);
console.log('JSON Fired');
});
The JSON Data should be inputted into the div #viewed with the viewers first and last name. I am not too familiar with Plunker, so I am not sure if I am going about something the wrong way within Plunker, or if a portion of the current code is causing the JSON Data to not be entered.
View the current Plunker.
The problem is you are mixing jQuery and native dom methods then getting confused about what is what
This returns a jQuery object:
var viewerSection = $('#viewed');
This is applying a property to that jQuery object that won't update the DOM since it isn't being applied to a DOM node:
viewerSection.innerHTML( newViewers);
to set the html using jQuery you need to use html() method:
viewerSection.html( newViewers);
Or to set it using native method you need to do
var viewerSection = $('#viewed')[0]; /* returns the DOM node from jQuery object */
/* or */
var viewerSection = document.getElementById('viewed');
/* then */
viewerSection.innerHTML( newViewers);
I would suggest for DOM manipulation you pick either jQuery or native javascript and stick to using one or the other and don't mix them
Working Demo Using html()

how to make the jquery function load before one ajax function finish

How do I fire one event before the previous function completed its function?
I have the following AJAX code :
var BrainyFilter = {
//...
init: function (opts) {},
changeTotalNumbers: function (data) {
jQuery(BrainyFilter.filterFormId).find('.bf-count').remove();
jQuery(BrainyFilter.filterFormId).find('option span').remove();
jQuery(BrainyFilter.filterFormId).find('select').removeAttr('disabled');
jQuery('.bf-attr-filter').not('#bf-price-container').find('input, option')
.attr('disabled', 'disabled')
.parents('.bf-attr-filter')
.addClass('bf-disabled');
if (data && data.length) {
for (var i = 0; i < data.length; i++) {
jQuery('.bf-attr-' + data[i].id + ' .bf-attr-val').each(function (ii, v) {
if (jQuery(v).text() == data[i].val) {
var parent = jQuery(v).parents('.bf-attr-filter').eq(0);
var isOption = jQuery(v).prop('tagName') == 'OPTION';
var selected = false;
if (isOption) {
jQuery(v).removeAttr('disabled');
selected = jQuery(v)[0].selected;
} else {
parent.find('input').removeAttr('disabled');
selected = parent.find('input')[0].checked;
}
parent.removeClass('bf-disabled');
if (!selected) {
if (!isOption) {
parent.find('.bf-cell').last().append('<span class="bf-count">' + data[i].c + '</span>');
} else {
jQuery(v).append('<span> (' + data[i].c + ')</span>');
}
}
}
});
}
jQuery('.bf-attr-filter input[type=checkbox]').filter(':checked')
.parents('.bf-attr-block').find('.bf-count').each(function (i, v) {
var t = '+' + jQuery(v).text();
jQuery(v).text(t);
});
// since opencart standard filters use logical OR, all the filter groups
// should have '+' if any filter was selected
if (jQuery('.bf-opencart-filters input[type=checkbox]:checked').size()) {
jQuery('.bf-opencart-filters .bf-count').each(function (i, v) {
var t = '+' + jQuery(v).text().replace('+', '');
jQuery(v).text(t);
});
}
}
// disable select box if it hasn't any active option
jQuery(BrainyFilter.filterFormId).find('select').each(function (i, v) {
if (jQuery(v).find('option').not('.bf-default,[disabled]').size() == 0) {
jQuery(v).attr('disabled', 'true');
}
});
},
//...
} // close the BrainyFilter
I also have another jQuery file running to get the bf-count value using $('.bf-count').text().
When the page load, the bf-count value is empty. Since the code above inject the bf-count, I will need to wait until it finishes the for loop in order to get the bf-count value.
What is the best way to approach this?
without knowing how the second js file is loaded, I can only give you a guesstimate suggestion.
If you want to run the second js file code after the page is fully loaded, you can wrap the code in:
jQuery(window).load(function(){
//your code here. runs after the page is fully loaded
});
jQuery documentation: http://api.jquery.com/load-event/
"The load event is sent to an element when it and all sub-elements have been completely loaded. This event can be sent to any element associated with a URL: images, scripts, frames, iframes, and the window object."

Categories

Resources