How to strip all elements but some? - javascript

I am generating <ul> and sub <ul>, what I would like to do is to place the html structure of the list only with its values in it. With the following code I get into the text area all the <ul> content not simply the:
HTML
<div id="mindMap">
<ul class="list-unstyled margin-bottom-20">
<li><button class="btn btn-default ul-appending margin-bottom-20">+ voce</button></li>
</ul>
</div>
<div id="mindMapData">
<textarea name="usp-custom-11" id="usp-custom-11" data-required="false" placeholder="Example Input 11" data-richtext="false" class="usp-input usp-textarea usp-form-365" rows="0" cols="30" style="margin: 0px; width: 871px; height: 291px;"></textarea>
</div>
jQuery
$('body').on('click', 'button.ul-appending', function() {
$(this).parent().append(
$('<ul class="main_ul list-unstyled margin-bottom-20">').addClass('newul').append(
$('<li class="margin-bottom-20"><div class="input-group margin-bottom-20"><input placeholder="Aggiungi una voce..." class="form-control" type="text"><div class="input-group-btn"><button type="button" class="btn btn-default list">+ sotto voce</button><button type="button" class="btn btn-default removeThis">elimina</button></div></div></li>')
)
);
});
$('body').on('click', 'button.list', function() {
var newLi = '<ul class="sub_ul list-unstyled margin-bottom-20"><li class="listSub margin-bottom-20"><div class="input-group margin-bottom-20"><input placeholder="Aggiungi una sotto voce..." class="form-control" type="text"><div class="input-group-btn"><button type="button" class="btn btn-default list">+ sotto voce</button><button type="button" class="btn btn-default removeThis">elimina</button></div></div></li></ul>';
var listEl = $(this).parent().parent().parent();
$(listEl).append(newLi);
});
Then I check for the the html changes and insert the html into the textarea like this:
$("#mindMap").on("DOMSubtreeModified",function(){
$("#mindMapData textarea").val($("#mindMap").html());
});
In the text area i get all the html tho:
<ul class="main_ul list-unstyled margin-bottom-20 newul">
<li class="margin-bottom-20">
<div class="input-group margin-bottom-20">
<input placeholder="Aggiungi una voce..." class="form-control" type="text">
<div class="input-group-btn">
<button type="button" class="btn btn-default list">+ sotto voce</button>
<button type="button" class="btn btn-default removeThis">elimina</button>
</div>
</div>
<ul class="sub_ul list-unstyled margin-bottom-20">
<li class="listSub margin-bottom-20">
<div class="input-group margin-bottom-20">
<input placeholder="Aggiungi una sotto voce..." class="form-control" type="text">
<div class="input-group-btn">
<button type="button" class="btn btn-default list">+ sotto voce</button>
<button type="button" class="btn btn-default removeThis">elimina</button>
</div>
</div>
</li>
</ul>
Here it is a working jsFiddle, see the content in the textarea is wrong, I am trying to get:
<ul>
<li>Added node
<ul>
<li>Added sub node</li>
</ul>
</li>
</ul>

You can traverse the DOM with this code:
function ul(indent) {
indent = indent || 4;
var node = $(this);
return node.removeAttr('class').children().map(function() {
var self = $(this);
var value = self.find('> .input-group input').val();
var sub_ul = self.find('> ul');
var ul_spaces = new Array(indent+4).join(' ');
var li_spaces = new Array(indent).join(' ');
if (sub_ul.length && ul) {
return li_spaces + '<li>' + value + '\n' + ul_spaces +
'<ul>\n' + ul.call(sub_ul, indent+8) + '\n' + ul_spaces + '<ul>\n' +
li_spaces + '</li>';
} else {
return li_spaces + '<li>' + value + '</li>';
}
}).get().join('\n');
}
function updateTree() {
$("#mindMapData textarea").val('<ul>\n' + $("#mindMap").clone().find('.main_ul').map(ul).get().join('\n') + '\n</ul>');
}
one side note you should call that updateTree function on keyup for each input because DOMSubtreeModified is not fired when input change it's value, see update fiddle http://jsfiddle.net/44yb96Lb/72/

I think parsing the DOM tree recursively and filtering out unwanted tags is much more easier to understand. Have a look:
/**
* #param {array<string>} allowedTags A list of tags that are allowed in the output
* #returns {function} A function that takes a jQuery elements and returns a copy with only the allowed elements
*/
function filterElementsFactory(allowedTags) {
allowedTags = allowedTags.map(function (tag) { return tag.toUpperCase(); });
/**
* #param {object} element jQuery element
* #returns {documentFragment}
*/
return function filterElements(element) {
element = element.clone();
var elementList = element.contents();
var finalElem = document.createDocumentFragment();
for (element of elementList) {
if (element.nodeType === Node.TEXT_NODE) {
finalElem.appendChild(element);
} else if (element.nodeType === Node.ELEMENT_NODE) {
if (allowedTags.indexOf(element.tagName) !== -1) {
var elemFrame = document.createElement(element.tagName);
elemFrame.appendChild(filterElements($(element)))
finalElem.appendChild(elemFrame);
} else {
finalElem.appendChild(filterElements($(element)));
}
}
};
return finalElem;
}
}
You can use this like this:
var allowedTags = ['ul', 'li'];
var filterElements = filterElementsFactory(allowedTags);
$("#mindMap").on("DOMSubtreeModified",function(){
var placeholderDiv = $('<div/>').append(filterElements($("#mindMap")));
$("#mindMapData textarea").val(placeholderDiv.html());
});

Related

How to get drag + drop Javascript code to apply to each individual task item, making each list item draggable, rather than items together in block?

My drag and drop code does not apply to each new added list item individually, but instead applies to all the list items in one block. However, the purpose of the drag and drop is to make the list items individually sortable and draggable. Any clue to how to correct the code to apply to each new task/list item that is appended under the 'To Do' list?
var $addButton = $(".btn-primary");
var $removeButton = $(".btn-danger");
var $todoList = $(".uncomplete");
var $doneList = $(".completed");
//Take Text Input and Add <li> to To Do List
$addButton.on("click", function(){
//Creating object Variables
var $sort = $(".sort").val();
var $newTask = $(".newTask").val();
var $taskDescr = $(".taskDescr").val();
var $taskDate = $(".taskDate").val();
// var $category= $(".category").val();
var $category= $("input[type='radio'][name='category']:checked").val();
//var $importance = $("input[type='checkbox'][name='importance']:checked").val();
var $importance = $('<input type="checkbox" name="importance"/>').val();
var $newTaskString = $sort + ", " + $taskDescr + ", " + $newTask + ", " + $taskDate + ", " + $category + ", " + $importance + " ";
var $todoList = $(".uncompleted");
//call append method on $todoList
$todoList.append("<li>" + $newTaskString + "<button><span> Done</span></button><button><span> Remove</span></button></li>").addClass("todo");
//drag and drop array
function allowDrop(e)
{
console.log("allow drop");
e.preventDefault();
}
function drop(e)
{
console.log("drop");
e.preventDefault();
var data = e.dataTransfer.getData("text");
e.target.appendChild(document.querySelector("#" + data));
}
function drag(e)
{
console.log("dragging");
//e.preventDefault();
e.dataTransfer.setData("text", e.target.id);
}
function showAllUsers(){
let allUsersDiv=document.querySelector("#allUsersDiv");
for(var i=0; i < allUsers.length; i++)
{
var newUserDiv=document.createElement("DIV");
newUserDiv.setAttribute("draggable", "true");
newUserDiv.setAttribute("ondragstart", "drag(event)"); //"editUser(this)"
newUserDiv.setAttribute("id", ("userdiv-" + i));
newUserDiv.setAttribute("style", "border:1px solid red;");
var newUserEditLink = document.createElement("A");
newUSerEditLink.setAttribute("href", "#");
newUSerEditLink.setAttribute("onclick", "editUSer(this)");
newUserEditLink.innerHTML = "Edit";
newUserEditLink.setAttribute("id", ("edit-", + i));
newUserDiv.innerHTML=allUsers[i].username;
newUserDiv.appendChild(nowUserEditLink);
allUsersDiv.appendChild(newUserDiv);
}
}
<div class="list-wrap" contenteditable="false">
<div class="list-inner-wrap">
<h2 class="title">ToDo List</h2>
<h3 class="title">Add Task</h2>
<!--<h4>Task Name</h4>-->
<label for="sort">Sort Order:</label><input type="text" class="sort"
name="sort" id="sort" value="" placeholder="A,B,C,etc.">
<br> </div></div>
<button class="btn btn-primary">
<span class="glyphicon glyphicon-plus"> Add</span>
</button>
<h3 class="title">To Do</h2>
<h6><i>Click task item to edit or modify</i></h6>
<!--Change color of editable task -->
<div id='div' contenteditable='false' oninput='change()'>
<div id="allUsersDiv" ondragover="allowDrop(event)" ondrop="drop(event)" style="position:absolute;left:5px;top:450px;height:200px;width:500px; border: 1px solid black">
<div draggable="true" ondragstart="drag(event)">
<ul class="uncompleted" contenteditable="false" id="id01" >
<li>Need to be completed task
<button class="btn btn-success">
<span class="glyphicon glyphicon-ok"> Done</span>
</button>
<button class="btn btn-danger">
<span class="glyphicon glyphicon-remove"> Remove</span></button>
<br>
</li></ul>
</div></div></div>

Creating dynamic cards using jQuery

I'm doing an e-trade site with jQuery; however, when I increase then submit one of the products, they all get the properties of the first product. I defined the products as a json to a variable.
How can I create dynamic cards with jquery?
Here is how it looks:
İmage
Here is the source code:
$(document).on('click', '.number-spinner button', function() {
var btn = $(this),
oldValue = btn.closest('.number-spinner').find('input').val().trim(),
newVal = 0;
newVal = (btn.attr('data-dir') === 'up') ? parseInt(oldValue) + 1 : (oldValue > 1) ? parseInt(oldValue) - 1 : 0;
btn.closest('.number-spinner').find('input').val(newVal);
});
let html = data.reduce((acc, {name,value,image,counter,totalMoney}) =>
acc + `
<div class='card col-md-3'>
<img class='card-img-top' src="${image}" alt='Card image cap'>
<div class='card-body'>
<h5 class='card-title'>${name}</h5>
<p class="card-text">${value}</p>
<input class="money-input money" value="${value}"/>
<div class="number-spinner">
<div class="input-group number-spinner">
<span class="input-group-btn">
<button type="button" class="btn btn-default btn-number btn-minus" data-type="minus" data-dir="dwn"><span>-</span></button>
</span>
<input min="1" class="adet input-number" value="${counter}" type="number">
<span class="input-group-btn">
<button type="button" class="btn btn-default btn-number btn-plus" data-type="plus" data-dir="up"><span>+</span></button>
<div class="total-price"></div>
</span>
</div>
</div>
<button class="submit">Add To Card</button>
</div>
</div>`
, ``);
$('#list').append(html);
const adet = $(".adet").val()
const money = $(".money").val()
const totalMoney = adet * money;
var endText = 'Price'
var space = ' '
$( ".submit" ).click(function() {
$(".total-price").text($(".adet").val() * totalMoney);
$('.total-price').append( space + endText);
});
The "problem" is that you have (possibly) multiple elements with the class .adet and .money. However, the .val() method of a jQuery collection only extracts the value of the first element it contains. See the jQuery docs:
Get the current value of the first element in the set of matched elements...
jQuery docs

append element to dynamically generated div using same classnames - Jquery

I have a toDo list for the very first list, I can add elements. I can also create multiple toDo lists dynamically, but while adding here it is been added to the very first list instead of the respective list where I click. Please someone help me, I am very new to JavaScript.
$toDoList = $('#toDoList');
$newTodoList = $('#newTodoList');
$parent = $('#parent');
$ul = $('ul');
$totalList = $('.totalList');
$(".remove").click(function() {
confirm('Are you sure? do you want to delete the item') ? $(this).parent().remove() : $(this);
});
$("li").click(function() {
$(this).hasClass("addBorder") ? $(this).removeClass("addBorder") : $(this).addClass("addBorder");
});
$('body').on('click', '.add', function() {
var itemName = $('#itemName').val();
var listItem = $('<li>' + itemName + '<button type="button" class="buttonStyle">-</button></li>');
listItem.on("click", function() {
confirm('Are you sure? do you want to delete the item') ? $(this).remove() : $(this);
});
$totalList.append(listItem);
$('#itemName').val('');
});
index = 1;
i = 1;
function addNewList() {
var newList = $('<div class="listParent" id="newList"><button type="button" class="addNewList" onClick="addNewList()">+</button><h2>My ToDO List!!</h2><ul id="toDoList" class="totalList"><li>Java script<button type="button" class="remove buttonStyle">-</button></li><li>Angular<button type="button" class="remove buttonStyle">-</button></li><li>Jasmine<button type="button" class="remove buttonStyle">-</button></li></ul><div class="inputText"><input type="text" id="itemName" class="leftmargin10" name="ListItem"><button type="button" id="addButton" class="buttonPlacement buttonStyle add">+</button></input></div></div>');
$('#newList').clone().attr('id', 'newList' + index++)
.insertAfter($('[id^=newList]:last'));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent" id="parent">
<div class="listParent" id="newList">
<button type="button" class="addNewList" onclick="addNewList()">+</button>
<h2>My ToDO List!!</h2>
<ul id="toDoList" class="totalList">
<li>Java script<button type="button" class="remove buttonStyle">-</button></li>
<li>Angular<button type="button" class="remove buttonStyle">-</button></li>
<li>Jasmine<button type="button" class="remove buttonStyle">-</button></li>
</ul>
<div class="inputText">
<input type="text" id="itemName" class="leftmargin10" name="ListItem"><button type="button" id="addButton" class="buttonPlacement buttonStyle add">+</button></input>
</div>
</div>
<!-- New list -->
The first thing I saw was that you are using multiple times the same id.
So I removed them all, since the "to do list" is to be cloned.
I simplified your code... I hope this will help.
// Remove (Delegate the clicks)
$(document).on("click",".remove",function(){
confirm('Are you sure? do you want to delete the item')? $(this).parent().remove():$(this);
});
// Li border (Delegate the clicks)
$(document).on("click","li",function(){
$(this).hasClass("addBorder")?$(this).removeClass("addBorder"):$(this).addClass("addBorder");
});
// Add a to do item to the list where the add button has been clicked.
$('body').on('click', '.add', function () {
// Find the relevant elements.
var thisParent = $(this).closest(".listParent");
var newTodoVal = thisParent.find(".newToDo");
var thisList = thisParent.find(".totalList");
// If there in a name inputed.
if(newTodoVal.val() !=""){
var listItem = "<li>"+newTodoVal.val()+"<button type='button' class='buttonStyle'>-</button>";
thisList.append(listItem);
newTodoVal.val('');
}
});
// Clone the last list to create a new one.
$(".addNewList").on("click",function(){
var lastList = $(".listParent").last();
lastList.clone().insertAfter(lastList);
});
.addBorder{
border:1px solid black;
max-width:10em;
}
.leftmargin10{
margin-left:10px;
}
.buttonStyle{
margin-left:0.5em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent">
<button type="button" class="addNewList">+</button>
<div class="listParent">
<h2>My ToDO List!!</h2>
<ul class="totalList">
<li>Java script<button type="button" class="remove buttonStyle">-</button></li>
<li>Angular<button type="button" class="remove buttonStyle">-</button></li>
<li>Jasmine<button type="button" class="remove buttonStyle">-</button></li>
</ul>
<div class="inputText">
<input type="text" class="leftmargin10 newToDo" name="ListItem">
<button type="button" class="buttonPlacement buttonStyle add">+</button>
</div>
</div>
<!-- New list -->
</div>
I assume that you click the + to add an item to a list.
You have this line of code:
$totalList.append(listItem);
In theory that should append listItem to every list which has class='totalList', I think you want it added only to the list where the + button was clicked, so I would change that line to
$(this).closest('.totalList').append(listItem);

add class in for loop button click

(function ($) {
$.fn.fCycle = function () {
var x;
for (x in arguments) {
$(arguments[x]).close();
}
$(this).collapse("show");
};
$(".btn-next").on('click', function() {
var form = [$("#name"), $("#surname"), $("#student_number"), $("#cellphone"), $("#email"), $("#course"), $("#year")],
i = 0,
a = "#" + $(this).attr("data-to"),
b = "#" + $(this).attr("data-from");
if ($(this).hasClass("to_course")) {
for (i; i < 5; i++) {
console.log(form[i].val());
if (form[i].val() === undefined) {
form[i].addClass("has-danger")
$(a).fCycle(b);
} else if (form[i].hasClass("has-danger") && form[i].length > 0) {
form[i].removeClass("has-danger")
}
}
$(a).fCycle(b);
}
});
}(jquery));
$(".btn-next").on('click', function () {
var form = [$("#name")],
i = 0,
a = "#" + $(this).attr("data-to"),
b = "#" + $(this).attr("data-from");
if ($(this).hasClass("to_course")) {
for (i; i < form.length; i++) {
if (form[i].val() === undefined) {
form[i].addClass("has-danger")
$(a).fCycle(b);
}
else if (form[i].hasClass("has-danger") && form[i].length > 0) {
form[i].removeClass("has-danger");
}
}
$(a).fCycle(b);
}
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.2/css/bootstrap.min.css" rel="stylesheet"/>
<form method="post" id="apply">
<div id="personal" class="collapse in">
<fieldset class="col-xs-10 col-xs-offset-1 form-group">
<div class="row">
<label for="names">Name(s)</label>
<input class="form-control" type="text" name="names" id="names" placeholder="Enter your full name here">
</div>
<hr>
<div class="row">
<nav>
<ul class="pager">
<li>
<button class="btn btn-danger btn-cancel" type="button">cancel</button>
</li>
<li class="pager-next">
<button class="btn btn-next btn-success to_course" type="button" data-to="course" data-from="personal">next</button>
</li>
</ul>
</nav>
</div>
</fieldset>
</div>
<div id="course" class="collapse">
<p>course</p>
</div>
</form>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.2/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
The above snippet doesn't seem to work at all - in the case of the Original (http://alpha.msauwc.co.za -> if you click on the Join the MSA button,
You'll find that the form does work. The issue is that the next button should not be working when the input fields have not been filled.
This has to be prevented using jquery.
Try defining your array with just selector strings, and then wrapping your form[i] objects like:
$(form[i]).val(), $(form[i]).addClass('has-danger'), etc
You can use these methods to disable & activate the button:
$(".btn-next").addClass('disabled') // when you want to disable it
$(".btn-next").removeClass('disabled') // when you want to activate it

How to get the value of a particular input field using id in the html templates

I have two div html elements with different id and here I am using spinner. Whenever values in the spinner input changes alert box will be displayed.
HTML code
<div id="accordion2" class="panel-group" style="display: block;">
<div id="accordion2" class="panel-group">
<div id="Tea">
<div class="spinner Tea input-group ">
<input type="text" id = "servings" class="form-control input- sm" value="Tea"/>
<div class="input-group-btn-vertical">
<button class="btn Tea btn-default">
<i class="fa fa-caret-up"></i>
</button>
<button class="btn Tea btn-default">
<i class="fa fa-caret-down"></i>
</button>
</div>
<h4 id="energy" class="Tea"> Tea </h4>
</div>
<div id="Coffee">
<div class="spinner Coffee input-group ">
<input type="text" id = "servings" class="form-control input-sm" value="Coffee"/>
<div class="input-group-btn-vertical">
<button class="btn Coffee btn-default">
<i class="fa fa-caret-up"></i>
</button>
<button class="btn Coffee btn-default">
<i class="fa fa-caret-down"></i>
</button>
</div>
<h4 id="energy" class="Coffee">Coffee</h4>
</div>
</div>
</div>
JQuery code
$(function(){
$('.spinner:first-of-type input').on('click', function() {
$('.spinner:first-of-type input').val(parseInt($('.spinner:first-of-type input').val(), 10) + 1);
var val = $('.spinner:first-of-type input').val();
changeValues(val);
});
$('.spinner:last-of-type input').on('click', function() {
$('.spinner input').val( parseInt($('.spinner input').val(), 10) - 1);
});
function changeValues(value){
alert($('#energy').attr('class').split(' '));
};
});
But in the alert box whenever I click the spinner up arrow only Tea is displayed.
what I expect is when the spinner is clicked from Tea div tea should be displayed and when from coffee , coffee should be displayed.Please help me out
I'm not sure I totally got what you are trying to do, but it seems to me that you want to increment and decrement number of beverage cups on up/down buttons click. For this you would better modify mark up a little (remove duplicated ids, add classes for convenience). And I may look like this then:
$(function() {
$('.spinner').on('click', '.servings', function(e) {
$(this).val(parseInt($(this).val() || 0, 10) + 1);
var val = $(this).val();
changeValues.call(e.delegateTarget, val);
})
.on('click', '.up', function(e) {
$(e.delegateTarget).find('.servings').val(function() {
return ++this.value;
});
})
.on('click', '.down', function(e) {
var $input = $(e.delegateTarget).find('.servings');
if (+$input.val() > 1) {
$input.val(function() {
return --this.value;
});
}
});
function changeValues(value) {
var type = $(this).find('.energy').data('type');
alert(type);
};
});
Demo: http://plnkr.co/edit/9vXC0RipxkzqhXrHJAKD?p=preview
try this:
$(function () {
$('.spinner').each(function () {
var $el = $(this),
$buttons = $el.find('button'),
$h4 = $el.find('h4'),
input = $el.find('input').get(0);
function showAlert() {
alert($h4.get(0).className);
}
$buttons.eq(0).on('click', function (event) {
event.preventDefault();
input.value = (parseInt(input.value, 10) || 0) + 1;
showAlert();
});
$buttons.eq(1).on('click', function (event) {
event.preventDefault();
input.value = (parseInt(input.value, 10) || 0) - 1;
});
});
});
JSFiddle http://jsfiddle.net/yLtn57aw/2/
Hope this helps

Categories

Resources