JsTree: Show more options - javascript

Is there any way to have a show more option/link in jsTree?
I want to show only part of the children and have a link to expand to show all elements.
I tried a few google searches but could not find a solution. Any help/hint would be useful.
Let's say parent-1 has 10 child nodes and the Main Root has 5 parent nodes.
Main Parent
- Parent - 1
- child-1
- child-2
- child-3
show 7 more parent-1 elements //LINK
- Parent - 2
- child-1
- child-2
- Parent - 3
- child-1
- child-2
show 2 more Main Parent elements //LINK
I'm trying to achieve the following result
Is this possible? Are there any available plugins for this? Are there any alternatives for jsTree that support this?

You could feasibly use classes/childElement count to work this. Depending on what you want to show, you could use ids/classes to leave the elements you want to stay visible or optionally show/hide. The same principle can be applied to both child elements (say list items in a list) and higher parent elements, so once you have the first function, it can easily be adapted.
I've included a list example here to give you the idea (it's in plain javascript and you could tweak it a bit..) Jquery would make the js shorter, but it's always good to know the vanilla i reckon..
var x = document.getElementById("show");
//var root = document.getElementsByTagName('body')[0];
var count = x.childElementCount;
var btn1 = document.getElementById("ulmore");
btn1.innerHTML = "+ Show all " + count + " li children";
document.getElementById("ulmore").addEventListener("click", showmore);
function showmore() {
//var d = document.getElementsByClassName("tg1").length;
//use d if you want to show "show d more children" instead of the full amount of children
var el = document.getElementsByTagName("li");
var i;
for (i = 0; i < el.length; i++) {
if (el[i].classList.contains("tg1")) {
//el[i].style.display = "block"; works
el[i].classList.toggle('more');
if (el[i].classList.contains("more")) {
btn1.innerText = "Hide children";
} else {
btn1.innerText = "+ Show all " + count + " li children";
}
}
}
}
body {
padding: 1em;
font-size: 10pt;
}
ul {
list-style: none;
width: 10em;
padding: 0px;
}
li {
text-align: left;
line-height: 1.5;
background: lightblue;
border: 1px solid #444;
margin: 1px 0px;
padding: 2px;
}
span {
display: inline-block;
}
div {
display: inline-block;
width: 100%;
float: left;
margin: 1em 2em 1em 0em;
}
.tg1 {
background: lightsteelblue;
display: none;
}
.more {
background: lightsteelblue;
display: block;
}
/*.tog2 {
display: none;
}
.grow {
background: yellow;
display: inline-block;
}*/
<body>
<div id="ulbit">
<h4>Demo List</h4>
<ul id="show">
<li>One</li>
<li>Two</li>
<li class="tg1">Three</li>
<li class="tg1">Four</li>
<li class="tg1">Five</li>
<li class="tg1">Six</li>
<li class="tg1">Seven</li>
<li class="tg1">Eight</li>
</ul>
<span id="ulmore"></span>
</div>
<!-- <div class="tog2">
Div 2 hello
</div>
<div class="tog2">
Div 3
</div>
<span id="divmore"></span>-->
</body>
Here's a fiddle link (with body 'parent' elements) included in code.
(Note: even a <br> tag [when used between divs] will be regarded as a top-level element .. I'd think that count by tagName (or className) would be most useful if you want to count different types of 'parent' elements (as opposed to counting children of body). Examples of both (children of body and getElementsByTagName) are included in the fiddle)
Hope this helps

did you try to use "before_open.jstree" event to show the tree the way you need?
see the example (I use part of the demo page from the jstree site):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jstree basic demos</title>
<style>
html { margin:0; padding:0; font-size:62.5%; }
body { max-width:800px; min-width:300px; margin:0 auto; padding:20px 10px; font-size:14px; font-size:1.4em; }
h1 { font-size:1.8em; }
.demo { overflow:auto; border:1px solid silver; min-height:100px; }
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" />
</head>
<body>
<h1>Interaction and events demo</h1>
<button id="evts_button">select node with id 1</button> <em>either click the button or a node in the tree</em>
<div id="evts" class="demo"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>
<script>
// interaction and events
$('#evts_button').on("click", function () {
var instance = $('#evts').jstree(true);
instance.deselect_all();
instance.select_node('1');
});
$('#evts')
.on("changed.jstree", function (e, data) {
if(data.selected.length) {
alert('The selected node is: ' + data.instance.get_node(data.selected[0]).text);
}
})
.on("before_open.jstree", function (e, data,a,b,c,d) {
$('#' + data.node.id + ' ul li:nth-child(n + 2)').hide();
var str = '<li class="jstree-node jstree-leaf jstree-last" role="treeitem">press to show ' + $('#' + data.node.id + ' ul li:nth-child(n + 2)').length + ' more items</li>';
var li = $(str).on('click', function(a,b,c,d) {$(a.target).parent().find('li').show(); $(a.target).hide()});
$('#' + data.node.id + ' ul').append(li);
})
.jstree({
'core' : {
'multiple' : false,
'data' : [
{ "text" : "Root node", "children" : [
{ "text" : "Child node 1", "id" : 1 },
{ "text" : "Child node 2" }
]}
]
}
});
</script>
</body>
</html>
I hope this helped.

Related

Need help sorting global list by the currently selected value

I'm taking a Javascript Basics course and I'm stuck on getting the list to sort. Specifically with Step 8. How do I get it to recognize that they select either ascending or descending and make it populate? Right now it disappears and I see no console errors. Thanks for any help!
Here is what I have so far. You can ignore the controlling your code section in the html. I took that js section out to hopefully make it easier to follow:
/* FETCH */
// Step 1: Declare a global empty array variable to store a list of temples
let templeList = [];
// Step 2: Declare a function named output that accepts a list of temples as an array argument and does the following for each temple:
function output(temples) {
templeList = temples;
let div = document.getElementById('temples');
temples.forEach(temple => {
// - Creates an HTML <article> element
let article = document.createElement('article');
// - Creates an HTML <h3> element and add the temple's templeName property to it
// - Appends the <h3> element, the two <h4> elements, and the <img> element to the <article> element as children
let h3 = document.createElement('h3');
h3.innerHTML = temple.templeName;
article.appendChild(h3);
// - Creates an HTML <h4> element and add the temple's location property to it
// - Appends the <h3> element, the two <h4> elements, and the <img> element to the <article> element as children
let h4First = document.createElement('h4');
h4First.innerHTML = temple.location;
article.appendChild(h4First);
// - Creates an HTML <h4> element and add the temple's dedicated property to it
// - Appends the <h3> element, the two <h4> elements, and the <img> element to the <article> element as children
let h4Second = document.createElement('h4');
h4Second.innerHTML = temple.dedicated;
article.appendChild(h4Second);
// - Creates an HTML <img> element and add the temple's imageUrl property to the src attribute and the temple's templeName property to the alt attribute
let image = document.createElement('img');
image.setAttribute('src', temple.imageUrl);
article.appendChild(image);
// - Appends the <article> element to the HTML element with an ID of temples
div.appendChild(article);
});
};
// Step 3: Create another function called getTemples. Make it an async function.
async function getTemples() {
// Step 4: In the function, using the built-in fetch method, call this absolute URL: 'https://byui-cse.github.io/cse121b-course/week05/temples.json'. Create a variable to hold the response from your fetch. You should have the program wait on this line until it finishes.
let responseFromURL = await fetch('https://byui-cse.github.io/cse121b-course/week05/temples.json');
// Step 5: Convert your fetch response into a Javascript object ( hint: .json() ). Store this in the templeList variable you declared earlier (Step 1). Make sure the the execution of the code waits here as well until it finishes.
let templeArray = await responseFromURL.json();
output(templeArray);
};
// Step 6: Finally, call the output function and pass it the list of temples. Execute your getTemples function to make sure it works correctly.
getTemples(templeList);
// Step 7: Declare a function named reset that clears all of the <article> elements from the HTML element with an ID of temples
function reset() {
return document.getElementById('temples').innerHTML = '';
};
// Step 8: Declare a function named sortBy that does the following:
function sortBy() {
// - Calls the reset function
reset();
// - Sorts the global temple list by the currently selected value of the HTML element with an ID of sortBy
let asc = document.getElementById('templeNameAscending');
let dsc = document.getElementById('templeNameDescending');
let sort = document.getElementById('sortBy');
if (asc) {
let sorted = templeList.sort(function(a,b) {return a-b});
return output(sorted);
}else if (dsc) {
let sorted = templeList.sort(function(a,b) {return a-b});
return output(sorted);
};
};
// Step 9: Add a change event listener to the HTML element with an ID of sortBy that calls the sortBy function
document.getElementById('sortBy').addEventListener('change', sortBy);
/* STRETCH */
// Consider adding a "Filter by" feature that allows users to filter the list of temples
// This will require changes to both the HTML and the JavaScript files
/* HTML Selectors */
article {
margin: 10px;
}
body {
font-family: 'Kalam', cursive;
}
div {
margin: 10px;
text-align: center;
}
footer {
background-color: gray;
color: white;
padding: 5px;
text-align: center;
}
header {
margin: auto;
text-align: center;
}
img {
width: 80%;
}
label {
display: inline-block;
min-width: 120px;
text-align: right;
}
main {
text-align: center;
}
nav {
background-color: black;
color: white;
}
nav ul {
display: flex;
flex-direction: column;
justify-content: center;
align-content: space-around;
margin: 0;
padding: 0;
}
nav ul li:first-child {
display: block;
}
nav ul li {
display: none;
list-style: none;
margin: 10px;
}
nav ul li a {
color: white;
display: block;
padding: 10px;
text-decoration: none;
}
nav ul li a:hover {
background-color: #efefef;
color: black;
}
section {
/* display: flex;
flex-direction: column;
align-items: center; */
}
/* Class Selectors */
.active {
background-color: white;
color: black;
}
.open li {
display: block;
}
/* ID Selectors */
#favorite-foods, #hobbies, #places-lived {
margin: 0;
padding: 0;
list-style: none;
display: inline-block;
text-align: left;
vertical-align: top;
}
#temples {
display: grid;
grid-template-columns: 1fr;
}
/* Media Queries */
#media only screen and (min-width: 32.5em) {
nav ul {
flex-direction: row;
}
nav ul li:first-child {
display: none;
}
nav ul li {
display: inline;
margin: 0 10px;
}
#temples {
grid-template-columns: 1fr 1fr;
}
}
#media only screen and (min-width: 64em) {
#temples {
grid-template-columns: 1fr 1fr 1fr;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>CSE 121b: Week 05 | Sample Solution</title>
<link href="https://fonts.googleapis.com/css?family=Kalam&display=swap" rel="stylesheet">
<link rel="stylesheet" href="styles/main.css">
</head>
<body>
<nav>
<ul id="menu">
<li><a id="toggleMenu">≡</a></li>
<li>Home</li>
<li>Lesson 2</li>
<li>Lesson 3</li>
<li>Lesson 4</li>
<li>Lesson 5</li>
</ul>
</nav>
<header>
<h1>Controlling Your Code</h1>
</header>
<main>
<section>
<h2>
Today is <span id="message2"></span>.
</h2>
<h3>
<span id="message1"></span>
</h3>
</section>
<hr>
<section>
<h2>Temples in Utah</h2>
<p>
Sort by:
<select id="sortBy">
<option value="templeNameAscending">Temple Name Ascending</option>
<option value="templeNameDescending">Temple Name Descending</option>
</select>
</p>
<div id="temples">
</div>
</section>
</main>
<footer>
©<span id="year"></span> | Controlling Your Code | Lesson 5
</footer>
<script src="scripts/main.js"></script>
<script src="scripts/task5.js"></script>
</body>
</html>
Here it is. First of all, you are tracking changes on input field and checking if it's equal to templeNameAscending or templeNameDescending, and based on it sort the results.
Main thing is this part of code:
if (e.target.value === 'templeNameAscending') {
let sorted = templeList.sort(function(a,b) {return a.templeName>b.templeName ? 1 : -1});
return output(sorted);
}else if (e.target.value === 'templeNameDescending') {
let sorted = templeList.sort(function(a,b) {return b.templeName>a.templeName ? 1 : -1});
return output(sorted);
};
You made a mistake by trying to select those fields by id, and you never assigned id to them.
If you're confused with events, take a look at event objects
Here is the working snippet:
/* FETCH */
// Step 1: Declare a global empty array variable to store a list of temples
let templeList = [];
// Step 2: Declare a function named output that accepts a list of temples as an array argument and does the following for each temple:
function output(temples) {
templeList = temples;
let div = document.getElementById('temples');
temples.forEach(temple => {
// - Creates an HTML <article> element
let article = document.createElement('article');
// - Creates an HTML <h3> element and add the temple's templeName property to it
// - Appends the <h3> element, the two <h4> elements, and the <img> element to the <article> element as children
let h3 = document.createElement('h3');
h3.innerHTML = temple.templeName;
article.appendChild(h3);
// - Creates an HTML <h4> element and add the temple's location property to it
// - Appends the <h3> element, the two <h4> elements, and the <img> element to the <article> element as children
let h4First = document.createElement('h4');
h4First.innerHTML = temple.location;
article.appendChild(h4First);
// - Creates an HTML <h4> element and add the temple's dedicated property to it
// - Appends the <h3> element, the two <h4> elements, and the <img> element to the <article> element as children
let h4Second = document.createElement('h4');
h4Second.innerHTML = temple.dedicated;
article.appendChild(h4Second);
// - Creates an HTML <img> element and add the temple's imageUrl property to the src attribute and the temple's templeName property to the alt attribute
let image = document.createElement('img');
image.setAttribute('src', temple.imageUrl);
article.appendChild(image);
// - Appends the <article> element to the HTML element with an ID of temples
div.appendChild(article);
});
};
// Step 3: Create another function called getTemples. Make it an async function.
async function getTemples() {
// Step 4: In the function, using the built-in fetch method, call this absolute URL: 'https://byui-cse.github.io/cse121b-course/week05/temples.json'. Create a variable to hold the response from your fetch. You should have the program wait on this line until it finishes.
let responseFromURL = await fetch('https://byui-cse.github.io/cse121b-course/week05/temples.json');
// Step 5: Convert your fetch response into a Javascript object ( hint: .json() ). Store this in the templeList variable you declared earlier (Step 1). Make sure the the execution of the code waits here as well until it finishes.
let templeArray = await responseFromURL.json();
output(templeArray);
};
// Step 6: Finally, call the output function and pass it the list of temples. Execute your getTemples function to make sure it works correctly.
getTemples(templeList);
// Step 7: Declare a function named reset that clears all of the <article> elements from the HTML element with an ID of temples
function reset() {
return document.getElementById('temples').innerHTML = '';
};
// Step 8: Declare a function named sortBy that does the following:
function sortBy(e) {
// - Calls the reset function
reset();
// - Sorts the global temple list by the currently selected value of the HTML element with an ID of sortBy
let sort = document.getElementById('sortBy');
if (e.target.value === 'templeNameAscending') {
let sorted = templeList.sort(function(a,b) {return a.templeName>b.templeName ? 1 : -1});
return output(sorted);
}else if (e.target.value === 'templeNameDescending') {
let sorted = templeList.sort(function(a,b) {return b.templeName>a.templeName ? 1 : -1});
return output(sorted);
};
};
// Step 9: Add a change event listener to the HTML element with an ID of sortBy that calls the sortBy function
document.getElementById('sortBy').addEventListener('change', sortBy);
/* STRETCH */
// Consider adding a "Filter by" feature that allows users to filter the list of temples
// This will require changes to both the HTML and the JavaScript files
/* HTML Selectors */
article {
margin: 10px;
}
body {
font-family: 'Kalam', cursive;
}
div {
margin: 10px;
text-align: center;
}
footer {
background-color: gray;
color: white;
padding: 5px;
text-align: center;
}
header {
margin: auto;
text-align: center;
}
img {
width: 80%;
}
label {
display: inline-block;
min-width: 120px;
text-align: right;
}
main {
text-align: center;
}
nav {
background-color: black;
color: white;
}
nav ul {
display: flex;
flex-direction: column;
justify-content: center;
align-content: space-around;
margin: 0;
padding: 0;
}
nav ul li:first-child {
display: block;
}
nav ul li {
display: none;
list-style: none;
margin: 10px;
}
nav ul li a {
color: white;
display: block;
padding: 10px;
text-decoration: none;
}
nav ul li a:hover {
background-color: #efefef;
color: black;
}
section {
/* display: flex;
flex-direction: column;
align-items: center; */
}
/* Class Selectors */
.active {
background-color: white;
color: black;
}
.open li {
display: block;
}
/* ID Selectors */
#favorite-foods, #hobbies, #places-lived {
margin: 0;
padding: 0;
list-style: none;
display: inline-block;
text-align: left;
vertical-align: top;
}
#temples {
display: grid;
grid-template-columns: 1fr;
}
/* Media Queries */
#media only screen and (min-width: 32.5em) {
nav ul {
flex-direction: row;
}
nav ul li:first-child {
display: none;
}
nav ul li {
display: inline;
margin: 0 10px;
}
#temples {
grid-template-columns: 1fr 1fr;
}
}
#media only screen and (min-width: 64em) {
#temples {
grid-template-columns: 1fr 1fr 1fr;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>CSE 121b: Week 05 | Sample Solution</title>
<link href="https://fonts.googleapis.com/css?family=Kalam&display=swap" rel="stylesheet">
<link rel="stylesheet" href="styles/main.css">
</head>
<body>
<nav>
<ul id="menu">
<li><a id="toggleMenu">≡</a></li>
<li>Home</li>
<li>Lesson 2</li>
<li>Lesson 3</li>
<li>Lesson 4</li>
<li>Lesson 5</li>
</ul>
</nav>
<header>
<h1>Controlling Your Code</h1>
</header>
<main>
<section>
<h2>
Today is <span id="message2"></span>.
</h2>
<h3>
<span id="message1"></span>
</h3>
</section>
<hr>
<section>
<h2>Temples in Utah</h2>
<p>
Sort by:
<select id="sortBy">
<option value="templeNameAscending">Temple Name Ascending</option>
<option value="templeNameDescending">Temple Name Descending</option>
</select>
</p>
<div id="temples">
</div>
</section>
</main>
<footer>
©<span id="year"></span> | Controlling Your Code | Lesson 5
</footer>
<script src="scripts/main.js"></script>
<script src="scripts/task5.js"></script>
</body>
</html>

Onclick or href not working on Dropdown menu on hover effect

I have a menu with drop down on hover and when clicked it should open a new page.
Here is the HTML;
<ul class=“Mainmenu” id=“Mainmenu”>
<li class=“dropdown”><a onclick=“window.location.reload()”>Home</a></li>
<li class=“dropdown”><a href=“Page1.html” onclick=“Loadpage(); return false;”>About us</a>
<ul class=“dropdown-menu” id=“menu1”>
<li class=“dropdownlink” id=“link1”><a href=“#”>Domestic</a></li>
<li class=“dropdownlink” id=“link2”><a href=“#”>International</a></li>
</ul>
</li>
<li class=“dropdown”><a onclick=“Loadteampage(); return false;”>Team</a></li>
</ul>
Here is the JavaScript:
function Loadpage(){
window.location.href=“Page1.html”;
}
function Loadteampage(){
window.location.href=“Team.html”;
}
Here is the CSS
.Mainmenu{
height: 15px;
font-family: Calibri;
font-size 12. 5px;
display: inline;
position: absolute;
width: 100%;
line-height: 15px;
text-align: center;
list-style: none;
top 18px;
}
.Mainmenu a{
float: left;
font-size: 14px;
color: #FAF6AF;
text-align: center;
padding: 5px 10px;
text-decoration: none;
height: 15px;
line -height: 15px;
transition: all 0.7s ease;
}
ul.Mainmenu > li{
float: left;
position: relative;
}
ul.Mainmenu li > a{
height: 15px;
line-height: 15px;
text-align: Center;
display: block;
background: #000000;
color: #FAF6AF;
white-space: nowrap;
}
ul.Mainmenu li:hover > a{
background-color: #FAF6AF;
color #000000;
cursor: pointer;}
ul.Mainmenu > li ul {
display: none;
position: absolute;
}
ul.Mainmenu > li:hover ul{
display: block;
cursor: pointer;
}
ul.Mainmenu > li ul li{
display: block;
position: relative;
top: 25px;
left: -40px;
}
.dropdownlink a{
text-align: center;
line-height: 15px;
font-size: 12.5px;
padding: 0px 0px 0px 0px;
margin: 0;
width: 100%;
}
The “About us” should act as dropdown when hovered on and act as link when clicked. But the onclick and href on “About us” is not working. Even I tried alert(); in onclick but it’s not working.
Please find the JSFIDDLE Link below:
JSFIDDLE
Can someone help me fix this issue?
Edited to include my favorite expand a list javascript
/*
CollapsibleLists.js
An object allowing lists to dynamically expand and collapse
Created by Stephen Morley - http://code.stephenmorley.org/ - and released under
the terms of the CC0 1.0 Universal legal code:
http://creativecommons.org/publicdomain/zero/1.0/legalcode
*/
// create the CollapsibleLists object
var CollapsibleLists =
new function(){
/* Makes all lists with the class 'collapsibleList' collapsible. The
* parameter is:
*
* doNotRecurse - true if sub-lists should not be made collapsible
*/
this.apply = function(doNotRecurse){
// loop over the unordered lists
var uls = document.getElementsByTagName('ul');
for (var index = 0; index < uls.length; index ++){
// check whether this list should be made collapsible
if (uls[index].className.match(/(^| )collapsibleList( |$)/)){
// make this list collapsible
this.applyTo(uls[index], true);
// check whether sub-lists should also be made collapsible
if (!doNotRecurse){
// add the collapsibleList class to the sub-lists
var subUls = uls[index].getElementsByTagName('ul');
for (var subIndex = 0; subIndex < subUls.length; subIndex ++){
subUls[subIndex].className += ' collapsibleList';
}
}
}
}
};
/* Makes the specified list collapsible. The parameters are:
*
* node - the list element
* doNotRecurse - true if sub-lists should not be made collapsible
*/
this.applyTo = function(node, doNotRecurse){
// loop over the list items within this node
var lis = node.getElementsByTagName('li');
for (var index = 0; index < lis.length; index ++){
// check whether this list item should be collapsible
if (!doNotRecurse || node == lis[index].parentNode){
// prevent text from being selected unintentionally
if (lis[index].addEventListener){
lis[index].addEventListener(
'mousedown', function (e){ e.preventDefault(); }, false);
}else{
lis[index].attachEvent(
'onselectstart', function(){ event.returnValue = false; });
}
// add the click listener
if (lis[index].addEventListener){
lis[index].addEventListener(
'click', createClickListener(lis[index]), false);
}else{
lis[index].attachEvent(
'onclick', createClickListener(lis[index]));
}
// close the unordered lists within this list item
toggle(lis[index]);
}
}
};
/* Returns a function that toggles the display status of any unordered
* list elements within the specified node. The parameter is:
*
* node - the node containing the unordered list elements
*/
function createClickListener(node){
// return the function
return function(e){
// ensure the event object is defined
if (!e) e = window.event;
// find the list item containing the target of the event
var li = (e.target ? e.target : e.srcElement);
while (li.nodeName != 'LI') li = li.parentNode;
// toggle the state of the node if it was the target of the event
if (li == node) toggle(node);
};
}
/* Opens or closes the unordered list elements directly within the
* specified node. The parameter is:
*
* node - the node containing the unordered list elements
*/
function toggle(node){
// determine whether to open or close the unordered lists
var open = node.className.match(/(^| )collapsibleListClosed( |$)/);
// loop over the unordered list elements with the node
var uls = node.getElementsByTagName('ul');
for (var index = 0; index < uls.length; index ++){
// find the parent list item of this unordered list
var li = uls[index];
while (li.nodeName != 'LI') li = li.parentNode;
// style the unordered list if it is directly within this node
if (li == node) uls[index].style.display = (open ? 'block' : 'none');
}
// remove the current class from the node
node.className =
node.className.replace(
/(^| )collapsibleList(Open|Closed)( |$)/, '');
// if the node contains unordered lists, set its class
if (uls.length > 0){
node.className += ' collapsibleList' + (open ? 'Open' : 'Closed');
}
}
}();
the Html recommended is
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Vakram Mohan Help</title>
<link rel="stylesheet" href="reset.css" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:regular,bold,italic,thin,light,bolditalic,black,medium&lang=en">
<script type="text/javascript" src="CollapsibleLists.js"></script>
</head>
<body>
<div>
<UL id="Mainmenu">
<li>
<h2><span>Menu</span></h2>
<ul>
<li> <span><a onclick=“window.location.reload()”>Home</a></span></li>
<li><span>About us</span>
<ul>
<li><span><a href=“#”>Domestic</a></span></li>
<li><span><a href=“#”>International</a></span></li>
</ul>
</li>
</ul>
</li><!--Menu end -->
</UL> <!-- Main Menu end -->
</body>
<script language="javascript" type="text/javascript">
function btntest_onclick()
{
window.location.href = "http://www.google.com";
}
</script>
<script>
CollapsibleLists.applyTo(document.getElementById('Mainmenu'));
</script>
</head>
</html>
Notice i am not using your CSS file.
it was a mess
#para1 {
text-align: center;
color: red;
}
that is a ID selector
.center {
text-align: center;
color: red;
}
that is a Class selector.
Reset.css is here
html, body, header, footer, hgroup, nav, main, article, section, figure, figcaption, h1, h2, h3, ul, li, body, div, p, img
{
margin: 0;
padding: 0;
font-size: 100%;
vertical-align: baseline;
border: 0;
}

Reloading of deleted list items

I have an input box which you can enter items, submit it, and create a box with it's own delete button to remove it. Problem is, after deleting a number of boxes, and then entering something new in input, all the previous items that were deleted get reloaded, including the new item.
How can I prevent reloading of already removed boxes?
Fiddle (Stacksnippets do not allow submit)
This is my Html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Shopping List Example</title>
<link rel="stylesheet" type="text/css" href="css-list.css">
</head>
<div id="centerPanel">
<form class="my-list-form">
<input type="text" class="input" name="add-input" id="add-input">
<button class="add-button" id="submitBtn">Add</button>
</form>
<ul class="my-list-ul"></ul>
</div>
<script src="https://code.jquery.com/jquery-2.2.3.min.js"></script>
<script src="js-list.js"></script>
</html>
JS:
var state = {items:[]};
var addItem = function(state, item)
{
state.items.push(item);
}
var displayItem = function(state, element){
var htmlItems = state.items.map(function(item){
return '<li class="box">' + item + '</br><button class="divBtns" id="deleteBtn">Delete</button>' + '</li>';
});
element.html(htmlItems);
}
//After deleting items, this button again loads all items that have been created since
//the page loaded up, including the new item.
//Needs to be fixed to not reload the deleted items
$('.my-list-form').submit(function(event){
event.preventDefault();
addItem(state, $('.input').val());
displayItem(state, $('.my-list-ul') );
/* alert(state.items[1]); shows that the items array holds everything that is turned into a div*/
})
$(document).ready(function(e){
$('ul').on('click', '#deleteBtn', function(event){
var rmvButton = $(this).closest('li');
rmvButton.remove();
});
})
css:
* {
font-family: sans-serif;
font-weight: normal;
}
#centerPanel {
margin-left: 50px;
margin-top: 50px;
padding-left: 10px;
}
h1 {
font-size: 34px;
}
.font-size {
font-size: 17px;
}
#add-input {
height:25px;
width: 190px;
font-size: 16px;
}
button {
font-size: 17px;
}
#submitBtn {
height: 30px;
width: 85px;
}
.divBtns {
margin-top: 10px;
}
.box {
border: 1px solid black;
border-color: grey;
width: 153px;
height: 65px;
padding: 20px;
font-style: italic;
font-size: 22px;
margin-bottom:10px;
margin-right: 10px;
}
ul {
list-style-type: none;
margin-left:-40px;
color: grey;
}
li {
float: left;
}
It appears you never remove anything from the state object, which is added to every time you run addItem().
You'd need a way to remove a specific item from this array, probably by getting the index of the li to delete and doing
state.items.splice(index, 1);
Store the index as a data attribute on the button:
var displayItem = function(state, element){
var i = 0;
var htmlItems = state.items.map(function(item){
return '<li class="box">' + item + '</br><button class="divBtns" ' +
'id="deleteBtn" data-index="' + (i++) + '">Delete</button>' + '</li>';
});
element.html(htmlItems);
}
Then you can get it in the click callback
var index = $(this).data('index');
You can update state to solve this problem.
It's my code:
...
var deleteItem = function(state, itemId) {
var index = 0;
var isFind = state.items.some(function(item, i) {
if (item.id == itemId) {
index = i;
return true;
} else {
return false;
}
});
if (isFind) {
state.items.splice(index, 1);
}
}
...
$(document).ready(function(e){
$('ul').on('click', '#deleteBtn', function(event){
...
// update state
deleteItem(state, $(this).parent().data('id'));
});
})
https://jsfiddle.net/q483cLp9/

Convert hierarchical JSON files to hierarchical jQuery divs

How do I loop through two PARENT-CHILD-relationship (on simple ID PKEY and FKEY) JSON files and display them as a list of divs that are:
hierarchical - where child/FKEY divs only appear under the parent/PKEY div (show up as parent-child-child, parent-child-child-child, etc.)
expandable - these child/FKEY divs are display:none until you click the parent/PKEY div; i.e., items appear/disappear when you click the PKEY div, using jQuery's $(panelID).slideToggle(speed) method
able to be toggled with a separate checkbox div if the last key-value pair in the parent div OR child div exists and has key="DEPRECATED"
sortable - Just Kidding
jQuery offers me both parseJSON and cool display functions, and I give it atrociously horrible JS-debugging skills in return.
Edit: Here are the two JSON files in question:
types.json:
{"objtype":[{"NAME":"Animal","ID":"15","DEPRECATED":""},{"NAME":"Vegetable","ID":"8"},{"NAME":"Mineral","ID":"2","DEPRECATED":""}]}
objs.json:
{"objinstance":[{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"8","OBJNAME":"Fruit salad consisting of oranges and mangoes","OBJID":"454","DATEEXPIRES":"2014-09-01 00:00:00.0","DEPRECATED":""},{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"8","OBJNAME":"Spicy V-8 juice","OBJID":"499","DATEEXPIRES":"2015-01-02 00:00:00.0"},{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"2","OBJNAME":"Rental agreement for new apartment","OBJID":"2885","DATEEXPIRES":"2015-08-25 00:00:00.0"},{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"2","OBJNAME":"Salt","OBJID":"1033","DATEEXPIRES":"","DEPRECATED":""},{"DATEBOUGHT":"","OBJTYPEID":"15","OBJNAME":"Koko the Monkey","OBJID":"68","DATEEXPIRES":"","DEPRECATED":""},{"DATEBOUGHT":"","OBJTYPEID":"15","OBJNAME":"Bubbles the Clown","OBJID":"69","DATEEXPIRES":"","DEPRECATED":""}]}
Here is an extremely simple example of how you could generate HTML markup based on your data in JSON.
Algorithm:
Parse JSON string into Javascript objects
Iterate parent data
For each parent data, create parent div and add required content into it.
Iterate child data, search for common id
For each child data which matches the parent id, create child div, add required content into it, and finally append to the parent div
Append parent div to a container or body
Rinse, lather, repeat
Create CSS styles as per your taste
.
Demo Fiddle: http://jsfiddle.net/abhitalks/h3nbwc1f/
Snippet:
var typesString = '{"objtype":[{"NAME":"Animal","ID":"15","DEPRECATED":""},{"NAME":"Vegetable","ID":"8"},{"NAME":"Mineral","ID":"2","DEPRECATED":""}]}';
var objsString = '{"objinstance":[{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"8","OBJNAME":"Fruit salad consisting of oranges and mangoes","OBJID":"454","DATEEXPIRES":"2014-09-01 00:00:00.0","DEPRECATED":""},{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"8","OBJNAME":"Spicy V-8 juice","OBJID":"499","DATEEXPIRES":"2015-01-02 00:00:00.0"},{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"2","OBJNAME":"Rental agreement for new apartment","OBJID":"2885","DATEEXPIRES":"2015-08-25 00:00:00.0"},{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"2","OBJNAME":"Salt","OBJID":"1033","DATEEXPIRES":"","DEPRECATED":""},{"DATEBOUGHT":"","OBJTYPEID":"15","OBJNAME":"Koko the Monkey","OBJID":"68","DATEEXPIRES":"","DEPRECATED":""},{"DATEBOUGHT":"","OBJTYPEID":"15","OBJNAME":"Bubbles the Clown","OBJID":"69","DATEEXPIRES":"","DEPRECATED":""}]}';
var types = JSON.parse(typesString);
var objs = JSON.parse(objsString);
types.objtype.forEach(function(item, idx) {
var $parent = $("<div class='parent' />");
var $label = $("<label>").text(item.ID + ': ' + item.NAME).attr('for', 'c' + idx);
var $input = $('<input type="checkbox">').attr('id', 'c' + idx);
$parent.append($label);
$parent.append($input);
objs.objinstance.forEach(function(item2) {
if (item2.OBJTYPEID == item.ID) {
var $child = $("<div class='child' />");
var txt2 = item2.OBJID + ': ' + item2.OBJNAME;
$child.text(txt2);
$parent.append($child);
}
});
$("#wrap").append($parent);
});
div#wrap {
font-family: helvetica, sans-serif;
font-size: 17px;
}
div.parent {
border: 1px solid blue;
padding: 8px; margin: 4px;
}
div.child {
border: 1px solid green;
font-size: 15px;
padding: 0px; margin: 0px;
opacity: 0; height: 0px;
transition: all 250ms;
}
label {
cursor: pointer;
}
input[type=checkbox] {
display: none;
}
input[type=checkbox]:checked ~ div.child {
padding: 8px; margin: 8px;
opacity: 1; height: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrap"></div>

What are the CSS secrets to a flexible/fluid HTML form?

The below HTML/CSS/Javascript (jQuery) code displays the #makes select box. Selecting an option displays the #models select box with relevant options. The #makes select box sits off-center and the #models select box fills the empty space when it is displayed.
How do you style the form so that the #makes select box is centered when it is the only form element displayed, but when both select boxes are displayed, they are both centered within the container?
var cars = [
{
"makes" : "Honda",
"models" : ['Accord','CRV','Pilot']
},
{
"makes" :"Toyota",
"models" : ['Prius','Camry','Corolla']
}
];
$(function() {
vehicles = [] ;
for(var i = 0; i < cars.length; i++) {
vehicles[cars[i].makes] = cars[i].models ;
}
var options = '';
for (var i = 0; i < cars.length; i++) {
options += '<option value="' + cars[i].makes + '">' + cars[i].makes + '</option>';
}
$("#make").html(options); // populate select box with array
$("#make").bind("click", function() {
$("#model").children().remove() ; // clear select box
var options = '';
for (var i = 0; i < vehicles[this.value].length; i++) {
options += '<option value="' + vehicles[this.value][i] + '">' +
vehicles[this.value][i] +
'</option>';
}
$("#model").html(options); // populate select box with array
$("#models").addClass("show");
}); // bind end
});
.hide {
display: none;
}
.show {
display: inline;
}
fieldset {
border: #206ba4 1px solid;
}
fieldset legend {
margin-top: -.4em;
font-size: 20px;
font-weight: bold;
color: #206ba4;
}
fieldset fieldset {
position: relative;
margin-top: 25px;
padding-top: .75em;
background-color: #ebf4fa;
}
body {
margin: 0;
padding: 0;
font-family: Verdana;
font-size: 12px;
text-align: center;
}
#wrapper {
margin: 40px auto 0;
}
#myFieldset {
width: 213px;
}
#area {
margin: 20px;
}
#area select {
width: 75px;
float: left;
}
#area label {
display: block;
font-size: 1.1em;
font-weight: bold;
color: #000;
}
#area #selection {
display: block;
}
#makes {
margin: 5px;
}
#models {
margin: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<div id="wrapper">
<fieldset id="myFieldset">
<legend>Cars</legend>
<fieldset id="area">
<label>Select Make:</label>
<div id="selection">
<div id="makes">
<select id="make"size="2"></select>
</div>
<div class="hide" id="models">
<select id="model" size="3"></select>
</div>
</div>
</fieldset>
</fieldset>
</div>
It's not entirely clear from your question what layout you're trying to achieve, but judging by that fact that you have applied "float:left" to the select elements, it looks like you want the select elements to appear side by side. If this is the case, you can achieve this by doing the following:
To centrally align elements you need to add "text-align:center" to the containing block level element, in this case #selection.
The position of elements that are floating is not affected by "text-align" declarations, so remove the "float:left" declaration from the select elements.
In order for the #make and #model divs to sit side by side with out the use of floats they must be displayed as inline elements, so add "display:inline" to both #make and #model (note that this will lose the vertical margin on those elements, so you might need to make some other changes to get the exact layout you want).
As select elements are displayed inline by default, an alternative to the last step is to remove the #make and #model divs and and apply the "show" and "hide" classes to the model select element directly.
Floating the select boxes changes their display properties to "block". If you have no reason to float them, simply remove the "float: left" declaration, and add "text-align: center" to #makes and #models.

Categories