Open one node and all its parents using jstree - jstree

I'm trying to use jstree and let one node and all its parent be opened when the page is opened. Here is the html code I used to test.
<div id="treeTask">
<ul>
<li id="node_37">TEST1
<ul>
<li id="node_38">TEST2</li>
<li id="node_39">TEST3</li>
</ul>
</li>
</ul>
<ul>
<li id="node_3">TEST1
<ul>
<li id="node_4">TEST2</li>
<li id="node_6">TEST3</li>
</ul>
</li>
</ul>
</div>
And here is the call to initialize jstree and open the node.
$(function () {
$("#treeTask").jstree();
$("#treeTask").bind("ready.jstree", function (event, data) {
$("#treeTask").jstree("open_node", $("#node_4"));
if((data.inst._get_parent(data.rslt.obj)).length) {
data.inst._get_parent(data.rslt.obj).open_node(this, false);
}
});
});
I have been manipulating the code for a while, but could not make it work. I would really appreciate if anyone can help.
Thanks so much!

You can use the built-in _open_to function:
http://www.jstree.com/api/#/?q=open_to&f=_open_to%28obj%29
$("#treeTask").jstree().bind('ready.jstree', function (event, data) {
data.instance._open_to('node_4');
});

Based on #maddin solution, I've updated it to support any number of parent levels.
jsFiddle
$("#treeTask").jstree().bind('ready.jstree', function (event, data) {
$("#treeTask").jstree('open_node', 'node_4', function(e,d) {
for (var i = 0; i < e.parents.length; i++) {
$("#treeTask").jstree('open_node', e.parents[i]);
};
});
});
It should be noted that if a node is selected, all its parents will be opened automatically. This would be somewhat equivalent to the above:
$("#treeTask").jstree().bind('ready.jstree', function (event, data) {
$("#treeTask").jstree('select_node', 'node_4');
});

Maybe this is an Solution for your problem:
fiddle
$("#treeTask").jstree().bind('ready.jstree', function (event, data) {
$("#treeTask").jstree('open_node', 'node_4', function(e,d) {
if(e.parents.length){
$("#treeTask").jstree('open_node', e.parent);
};
});
});

Related

Get WordPress Submenus in Gatsby JS

I am fiddling around with Gatsby JS using WP as the backend and so far so good. Now I was trying to pull in the menu which for main menu items works just as expected. What I can't really wrap my head around is how to get the submenus pulled in.
The only related thing I found was https://github.com/gatsbyjs/gatsby/issues/2426 which does give me the submenus if I log the data. Just can't get them to be pulled into the menu.
Here is my query in layouts/index.js:
export const query = graphql`
query LayoutQuery {
allWordpressWpApiMenusMenusItems {
edges {
node {
name
count
items {
order
title
url
wordpress_children {
wordpress_id
title
url
}
}
}
}
}
}
`
This is my menu component:
class MainMenu extends Component {
render(){
const data = this.props.menu.allWordpressWpApiMenusMenusItems.edges["0"].node.items
console.log(data)
return(
<div>
<h1>Menu</h1>
<ul>
{data.map((item) =>
<li key={item.object_slug}>
<Link to={item.url}>
{item.title}
</Link>
</li>
)}
</ul>
</div>
)
}
}
export default MainMenu
I tried fiddling around with variations of
{item.children["0"].wordpress_children.title}
but just can't get it to work:/ Any ideas or pointers would be much appreciated!
I just tested this, and your logic is sound all you need is another loop to display subitems. So in your MainMenu.js you can do something like this:
class MainMenu extends Component {
render() {
const data = this.props.menu.allWordpressWpApiMenusMenusItems.edges[0].node.items
console.log(data)
return (
<div>
<h1>Main Menu</h1>
<ul>
{data.map((item) =>
<li key={item.object_slug}>
<Link to={item.url}>
{item.title}
</Link>
<ul>
{item.wordpress_children && item.wordpress_children.map((subitem) =>
<li key={item.wordpress_id}>
<Link to={subitem.url}>
{subitem.title}
</Link>
</li>
)}
</ul>
</li>
)}
</ul>
</div>
)
}
}
This line is very important {item.wordpress_children && item.wordpress_children.map((subitem)
This will check if your menu item has subitems, and if it does it will map them and iterate through them.
I hope this works for you, I tested it and it works.

jstree - node path has unexpected space characters

I need to get node path of jstree element ,I using this code :
$(function () {
$('#jstree').jstree();
$('#jstree')
// listen for event
.on('changed.jstree', function (e, data) {
if (data.action == "select_node") {
var node_path = data.instance.get_path(data.node, "/");
console.log(node_path)
}
});
});
But I get unexpected space character (You can see in console.log() function)
http://jsfiddle.net/3q9Ma/741/
I need a pretty path like this : Folder1/children 1
Please tell me what wrong .
Thank you
The problem actually with the HTML in your fiddle. It looks like this:
<div id="jstree">
<ul>
<li>Folder 1
<ul>
<li id="child_1">Child 1</li>
<li>Child 2</li>
</ul>
</li>
<li>Folder 2</li>
</ul>
</div>
The get_path function is doing exactly what it is supposed to - taking the text from the parent <li> followed by the text from the child <li>. What is happening is that the text from the parent Folder 1 is actually 'Folder/n ', which is causing your problem. I see why you have your HTML structured the way you do, since the example on jstree tells you to do it this way. A way around it would be to remove the line break after your Folder 1. It looks terrible, but it will make your get_path function work:
<div id="jstree">
<ul>
<li>Folder 1<ul>
<li id="child_1">Child 1</li>
<li>Child 2</li>
</ul>
<li>Folder 2</li>
</ul>
</div>

Adding qTip2 tooltips to each node of a jsTree

I am creating a tree structure using thymeleaf in a recursive way to generate the html ul and li elements. Afterwards, I transform this list into a tree using jsTree. Until there, everything is fine. Afterwards, I want to add a tooltip with html content to each element of the tree. I am trying it with qTip2 but for some reason it is only showing an empty tooltip on the root nodes (platform.projectname and platform.projectname2) and nothing at all in the children.
Has anyone done this before? Any advice will be appreciated.
HTML/Thymeleaf container for the tree:
<div id="jstree_demo_div">
<div th:fragment="submenu" th:remove="tag">
<ul>
<li th:each="node : ${nodelist}">
<span th:text="${node.path}" class="treeelement">Town hall</span>
<div class="tooltip">
Logging configuration:
<br/><br/>
<select>
<option value="trace">Trace</option>
<option value="debug">Debug</option>
<option value="info">Info</option>
<option value="warn">Warn</option>
<option value="error">Error</option>
</select>
</div>
<div th:with="nodelist = ${node.children}" th:include="this::submenu" th:remove="tag"></div>
</li>
</ul>
</div>
</div>
JavaScript:
// jsTree
$(function () {
// 6 create an instance when the DOM is ready
$('#jstree_demo_div').jstree();
// 7 bind to events triggered on the tree
$('#jstree_demo_div').on("changed.jstree", function (e, data) {
console.log(data.selected);
});
// 8 interact with the tree - either way is OK
$('button').on('click', function () {
$('#jstree_demo_div').jstree(true).select_node('child_node_1');
$('#jstree_demo_div').jstree('select_node', 'child_node_1');
$.jstree.reference('#jstree_demo_div').select_node('child_node_1');
});
});
// qTip2
$(function(){
$('.treeelement').each(function(){
$(this).qtip({
content: {
text: $(this).next('.tooltip')
},
show: 'click',
hide: {
fixed: true,
delay: 2000
}
});
});
});
I made it work I guess, check this: JS Fiddle.
Try to:
move your qtip binding into loaded jsTree event to be sure it is loaded before you start binding qtip;
bind to jstree-ancor class the jsTree node has
you do not need to iterate with each
The reason for your tooltip having no text is that when building the tree jsTree rebuilds your <li> elements leaving out your .tooltip divs.
I found a way which suits better my needs, here is a JSFiddle example.
First I register the method nodeSelected to be executed when a node is selected, then I create and show the tooltip. This allows me to assign a specific ID to <select>.
$('#jstree_demo_div').on("changed.jstree", function (e, data) {
nodeSelected(data);
})
...
function nodeSelected(data){
console.log(data.selected);
// Using getElementById since JQuery does not work well with dots in identifiers
$(document.getElementById(data.selected + '_anchor')).qtip({
content: {
text: 'Logging configuration:<br/><br/><select><option value="TRACE">Trace</option><option value="DEBUG">Debug</option><option value="INFO">Info</option></select></div>
},
show: 'click',
hide: {
fixed: true,
delay: 1000
}
});
$(document.getElementById(data.selected + '_anchor')).qtip("show");
}

angularjs socials share buttons troubles the display is only in one page

I'm going mad with a simple embedded of social buttons.
Put it in this way I've got two states home and blog
with this code
home
<div id="socials-bar" class=" clearfix">
<ul class="pull-right">
<li>
<div class="fb-like" data-href="http://mydomain.com" data-layout="standard" data-action="like" data-show-faces="false" data-share="true"></div>
</li>
<li>
Tweet
</li>
<li>
<div class="g-plusone" data-size="small" data-annotation="inline" data-width="120" data-href="http://mydomain.it"></div>
</li>
</ul>
</div>
//other html
<script>
!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');
</script>
<script>
window.___gcfg = {lang: 'it'};
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/platform.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
</script>
blog
<div class="clearfix">
<ul class="article-socials pull-right">
<li>
<div class="fb-like" data-href="http://mydomain.it/blog/{{article.id}}/{{article.slug}}" data-layout="standard" data-action="like" data-show-faces="false" data-share="true"></div>
</li>
<li>
Tweet
</li>
<li>
<div class="g-plusone" data-size="small" data-annotation="inline" data-width="120" data-href="http://mydomain.it/blog/{{article.id}}/{{article.slug}}"></div>
</li>
</ul>
</div>
<script>
!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');
</script>
<script>
window.___gcfg = {lang: 'it'};
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/platform.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
</script>
The problem is that the I see them only in the home
page if I get rid off of them in home I can see them in the blog state
Do you know what could be the problem ?
UPDATE: I've updated the below directives and registered them on bower with the package name 'angulike', for full details and a working demo go to http://jasonwatmore.com/post/2014/08/01/AngularJS-directives-for-social-sharing-buttons-Facebook-Like-GooglePlus-Twitter-and-Pinterest.aspx
The problem is that the social buttons only get initialized on page load by default, so in an angularjs app you need to re-initialize the buttons yourself when the view changes. I got them working by creating a directive for each, below is the code:
Google Plus Button Directive
app.directive('googlePlus', ['$window', function ($window) {
return {
restrict: 'A',
template: '<div class="g-plusone" data-size="medium"></div>',
link: function (scope, element, attrs) {
scope.$watch(function () { return !!$window.gapi; },
function (gapiIsReady) {
if (gapiIsReady) {
$window.gapi.plusone.go(element.parent()[0]);
}
});
}
};
}]);
Tweet Button Directive
app.directive('tweet', ['$window', function ($window) {
return {
restrict: 'A',
template: 'Tweet',
link: function (scope, element, attrs) {
scope.$watch(function () { return !!$window.twttr; },
function (twttrIsReady) {
if (twttrIsReady) {
$window.twttr.widgets.load(element.parent()[0]);
}
});
}
};
}]);
Facebook Like Button Directive
app.directive('fbLike', ['$window', function ($window) {
return {
restrict: 'A',
template: '<div class="fb-like" data-layout="button_count" data-action="like" data-show-faces="true" data-share="true"></div>',
link: function (scope, element, attrs) {
scope.$watch(function () { return !!$window.FB; },
function (fbIsReady) {
if (fbIsReady) {
$window.FB.XFBML.parse(element.parent()[0]);
}
});
}
};
}]);
HTML to use the directives
<div data-fb-like=""></div>
<div data-tweet=""></div>
<div data-google-plus=""></div>
If I understand, probably you should remove the script in blog state template.
Anyway, I can share how I do in my sample project:
index.html
directive for social buttons
template for
social buttons
basically in index there are scripts for social buttons available for all states

jQuery toggle only works on second click after scrollTo event

I have some mobile navigation that uses a scrollTo function, that once clicked, makes my toggle function only work on the second click. It may have to do the the binding of the scrollTo click, but I can't figure out how to fix it.
HTML:
<div class="nav-bar">
<ul class="nav">
<li>Section 1</li>
<li>Section 2</li>
<li>Section 3</li>
</ul>
<a class="nav-toggle">Menu</a>
</div>
<div class="section-wrap">
<div id="section1" class="section">Section 1</div>
<div id="section2" class="section">Section 2</div>
<div id="section3" class="section">Section 3</div>
</div>
JS:
$('ul.nav a').bind('click',function(event){
$('ul.nav a').removeClass('on');
$(this).addClass('on');
var $anchor = $(this);
$('html, body').stop().animate({
scrollTop: $($anchor.attr('href')).offset().top - 30
}, 200, function() {
$('.nav-bar').removeClass('open');
});
event.preventDefault();
});
$('a.nav-toggle').toggle(function() {
$('.nav-bar').addClass('open');
}, function () {
$('.nav-bar').removeClass('open');
});
See this for a working example of the issue: http://jsfiddle.net/MhSKC/9/
At the end of your animate, you remove the open class. Then on the next click of the menu bar, the toggle function tries to remove the open class again, because that's the one of the two toggle functions that needs to execute next. Here's a slightly reworked solution:
http://jsfiddle.net/P4mtC/
$('a.nav-toggle').click(function() {
$('.nav-bar').toggleClass('open');
});
instead of using
$('a.nav-toggle').toggle(function() {
$('.nav-bar').addClass('open');
}, function () {
$('.nav-bar').removeClass('open');
});
use
$('a.nav-toggle').click(function() {
$('.nav-bar').toggleClass('open');
});