I have a Bullet Region like
HelloHowareyou
No i am selecting are and changing to Number Bullet.
so my list should change like
HelloHowareyou
want to end the Disc bullet after second child.
want to add Third child as sibling to parent.
Want to again make Disc bullet to fourth child and add it as sibling to parent.
How can i do this.
This is actually a non-trivial and very interesting problem. However, you need to first know a couple of things:
The bullets on a list item are determined by its list; ul is for unordered lists (ie. disk bullets), and ol is for ordered lists (ie. numbered bullets).
You cannot have an li without its parent being either ul or ol.
You cannot have a ul be a direct child of a ol or vice versa (they can be children of an li though, but then they'll be sublists)
This means that every time you switch a list, you need to make sure that the item you're switching has a parent of the correct (and opposite) type, and the items before and after it are also in (separate) lists of the correct type. You will in many cases need to create those lists (or delete them, when they become empty).
Anyway, words are worthless, here's the code (I'm using jQuery, but the idea should be the same regardless of what you use):
$('li').on('click', function () {
var $listItem = $(this);
var $list = $(this).parent();
var $items = $list.children();
var itemIndex = $items.index($listItem);
var numItems = $items.length;
var curType = $list.is('ul') ? 'ul' : 'ol';
var newType = curType === 'ul' ? 'ol' : 'ul';
var $prev = $list.prev();
var $next = $list.next();
if (itemIndex === 0) {
// The item we're switching is the first Item in the list
if (!$prev.is(newType)) {
$prev = $('<' + newType + '/>');
$prev.insertBefore($list);
}
$prev.append($listItem);
} else if (itemIndex === numItems - 1) {
// The item we're switching is the last Item in the list
if (!$next.is(newType)) {
$next = $('<' + newType + '/>');
$next.insertAfter($list);
}
$next.prepend($listItem);
} else {
// The item is in the middle, we need to split the current list into 3.
$tailList = $('<' + curType + '/>');
$tailList.append($listItem.nextAll());
$tailList.insertAfter($list);
$middleList = $('<' + newType + '/>');
$middleList.append($listItem);
$middleList.insertAfter($list);
}
if (numItems === 1) {
// list used to have only one Item, so it's now empty, and should be removed.
$list.remove();
if ($prev.is(newType) && $next.is(newType)) {
// The two surrounding lists are of the same type and should be merged.
$prev.append($next.children());
$next.remove();
}
}
});
I'm using the click event on a list item to switch a list item. Here's a jsFiddle link for you to play around with the implementation and validate that everything works as expected: http://jsfiddle.net/8Z9rf/
The code can definitely be optimized for speed/performance, but I was aiming for simplicity and clarity, I hope I managed to accomplish this.
Related
I am relatively new to jquery and try to solve the following issue
I want to build a tree diagram, cf.
When an item in the first category is clicked, the second category (in div #category_2) pops-up. The same for the 3rd category. Every subsequent click on category 1 or 2 should remove the appended 2nd and 3rd item and append the chosen item from the 2nd and 3rd category.
Here is what I tried at the example of opening an item in category 3 (=subMenu2):
function makeType(subMenu2, root) {
if (typeof root === 'undefined') {
root = $('#category_3');
}
var ul = $("<ul></ul>");
if (root.children().length > 0) {
root.removeClass(ul)
}
root.append(ul);
for (var k = 0; k < subMenu2.length; k++) {
var li = $("<li class='category-selection-list-item is-subleaf'></li>");
ul.append(li);
var a = $("<a href='#' data-param='" + array[array_i].subMenu[submenu_i].subMenu2[k].param + "'>" + array[array_i].subMenu[submenu_i].subMenu2[k].type + "</a>");
li.append(a);
console.log(k);
}
}
Though the removeClass element stops adding further items, it does not delete previously added items. I tried to find a suitable answer in the forum, but this did not help. So, how can I fix this issue?
To remove the previously added items, you need to empty root.
if (root.children().length > 0) {
root.removeClass('ul');
root.empty();
}
addClass("className")
removeClass("className")
if you want to hide some node, just use this:
$("#someNode").hide()
I am building a small app, that lets you go through people businesscards, 3d style.
Basically, I have an unordered list, containing 10 list items. Each time I press the down arrow on the left, I want to remove the first (the one at the front) and push it at the back (so it becomes the last in the list).
Also, since all of the items, except the first one, have negative transformZ values to push them back, I want to rearrange them so they come closer to the user, each time the down btn is pushed. Right now each of them has a 80*i for a transformZ value and I have no idea how to push them towards without messing up the same layout.
I tried doing something like, but unfortunately it doesn't do the trick:
btnDown.addEventListener('click', function() {
listItems[0].parentNode.removeChild(listItems[0]);
for (i=0; i<=listItems.length-1;i++) {
list.style.webkitTransform = "rotateX(0deg) translateZ(-" + (100*i) + "px)";
}
}, false);
You can also find the complete project here:
http://codepen.io/gbnikolov/pen/cbdwl
Thanks in advance, all help is much appreciated!
btnDown.addEventListener('click', function() {
listItems[0].parentNode.appendChild(listItems[0]);
// re-index list
listItems = document.querySelectorAll('#primary ul li')
for (i=0; i<=listItems.length-1; i++) {
listItems[i].style.webkitTransform = "rotateX(0deg) translateZ(-" + (80*i) + "px) translateY(-" + i*20 + "px)";
}
}, false);
You were close. Instead of removing the item, move it to the end of the node. Then re-apply the webkitTransform.
btnUp.addEventListener('click', function() {
var lastItem = listItems[listItems.length-1]
listItems[0].parentNode.insertBefore(lastItem, listItems[0]);
listItems = document.querySelectorAll('#primary ul li');
applyWebkitTransform();
}, false);
For the up button use the insertBefore() function. See: http://codepen.io/anon/pen/cAbKI
hi can you please tell me how show child element in right element .My function work fine first time But it fail second time .
I do the following steps
1) Press Add button 2 times.Generate row2 as well as submenu of firstLevel.
2) Expand menu option (+) Button.Click "menu_tc_1".It remove rows on right panel .and press add button it create nested submenu .
3) When you press again "menu_tc_1" it show same number of rows as many you click add button.
4) But when you click "First Level " it should show two rows because it have two child("menu_tc_1","menu_tc_2") .It is showing all rows.Because in array it gives all values.
I need show only child
jsFiddle
$(document).on('click', 'ul li > a', function (e) {
//first method..
console.log($(this).siblings().length);
var selEl = [];
$(this).closest('ul').find('li').each(function (idx, el) {
var id= el.id.replace('menu_','');
selEl.push(id);
});
// alert(id);
console.log('aaa' + selEl);
getViewFromPanel(selEl);
});
function getViewFromPanel(arr) {
console.log(arr);
$('#ultest').html('');
for (var i = 1; i < arr.length; i++) {
$('#ultest').append('<li id=' + arr[i] + '>' + arr[i] + '</li>');
}
}
See this updated fiddle.
The main problem is $(this).closest('ul').find('li').each(function (idx, el) {. find will look for all sub levels, that is why is displays all menus. You only want the children of the next ul:
$(this).closest('li').children('ul').children().each(function (idx, el) {
Also, you skip the first element (probably due to using find) in getViewFromPanel - it should start at 0 index:
for (var i=0;i<arr.length;i++){
There is a problem with the way that you set the active class so when you go back and click add, it is added to the wrong hierarchy. I am not sure what your intention is with the active class, but I think that you should clear the class $('.active').removeClass('active') and set it again when the hierarchy changes.
I want a form that gives user the ability to dynamically add fields. What I need is the ability to add dynamic children and giving every child the ability to add its N number of children. Much like this
Parent 1
-- Child 1-1
-- Child 1-2
-- Child 1-2-1
-- Child 1-2-2
-- Child 1-2-3
-- Child 1-2-4
-- Child 1-2-4-1
-- Child 1-2-4-2
-- Child 1-3
-- Child 1-4
-- Child 1-5
-- Child 1-5-1
Parent 2
Parent 3
-- Child 3-1
Everything is dynamic, and a user can go as deep as they want to. So far, I'm able to achieve something similar to the JsFiddle link and I'm stuck badly after going 2 levels deep.
P.S: The numbers are added to show the relationship between a child to its siblings, its parent, and its children.
Update 1: This is what I've been able to achieve so far: JsFiddle
Update 2: Did some more work on this and was able to get it this far: jsFiddle
as discussed, i have worked it out on the fiddle.
please use the wrapElement() function to wrap your element in a div to your desire. In case you're loosing the fiddle, here's the code
$('.level_1').on('click', spawn);
function spawn(){
// check level
var level = stripLevel(this.className);
if (level !== '') {
var countOthers = this.parentNode.querySelectorAll("[class^='level_" + level +"']").length;
var x = wrapElement(level, countOthers);
if (level.length == 1) {
$('#addedElements').append(x);
} else {
//x.insertAfter(this);
$(this).parent().append(x);
}
}
}
// strip level
var stripLevel = function(className) {
var index = className.indexOf('_');
if(index > -1) {
return className.substr(index + 1);
} else {
return '';
}
}
// wrapper element
var wrapElement = function(level, number) {
var div = $('<div></div>');
if (level.length == 1) {
// it's parent
var input = $('<input type="text" name="foo_" />');
div.append(input);
} else {
// it's child
var span = $('<span>child level ' + level + '-' + number + '</span>');
div.append(span);
}
// add button
var button = $('<input class="level_' + level + '-' + number + '" type="button" value="Add Navigation" />');
button.on('click', spawn);
div.append(button);
div.css('margin-left', (level.length * 10) + 'px');
return div;
}
I wouldn't use the onclick attributes in html, but add the event handlers with javascrip
if your child nodes all use the same code, you could try to use a recursive approach:
function spawn(event) {
$(this).append(child);
$(child).on('click', function(event) {spawn(event);});
}
$('.parent').on('click', function(event) {spawn(event);});
was a first idea (with jquery), maybe it inspires you.
p.s. lacking the rep to make this comment, so it's an answer instead >.>
Based on the user3154108's answer, here's a recursive solution, you can start with:
$('.parent').on('click', spawn);
function spawn(){
var x = $('<input class="' + this.className + '-child" type="button" value="Add Navigation" />');
x.on('click', spawn);
x.insertAfter(this);
}
http://jsfiddle.net/Z9SBa/23/
Looking for some help on how to write a function to filter out certain divs with certain classes.
Essentially I have thrown together a quick e-commerce example. There are lists of different filters, with values. There are then products. Each product div has a number of classes applied to it, e.g "green" or "adult" or "wool" - these are the filterable parameters.
Not being savvy at all with JS I'm trying to write something, but looking for some advice. Here is basically what I'm after:
Starts with displaying all
If user selects GREEN, all items that do not have GREEN attributed are display:none'd (with a fade transition
Rep #2 for any attribute checked
Notes: multiple attributes can be checked, when items are unchecked, everything needs to reappear.
Any help? I guess it's basically linking up the value of each checkbox to the class.
Not sure if there is a better way codewise to do this... data attributes maybe?
Working example of the code here (obviously no JS)
Updated your fiddle and added some jQuery to hide the divs where the classes don't match the selected checkboxes.
Demo: fiddle
JS is a bit verbose, you can refactor it further if you like:
$(document).ready(function() {
var allSelectedClasses;
allSelectedClasses = '';
$('input[type="checkbox"]').click(function(){
//ensure the correct classes are added to the running list
if(this.checked){
allSelectedClasses += '.' + $(this).val();
}else{
allSelectedClasses = allSelectedClasses.replace($(this).val(), '');
}
//format the list of classes
allSelectedClasses = allSelectedClasses.replace(' ', '');
allSelectedClasses = allSelectedClasses.replace('..', '.');
var selectedClasses;
var allSelected;
allSelected = '';
//format these for the jquery selector
selectedClasses = allSelectedClasses.split(".");
for(var i=0;i < selectedClasses.length;i++){
var item = selectedClasses[i];
if(item.length > 0){
if(allSelected.length == 0){
allSelected += '.' + item;
}else{
allSelected += ', .' + item;
}
}
}
//show all divs by default
$("div.prodGrid > div").show();
//hide the necessary ones, include the 2 top level divs to prevent them hiding as well
if(allSelected.length > 0){
$("div.prodGrid > div:not(" + allSelected + ")").hide();
}
});
});
I added a new class to your Colors ul. Hope that's okay.
Here's a crude version of a filtering function, it only takes colors into account so you have to modify it yourself to take everything into account but the basic outline is there.
It can be refactored massively! :)
Since you're using jQuery:
$('ul.colorFilter li input[type="checkbox"]').click(function(){
var checkedBoxes = $('ul.colorFilter li input[type="checkbox"]:checked');
var listOfClasses = [];
checkedBoxes.each(function(index, el){
listOfClasses.push(el.value);
});
if(listOfClasses.length >= 1){
$('div.prodGrid').children('div').hide();
for(var i = 0; i < listOfClasses.length; i++){
$('div.prodGrid > div.'+listOfClasses[i]).show();
}
} else {
$('div.prodGrid > div').show();
}
});
I made a fiddle as well:
http://jsfiddle.net/Z9ZVk/4/