I'm building a website that will have a file upload. It should be possible to both upload picture, and also to drag and drop.
I have a droparea, that opens a file input once clicked.
Thereafter, it adds a new li where it is possible to delete the file.
However, I am not getting this to work with the drag and drop, no matter what I try.
In this fiddle you can see what my challange is.. pressing the field opens up correctly, and I can add and delete files.
It does not work when I drag and drop though.
https://jsfiddle.net/k14fgo0a/
<div class="upload-area text-center ml-4 py-4" id="dropContainer">
<i class="fa fa-upload mt-4 mb-2" style="font-size:50px"></i>
<p class=" mt-1" id="uploadText" style="font-size:18px">Upload file / drag file
here</p>
</div>
<ul class="list-group ml-4" id="attList">
<li class="border-0 bg-transparent" style="list-style-type: none;">
<input id="fileInput" value="%attachments%" type="file" name="attachment_0" class="attachment" />
</li>
</ul>
window.addEventListener("drop", function (e) {
e = e || event;
$(".upload-area").removeClass("onHover");
$("#uploadText").text("Upload file / drag file here");
e.stopPropagation();
e.preventDefault();
}, false);
$(document).ready(function () {
$('#attList').on('change', '.attachment', function () {
var currentInput = $(this);
var inputName = currentInput.attr('name');
var filename = currentInput.val().replace(/C:\\fakepath\\/i, '');
currentInput.css('display', 'none');
$('<li>' + filename + '<button type="button" class="remove ml-2 remove btn btn-danger btn-sm">Delete</button></li>').insertBefore(currentInput);
var idsInput = $('#attachment_ids');
var ids = idsInput.val();
if (ids != '')
idsInput.val(ids + ',' + inputName);
else
idsInput.val(inputName);
var number;
var arr = inputName.split('_');
if (arr.length > 1)
number = parseInt(arr[1]);
number += 1;
$('<li class="mb-1" style="list-style-type: none;"><input id=\"fileInput\" class=\"' + currentInput.attr('class') + '\" type=\"file\" name=\"' + arr[0] + '_' + number + '\" /></li>').insertBefore(currentInput.closest('li'));
});
any help would be appreciated!
Related
I have a list of items. I can create some items. The problem is that when I push the delete button I want all values to refresh and change. How can I do that?
For example when I delete the third number, then the fourth tag will be third.
$(document).on("click", ".addnew", function() {
id = this.id;
var idsh = parseInt(id.substr(3));
var ids = parseInt(id.substr(3)) + 1;
document.getElementById("ad_" + idsh).style.display = "none";
kanban = document.getElementById("kanban");
var btn = document.createElement("p");
btn.id = "main_" + ids;
btn.innerHTML =
'<span type="text" id="co_' + ids + '" class="counter text-center bg-success text-white" >' + ids + ' </span>' +
'<span id="mo_' + ids + '" class="formulbitti text-center bg-success text-white" > inner </span>' +
'<button id="de_' + ids + '" class="delete text-center bg-success text-white" >delete</button> ' +
'<button type="text" id="ad_' + ids + '" class="addnew text-center bg-success text-white" >add</button>';
kanban.appendChild(btn);
});
$("body").on("click", ".delete", function() {
id = this.id;
var ids = id.substr(3);
$('#main_' + ids).remove();
});
<script type="text/javascript" language="javascript" src="https://code.jquery.com/jquery-3.5.1.js"></script>
<div id="kanban">
<span type="text" id="co_1" class="counter text-center bg-success text-white">1</span>
<span type="text" id="mo_1" class="formulbitti text-center bg-success text-white">inner</span>
<button type="text" id="de_1" class="delete text-center bg-success text-white">delete</button>
<button type="text" id="ad_1" class="addnew text-center bg-success text-white">add</button>
</div>
Do not use incremental id attributes. As you can see in your code they add needless complication and have absolutely no benefit.
The best method to do what you require is to use DOM traversal to relate elements to each other. The only tweak you need to make to your HTML is to add a new div to group the span and button elements. From there when a button is clicked you can use closest() to retrieve the nearest .row container and clone/remove it.
The benefit of this is that the HTML becomes standardised and the JS to work with it is the same, regardless of the content or position.
To solve the issue of the counters being updated when an action is performed, create a function which iterates through all the .counter elements and updates their text based on their index in the DOM.
Finally note that button elements have a type of button or submit, never text.
With all that said, try this:
let $kanban = $('#kanban');
let updateCounters = () => $kanban.find('.counter').text(i => i + 1);
$(document).on("click", ".addnew", e => {
$(e.target).closest('.row').clone().appendTo($kanban);
updateCounters();
});
$(document).on("click", ".delete", e => {
$(e.target).closest('.row').remove();
updateCounters();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" language="javascript" src="https://code.jquery.com/jquery-3.5.1.js"></script>
<div id="kanban">
<div class="row">
<span type="text" class="counter text-center bg-success text-white">1</span>
<span type="text" class="formulbitti text-center bg-success text-white">inner</span>
<button type="button" class="delete text-center bg-success text-white">delete</button>
<button type="button" class="addnew text-center bg-success text-white">add</button>
</div>
</div>
One last thing to note is that it's a litte odd to have a table-level 'add' button on each row. It would make more sense to have a single add button at the top or bottom of the content.
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>
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
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());
});
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