I have the following:
<!-- group clone //-->
<div class="section">
<div class="parent row infoOn">
<div class="validGroup">
<a title="remove" class="iconClose" href="#">remove</a>
<div class="grouping">
<div class="clearfix valid">
<label>Name<span class="iconReq"> </span>:</label>
<input type="password" class="text inpButton" name="items[0].first">
</div>
<div class="clearfix">
<label>Email<span class="iconReq"> </span>:</label>
<input type="text" class="text inpButton" name="items[0].first">
</div>
</div>
</div>
</div>
<div class="row addControl">
Add
</div>
</div>
<!-- group clone //-->
and jQuery:
$(function(){
// Control clone
$('div.addControl a.button').click(function (e){
e.preventDefault();
var parent = $(this).closest('.section').find('.parent:last');
var parentInput = parent.clone();
parentInput.find("input").val("");
parent.after(parentInput);
});
$('div.validGroup a.iconClose').live('click', function (e){
e.preventDefault();
if ($(this).closest('.section').find('.parent').length > 1){
$(this).closest('div.parent').remove();
}
});
reflesh();
});
clicking the "Add" button removes
values from input fields and clones
the group (2 input fields).
clicking "remove" link removes
group
Question: how would I change it so that when adding OR removing a new group, input fields would be renamed to name="items[INDEX].first" and name="items[INDEX].last"
For example. when there's only one "group", input fields would have names:
name="items[0].first"
name="items[0].last"
if I add another one, the new one would have
name="items[1].first"
name="items[1].first"
and so on.
When I remove the first one (one with items[0].first), the second one's input names would be modified from "items[1].first" to items[0].first.
here is what it looks like:
I figured it out:
var size = parseInt($('.form .section .parent').size());
$('.form .section .parent').each(function(index){
$(this).find('input.text').each(function(){
$(this).attr("name", $(this).attr("name").replace($(this).attr("name").match(/\[[0-9]+\]/), "["+index+"]"));
});
if (size > 1) { $(this).find('a.iconClose').show(); }else{ $(this).find('a.iconClose').hide(); }
});
$('.add-more').on('click',function(){
var newelement= $(".form-content").eq(0).clone();
var num = $('.form-content').length;
var newNum = num + 1;
newelement.find('input').each(function(i){
$(this).attr('name',$(this).attr('name')+newNum);
$(this).attr('id',$(this).attr('id')+newNum);
});
$('.form-content').last().after(newelement);
});
Related
I have a problem concerning the use of .append("..."). I am coding a simple To-Do List and want to delete a list element when I click on the appended "REMOVE" button by reference to the buttons class.
I think it is not working because .append() isn't changing the html code of the website. At least I can't spot a difference after clicking the "ADD ITEM" button.
Do you have any ideas?
Thanks in advance!
var inputText;
var itemList = [];
$("#addButton").click(function(){
inputText = $("#textInput").val();
itemList.push(inputText);
$("#textInput").val("");
showItems();
});
//not working
$(".deleteButton").click(function(e){
console.log("test");
var className = e.attr("id");
console.log("ID:" + className);
});
function showItems(){
$("#list").html('');
for(var i=0; i<=itemList.length-1; i++){
$("#list").append('<div class="listelement"><p type="text" class="listItem" id="listItem '+ i +'">'+ itemList[i] +'</p> <button type="button" class="deleteButton" id="'+ i +'">REMOVE</button><div>');
}
}
<body>
<div class="container">
<div class="headline">
<h1 id="headline">TO DO LIST</h1>
</div>
<div class="userInput">
<input type="text" id="textInput">
<button type="button" id="addButton">ADD ITEM</button>
</div>
<div class="list" id="list">
<div class="listelement" id="listelement">
</div>
</div>
</div>
<script src="jquery-3.4.1.min.js"></script>
<script src="script.js"></script>
</body>
</html>
You need to use event delegation.
$(document).on("click",".deleteButton",function(e) {
$(this).closest(".listelement").remove()
});
$(".deleteButton").click(function(e){ will only work on those elements that exist on the page, but not on newly added elements.
var inputText;
var itemList = [];
$("#addButton").click(function() {
inputText = $("#textInput").val();
itemList.push(inputText);
$("#textInput").val("");
showItems();
});
//not working
$(document).on("click",".deleteButton",function(e) {
$(this).closest(".listelement").remove()
});
function showItems() {
$("#list").html('');
for (var i = 0; i <= itemList.length - 1; i++) {
$("#list").append('<div class="listelement"><p type="text" class="listItem" id="listItem ' + i + '">' + itemList[i] + '</p> <button type="button" class="deleteButton" id="' + i + '">REMOVE</button><div>');
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="headline">
<h1 id="headline">TO DO LIST</h1>
</div>
<div class="userInput">
<input type="text" id="textInput">
<button type="button" id="addButton">ADD ITEM</button>
</div>
<div class="list" id="list">
<div class="listelement" id="listelement">
</div>
</div>
</div>
If you just want to remove that specific div where you are clicking you can use following code. You dont need to match id here.
$(document).on("click",".deleteButton",function(e){
let parent = $(this).closest(".listelement");
parent.remove();
});
But according to your code after delete if you add something, all the data of the array will show.Because you are not deleting data from array. I think you need to delete that data from the array too.
$(document).on("click",".deleteButton",function(e){
let parent = $(this).closest(".listelement");
let id = $(this).attr("id");
console.log(id);
itemList.splice(id, 1);
parent.remove();
});
The issue here is that the element appended doesn't have an event listener attached to it, when you're calling $(...).click it will attach an event listener only to the currently existing elements. Since you're calling it when the document loads and there are no elements with the class deleteButton at that time it won't do anything.
You can solve this by moving the deletion code to it's own function and attaching a click event listener for each new element you create.
In order to do so efficiently, you'll need to get the element you're creating, you can do this like so:
$(HTML Code).appendTo('#list').click(...);
This will create an element from the html you pass it, append it to the element with the id list and attach a click event listener to it, so in the end this will the result:
var inputText;
var itemList = [];
$("#addButton").click(function() {
inputText = $("#textInput").val();
itemList.push(inputText);
$("#textInput").val("");
showItems();
});
function deleteItem(e) {
console.log(e.target.id);
}
function showItems() {
$("#list").html('');
for (var i = 0; i <= itemList.length - 1; i++) {
var html = '<div class="listelement"><p type="text" class="listItem" id="listItem ' + i + '">' + itemList[i] + '</p> <button type="button" class="deleteButton" id="' + i + '">REMOVE</button><div>';
$(html).appendTo('#list').click(deleteItem);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="headline">
<h1 id="headline">TO DO LIST</h1>
</div>
<div class="userInput">
<input type="text" id="textInput">
<button type="button" id="addButton">ADD ITEM</button>
</div>
<div class="list" id="list">
<div class="listelement" id="listelement">
</div>
</div>
</div>
If you try to do something with the elements that are dynamically added to DOM using the jQuery click() method it will not work, because it bind the click event only to the elements that exist at the time of binding
you can use
$(document).on("click", "button.deleteButton" , function() {
$(this).parent().remove();
});
https://jsfiddle.net/82d0e5at/3/
Summary: The purpose of this is to display a 3-part slider that users can click through, and they can use the index on each slide to filter the cards on that slide to a specific topic. The filters are working fine, but there's a problem in the JavaScript when it populates the indices: it's populating an index for all 3 cards, and showing that large index on each slide. Instead, the index for each slide needs to be unique, and only contain the hashtags from the cards in that same slide. I really want to avoid duplicating code for the different slides.
HTML
The following HTML has 3 (li) slides. Each slide contains a visible index (.hashtag-list), and one or more article cards (.item). Each (.item) besides the first one contains a hidden input with one or more hashtag values.
<li class="trend-cards">
<div class="card-items">
<div class="item trendingtopiccardblock">
<div class="hashtag-list"></div>
</div>
<div class="item">
<input class="tags" type="hidden" value="TopicA,TopicB"/>
</div>
<div class="item">
<input class="tags" type="hidden" value="TopicC"/>
</div>
</div>
</li>
<li class="trend-cards">
<div class="card-items">
<div class="item trendingtopiccardblock">
<div class="hashtag-list"></div>
</div>
<div class="item">
<input class="tags" type="hidden" value="TopicC, TopicD"/>
</div>
<div class="item">
<input class="tags" type="hidden" value="TopicA,TopicC,TopicD"/>
</div>
</div>
</li>
<li class="trend-cards">
<div class="card-items">
<div class="item trendingtopiccardblock">
<div class="hashtag-list"></div>
</div>
<div class="item">
<input class="tags" type="hidden" value="TopicA, TopicD"/>
</div>
<div class="item">
<input class="tags" type="hidden" value="TopicB,TopicC,TopicD"/>
</div>
</div>
</li>
JavaScript
The following jQuery pulls the values from the .tags classes, stores them in an array, removes duplicates, sorts them, and then populates the HTML in a callback. (Ignore the countryButtons and countries array, as that's not relevant.)
populateHashtagList: function() {
var $cards = $(".card-items .tags");
var list = [];
var $countryButtons = $('.card-filtering li .country-filtering');
var countries = [];
$countryButtons.each(function() {
countries.push(this.firstChild.data.replace("#", "").toLowerCase());
});
//Get tag values, set to lowercase and store in List array
$cards.each(function() {
var tags = getTags($(this).val());
$(tags).each(function (index, value) {
var tagValue = value.toLowerCase();
if($.inArray(tagValue, countries) === -1) list.push(value);
});
});
//Remove duplicates from the array
var uniqueTags = [];
$.each(list, function(i, el){
if($.inArray(el, uniqueTags) === -1) uniqueTags.push(el);
});
uniqueTags.sort();
function getTags(parameter) {
var arr = parameter.split(',');
return arr;
}
//Populate hash-tag List
var hashtagList = $('.hashtag-list');
populateHashtagList();
function populateHashtagList(callback) {
$.each(uniqueTags, function(i, el){
var htmlToInsert = '<span class="active">' + el + '</span>';
hashtagList.append(htmlToInsert);
});
if(typeof callback == "function")
callback();
}
}
What I've tried
Isolating the function using a $(".trend-cards").each function. This resulted in the same large list, but it was tripled on each slide.
Adding more specific paths to the .tags selectors, which changed nothing.
Using a parent selector once the .tags variable is set, and calling the remainder of the function from there. No hashtags populate in this case.
I appreciate any feedback and input on this. I want to learn how to do this better in the future. Thank you very much!
Wrapping this code in .each() function is the best solution here. You said you tried that and you probably forgot to specify parent element for cards and hashtag-list selectors.
Here is a working example: https://jsfiddle.net/k3oajavs/
$(".trend-cards").each(function(){
var $cards = $(".card-items .tags", this);
// ...
var hashtagList = $('.hashtag-list', this);
});
Not sure if this is possible, I'm just starting to learn javascript and jQuery. If the way that I would like is not possible, I am very open to hearing of different ways I may be able to achieve this.
I want to display a datepicker, the user will click on dates and when they do a dialog box appears which has specific predefined data in it. They can select a different date, and it will open another dialog box with different predefined data in it, and I want to keep track of the dates that they click on.
<div id="tabs">
<ul>
<li>First</li>
<li>Second</li>
<li>Third</li>
</ul>
<div id="tabs-1">
<p>I'm going to have different data applying to only this day</p>
</div>
<div id="tabs-2">
<p>I'm going to have different data applying to only this day</p>
</div>
<div id="tabs-3">
<p>I'm going to have different data applying to only this day</p>
</div>
</div>
Open jQuery dialog box upon selecting a date from jQuery datepicker inline
That link was useful because a user has a jsfiddle posted: http://jsfiddle.net/qqabC/ which is a start to what I am trying to do, I am just not sure of how or if it is even possible to incorporate divs into the dialog boxes like so. I keep messing around with it but I have been getting nowhere. Each date that is selected will have different dialog box content in it.
If this is not possible, what would be the best way to achieve this? Thank you.
--Edit:
I still need to implement the divs that I have defined above with div id "tabs". Tabs = workout days. So tabs-1 to tabs-5 would be 5 total days. tabs-1 is going to be their first click which is day 1 form content, tabs-2 will be their second click which is day 2 form content, and so on. I believe I should use a for loop, because which each click the div is being incremented onto the next one. I was trying to do something like:
var divs = $('#tabs > div[id]');
var links = $('#tabs li');
divs.hide();
for (i=0;i<=max_workouts;i++) {
$('#tabs li').on('click', function(e){
var clickedID = $(this).attr('href').clone().appendTo(#workout-modal);
}
Something like that, to iterate through the div's with each click, but it's not working, I have been trying to find examples of placing existing div content in modals but there is nothing on iterating through divs in this way, do you have any suggestions?
Here is an example of how you could achieve this functionality using Bootstrap. Of course you'll need to change the functionality and design as needed but this should be a fair start
The workflow is as follows:
User clicks a date
Modal is displayed with various inputs
Inputs are cleared when modal opens
User enters info in the inputs
User clicks add workout
A span label is added to the display showing the workout number and the date selected
This span has data attributes set to store the date, title, and each of the values from the modal inputs
If user clicks the "X" on the right end of the span, it is removed
If user clicks the span label anywhere else it reopens the modal and populates the inputs with the data stored as attributes on the span
If the user clicks add workout after loading an existing one, the new span replaces the old one instead of adding to the end of the div
Here is a jsFiddle also
$(function(){
var max_workouts = 5;
$('#workout-datepicker').datepicker({
startDate: "today"
}).on('changeDate', function(e) {
var cur = $('.workout-label').length;
if (cur < max_workouts) {
var workoutDate = e.format('mm/dd/yyyy');
var title = 'Workout ' + (cur + 1) + ' - ' + workoutDate;
openModal(title, workoutDate);
}
else{
var $tooMany=$('#too-many');
$tooMany.show();
setTimeout(function(){ $tooMany.hide() }, 2000);
}
});
var $workoutLabelsContainer = $('#workout-labels-container');
$('#add-workout').click(function() {
var $workoutModal = $('#workout-modal');
var workoutDate = $workoutModal.data('workout-date');
var title = $workoutModal.data('workout-title');
var vaule1 = $('#modal-workout-value-1').val();
var vaule2 = $('#modal-workout-value-2').val();
var $workout = $('<span class="label label-primary workout-label col-sm-12">' + title + '<span class="glyphicon glyphicon-remove pull-right remove-workout" aria-hidden="true"></span></span>');
var clickedLabelIndex = $workoutModal.data('crurent-label-index');
$workout.data('workout-title', title).data('workout-date', workoutDate).data('value-1', vaule1).data('value-2', vaule2);
if (clickedLabelIndex == -1) $workoutLabelsContainer.append($workout);
else($('.workout-label').eq(clickedLabelIndex).replaceWith($workout))
$workoutModal.modal('hide');
});
$workoutLabelsContainer.on('click', '.remove-workout', function(e) {
e.stopPropagation();
$(this).closest('.workout-label').remove();
})
$workoutLabelsContainer.on('click', '.workout-label', function() {
var $workoutLabel = $(this);
var workoutDate = $workoutLabel.data('workout-date');
var title = $workoutLabel.data('workout-title');
var value1 = $workoutLabel.data('value-1');
var value2 = $workoutLabel.data('value-2');
var labelIndex = $('.workout-label').index($workoutLabel);
openModal(title, workoutDate, value1, value2, labelIndex);
});
function openModal(title, workoutDate, value1, value2, labelIndex) {
var $workoutModal = $('#workout-modal');
var $value1 = $('#modal-workout-value-1').val('');
var $value2 = $('#modal-workout-value-2').val('');
$workoutModal.data('workout-title', title).data('workout-date', workoutDate);
$('#workout-modal-title').html(title);
if (value1) $value1.val(value1);
if (value2) $value2.val(value2);
if (labelIndex !== 'undefined' && labelIndex > -1) $workoutModal.data('crurent-label-index', labelIndex);
else $workoutModal.data('crurent-label-index', -1);
$workoutModal.modal({
show: true
});
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.5.1/js/bootstrap-datepicker.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.5.1/css/bootstrap-datepicker.min.css" rel="stylesheet"/>
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<style>
.workout-label {
padding: 6px;
font-size: 16px;
width: 100%;
display: block;
margin-bottom: 5px;
cursor: pointer;
}
.remove-workout {
cursor: pointer;
}
#too-many{
display:none;
}
</style>
<br>
<br>
<div class="container well" id="workout-container">
<div class="row">
<div class="col-xs-6">
<div id="workout-datepicker"></div>
</div>
<div class="col-xs-6" id="workout-labels-container">
</div>
</div>
<div class="alert alert-danger" id="too-many" role="alert">Maximun reached</div>
</div>
<div id="workout-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="workout-modal-title"></h3>
</div>
<div class="modal-body">
<form class="form-horizontal" role="form">
<div class="form-group">
<label for="firstname" class="col-sm-4 control-label">Some short text:</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="modal-workout-value-1" placeholder="">
</div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-4 control-label">Some longer text:</label>
<div class="col-sm-8">
<textarea class="form-control" id="modal-workout-value-2" name="textarea"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
<button type="button" class="btn btn-primary" id="add-workout">Add workout</button>
</div>
</form>
</div>
</div>
</div>
I need to loop through a list of divs. If a div in that list has the class name of "active", than I need to save the contents of the <p></p> tag of the specific div to a variable. I then need to place the contents of that variable in a the value of a hidden input element on a form. For example, here is some example HTML:
<div class="names">
<div class="one active">
<p>A</p>
</div>
<div class="two active">
<p>B</p>
</div>
<div class="three">
<p>C</p>
</div>
<div class="four active">
<p>D</p>
</div>
<div class="five">
<p>E</p>
</div>
<div class="six active">
<p>F</p>
</div>
</div>
<form action="form.php" method="POST">
<input type="hidden" name="list" id="list" value="">
</form>
Since four of the divs contain the "active" class, I need to save the content that is in each paragraph tag to a variable to be inserted into the value of the hidden field. In this example, the value of the field would be A, B, D, F.
I thought about doing something like this:
var userSelection = function() {
$('.names div').each(function () {
if($(this).hasClass('active')) {
return $(this).text();
}
});
};
$('#list').val(userSelection);
First off, that code doesn't work and I am also not even sure if that's the best way to go about solving my problem. Second, if anyone has a better idea of how to accomplish what I need, I would love to hear it.
I would use map() to get an array of the text:
var textArr = $('.names div.active').map(function() {
return $(this).text();
}).get();
From there, you could use join() to get a string you could write to the DOM:
var textString = textArr.join(', ');
Full, compressed code:
var userSelection = function() {
return $('.names div.active').map(function() {
return $(this).text();
}).get().join(', ');
};
$('#list').val(userSelection());
Alternative to Jason P's answer is to modify what you've got to return an array of the results, as you're calling a function into a variable that has multiple results:
var userSelection = function() {
var output = [];
$('.names div').each(function () {
if($(this).hasClass('active')) {
output.push( $(this).text().trim() );
}
});
return output;
};
See JSFiddle.
Working fiddle: http://jsbin.com/uQEJIkU/3/edit
$(document).ready(function() {
values = []
$("div.active > p").each( function() {
values.push($(this).text())
})
})
I have 2 images (.field-img) , wrapped in a container (.group-container),
each of the images are in a unique field id, so my tpl is broken down into
<div class=group-container>
<div id=field1>
<div class=field-img>
</div></div>
<div id=field2>
<div class=field-img>
</div></div>
</div>
my js is
$(".group-container .field-img").click(function() {
alert(".group-container .field-img");
what I would like is to detect automatically if the image belongs to field1 or field2.
So I could alert (".group-container .field1/2 .field-img");
How would I do this?
Thanks for any help
$(".group-container .field-img").click(function() {
var field=$(this).parent().attr('id');
});
An alternative to Izzey's solution is to use .closest with an attribute starts with selector (or classname because it would be more appropriate for those divs to have a common class)
$(".group-container .field-img").click(function() {
var field = $(this).closest("[id^=field]")[0].id;
});
or, with a common classname,
html
<div class=group-container>
<div class="field" id=field1>
<div class=field-img>
</div></div>
<div class="field" id=field2>
<div class=field-img>
</div></div>
</div>
js
$(".group-container .field-img").click(function() {
var field = $(this).closest(".field")[0].id;
});
$(".group-container .field-img").click(function() {
var field = this.parentNode.id;
alert (".group-container ." + field + " .field-img");
});
$(".group-container .field-img").each(function() {
$(this).click(function(){
var fieldid=$(this).parent().attr('id');
});
});
Since one element is inside the other, the click will propagate up anyway, so you could always just bind the click to the parent element and do :
$('div[id^="field"]').on('click', function() {
alert(".group-container "+this.id+" .field-img");
});
FIDDLE
or even get them all dynamically:
$('div[id^="field"]').on('click', function(e) {
alert('.'+this.parentNode.className+" "+this.id+" ."+e.target.className);
});
FIDDLE