Hiding and showing div series using Javascript - javascript

I'm making basic GPA calculator using Javascript.
Here is my code:
<div class="list">
<div class="row">
<div class="col col-50">Subject 1</div>
<div class="col"><input type="text" name ="GR1" placeholder="Grade"></div>
<div class="col"><input type="tel" name="CR1" placeholder="Credits"></div>
</div>
<div class="row">
<div class="col col-50">Subject 2</div>
<div class="col"><input type="text" name ="GR2" placeholder="Grade"></div>
<div class="col"><input type="tel" name ="CR2" placeholder="Credits"></div>
</div>
<button class="button button-positive">
Add Another Field //it can add uptop 10 fields
</button>
</div>
It will increment the same div series while incrementing the input name up to 10 fields. User can click Add Another Field and add a new div field.
In every div field, it only changes the subject and input fields' name with an incrementation of 1.
Question:
What is the best way to achieve this without duplicating the same thing over and over? Or do I need to first create 10 div forms and hide all and show them one by one upon each click? Please give me example.

Here is a solution that is in pure Javascript that will allow you to add up to 10 "field blocks". In the HTML file, put:
<div id="list">
<button onclick="addRow()">Add another field</button>
</div>
And here's the Javascript function to add a new row, and initialise the two first row:
<script type="text/javascript">
window.onload = function() {
addRow();
addRow();
};
function addRow() {
var element = document.getElementById('list');
var nextId = element.childElementCount;
if (nextId <= 10) {
var div = document.createElement('div');
div.setAttribute('class', 'row');
div.innerHTML = '<div class="col col-50">Subject ' + nextId + '</div><div class="col"><input type="text" name ="GR' + nextId + '" placeholder="Grade"></div><div class="col"><input type="tel" name="CR' + nextId + '" placeholder="Credits"></div>';
element.insertBefore(div, element.getElementsByTagName('button')[0]);
}
}
</script>
You can try it online on the following fiddle: https://jsfiddle.net/w82t30r4/

Try jQuery's clone (read about it here)
$(document).ready(function(){
$row = $(".row").clone();
$("button").click(function(){
$(".list").append($row.clone());
})
})
What's happening is that I clone the row to start with (before any data is in it). Then I add a clone of that clone to .list when the button is clicked.

Related

How to Remove a Div using variable parameters?

I'm trying to create a way to add entries to my form so that the user can choose how many he wants, but I can't get the remove part working.
JavaScript
var i = 1;
var divContent = document.getElementById('formulario');
//Click to add a field
function cria() {
//This add a HTML Inputs and divs who the ID is variable how the 'i' is increasedf
document.getElementById('formulario').innerHTML += '<div class="mb-1 col-3" id="div'+i+'"><label for="nomeTx0" class="form-label">Nome</label><input type="text" class="form-control" id="nomeTx'+i+'" name="nomeTx'+i+'" required></div><div class="mb-1 col-3" id="div2'+i+'"><label for="taxa'+i+'" class="form-label">Valor</label><input type="float" class="form-control" id="taxa'+i+'" name="taxa'+i+'" required></div>- Remover campo';
i++;
}
function remove(div1, div2){
var div = document.getElementById(div1);
var div2 = document.getElementById(div2);
div.remove();
div2.remove();
i--;
}
And now the HTML
<form>
<h4 class="card-tittle text-center">Taxas</h4>
<div id="formulario" class="form row align-items-start">
<div class="mb-1 col-3" id="0">
<label for="nomeTx0" class="form-label">Nome</label>
<input type="text" class="form-control" id="nomeTx0" name="nomeTx0" required>
</div>
<div class="mb-1 col-3" id="0">
<label for="taxa0" class="form-label">Valor</label>
<input type="float" class="form-control" id="taxa0" name="taxa0" required>
</div>
</div>
+ adicionar campo
<div class="mb-1 col-lg-12" style="text-align: center;">
<button class="btn btn-primary col-5" id="Enviar" type="submit" text="Enviar">Adicionar Taxas</button>
</div>
</form>
ID="taxa"+i but when I call the remove(); error is printed to me saing the variable is null.
This is really not the right approach in the first place.
Your fundamental problem is that you are relying on ids to know what element(s) to add and remove and this is leading you to concatenate an id onto dynamically created elements, made from long strings with variables concatenated into them. In reality, you should avoid ids whenever possible as they make your code very brittle and don't scale well.
This is a perfect use for the HTML <template> element. As you can see from the re-worked code below, all ids have been removed - - you don't need them. Additionally, instead of long strings with a variable concatenated into it, you just need to copy/clone the template whenever you need one. Then, you can use "event delegation" and smartly organized HTML to just set up a single click event on a master wrapper element, where the actual element that was clicked (the event.target) can be checked. If it was a remove button, then just remove the entire wrapper that is the nearest ancestor to the remove button that was clicked.
You can now add and remove as many items as you like with no need for an id or counting variables!
// Get a reference to the template, outer div and the add "button"
const template = document.querySelector("template");
const wrapper = document.querySelector(".wrapper");
const add = document.querySelector(".add");
// Set up the add event in Javascript, not with inline HTML
add.addEventListener("click", function(event){
var clone = template.content.cloneNode(true); // Clone the template
wrapper.appendChild(clone);
});
// Set up a wrapper level click event that any clicks within it will bubble up to
wrapper.addEventListener("click", function(event){
// Test to see if it was remove "button" that was clicked
if(event.target.classList.contains("remove")){
// Just remove the closest ancestor div that holds that particular group
// and remove it.
event.target.closest("div.templateWrapper").remove();
}
});
.mb-1.col-lg-12 {
text-align:center;
}
.mb-1.col-3 {
margin:2px;
}
.add, .remove {
cursor:pointer;
color:blue;
}
.labelName { display:inline-block; width:3em; }
/* This is just to better see the groups */
.templateWrapper, .form {
background-color:aliceblue;
padding:5px;
margin:8px;
}
<!-- This will not initially be shown on the page.
It will be used to copy from when/if needed. -->
<template>
<div class="templateWrapper">
<div class="mb-1 col-3">
<label class="form-label"><span class="labelName">Nome</span>
<input type="text" class="form-control" name="nomeTx" required>
</label>
</div>
<div class="mb-1 col-3">
<label class="form-label"><span class="labelName">Valor</span>
<!-- An input does not have a type=float -->
<input class="form-control" name="taxa" required>
</label>
</div>
<span class="remove">- Remover campo</span>
</div>
</template>
<form>
<h4 class="card-tittle text-center">Taxas</h4>
<!-- Hyperlinks are for navigation, not JavaScript click hooks. Any visible element
supports a click event. Use span and div for generic clickable inline or block
elements that need to have click event handlers. -->
<span class="add">+ adicionar campo</span>
<div class="wrapper">
<div class="form row align-items-start">
<div class="mb-1 col-3">
<label class="form-label"><span class="labelName">Nome</span>
<input type="text" class="form-control" name="nomeTx0" required>
</label>
</div>
<div class="mb-1 col-3">
<label class="form-label"><span class="labelName">Valor</span>
<input type="float" class="form-control" name="taxa0" required>
</label>
</div>
</div>
</div>
<div class="mb-1 col-lg-12">
<!-- A button does not have a "text" attribute -->
<button class="btn btn-primary col-5" type="submit">Adicionar Taxas</button>
</div>
</form>
You would like to pass the ids of the html elements to function remove , instead you pass something else.
Try this:
function remove(d1, d2){
//what are passing to function... id , or something else ?
console.log(d1,d2);
// now I force the arguments passed to function to a valid value id for test
var a = document.getElementById('div1'); // id is div1
var b = document.getElementById('div21'); // id is div21
//Ask to parentNode to remove his child
a.parentNode.removeChild(a);
b.parentNode.removeChild(b);
i--;
}
The problem in your code is that you don't pass a string to the remove function but instead you pass the whole element. That is why document.getElementById can't find anything because it expects a string as a parameter. I refactored you code a bit and also when removing the fields the link - Remover campo stayed and was not deleted. I fixed that as well by passing a third argument to the remove function.
var i = 1;
var divContent = document.getElementById('formulario');
//Click to add a field
function cria() {
//This add a HTML Inputs and divs who the ID is variable how the 'i' is increasedf
document.getElementById('formulario').innerHTML += '<div class="mb-1 col-3" id="div'+i+'"><label for="nomeTx0" class="form-label">Nome</label><input type="text" class="form-control" id="nomeTx'+i+'" name="nomeTx'+i+'" required></div><div class="mb-1 col-3" id="div2'+i+'"><label for="taxa'+i+'" class="form-label">Valor</label><input type="float" class="form-control" id="taxa'+i+'" name="taxa'+i+'" required></div>- Remover campo';
i++;
}
function remove(div1, div2, link){
var div = document.getElementById(div1);
var div2 = document.getElementById(div2);
var link = document.getElementById(link);
divContent.removeChild(div);
divContent.removeChild(div2);
divContent.removeChild(link)
i--;
}
The easiest way to do your code working it change your function "cria". (it's not the best option)
You miss ' '.
You have this.
onclick="remove(div'+i+',div2'+i+')"
You need this.
onclick="remove(\'div'+i+'\',\'div2'+i+'\')"
Javascript just doesn't understand that these parameters are strings.
And the full function "cria" after changes.
function cria() {
//This add a HTML Inputs and divs who the ID is variable how the 'i' is increasedf
document.getElementById('formulario').innerHTML += '<div class="mb-1 col-3" id="div'+i+'"><label for="nomeTx0" class="form-label">Nome</label><input type="text" class="form-control" id="nomeTx'+i+'" name="nomeTx'+i+'" required></div><div class="mb-1 col-3" id="div2'+i+'"><label for="taxa'+i+'" class="form-label">Valor</label><input type="float" class="form-control" id="taxa'+i+'" name="taxa'+i+'" required></div>- Remover campo';
i++;
}

how to generate the id of a div dynamically using javascript

I have a (+) sign and a (-) sign. If the user clicks on the + sign than whatever their in the row will automatically get generated the same with new id.
Now when user click on + sign than div id and text box under it will get changed.
Code below for div as follows:
<div class="row" id="Div0">
<div class="col-md-3">
<div class="form-group">
<label for="name">Last Name</label>
<input type="text" class="form-control" id="txtLastName0" placeholder="Enter name" required="required" />
</div>
</div>
<div class="col-md-9"></div>
</div>
Now when user clicks on + sign the new row with text box with new id txtLastName1 will get generated.
Now on click of + sign how do i get new id of textbox and a div with new row.
Div1 and textbox1 will get generated
Basically what you should do is, keep the markup you want to generate as a template in your DOM and when user clicks the "Add" button, clone this markup and append to the DOM (to a container div). then update the Id's of the input and divs as needed.
A simply sample would be like
<div class="row" id="template" style="display: none;">
<div class="col-md-3">
<div class="form-group">
<label for="name">Last Name</label>
<input type="text" class="form-control lname" id="txtLastName"
placeholder="Enter name" required="required" />
</div>
</div>
<div class="col-md-9"></div>
</div>
<button id="btnAdd">+</button>
<div id="container"></div>
Now wire up a click event handler to the Add/+ button. You may use the jQuery clone() method.
$(function () {
$("#btnAdd").click(function(e) {
e.preventDefault();
var childCount = $("#container").children().length;
var c = $("#template").clone().show();
c.attr("id", "Div" + childCount );
c.find(".lname").attr('id', 'txtLastName' + childCount);
$("#container").append(c);
});
});
For deleting, you can add a event handler on the delete button and remove the specific div from dom. jQuery remove() method will do it. Use closest() and find as needed to get the correct div to remove.
Here is a working simple jsbin sample for your reference

How to handle events on markup inserted through jQuery

I have the following markup:
<div id="section">
<input type="text" id="myInput">
</div>
On click of a button, I'm cloning and inserting a copy of this markup with unique IDs using this script:
var newSection = $("#section").clone();
$(newSection).attr('id', "section" + ($("div[id^=section").length + 1));
$(newSection).find("input").attr('id', "myInput" + ($("input[id^=myInput").length + 1));
$("div[id^=section").last().after(newSection);
My resulting markup:
<div id="section">
<input type="text" id="myInput">
</div>
<div id="section2">
<input type="text" id="myInput2">
</div>
My question: is it possible to manipulate this new markup with jQuery? I assume since it has loaded dynamically after a click it's not part of the initial DOM and jQuery doesn't recognize it? I'm having trouble getting a click event to register on #myInput2. Thanks for any insight.
Add classes to your markup:
<div id="section" class="section">
<input type="text" id="myInput" class="section-input">
</div>
Simplify your code
var $newSection = $('#section').clone();
var $sections = $('.section');
var index = $sections.length +1;
$newSection.attr('id', 'section' + index);
$newSection.find('input').attr('id', 'myInput' + index);
$sections.last().after($newSection);
Make sure click handlers are added to existing and new elements
$(document).on('click', '.section-input', function(){
... your code
})
if you wrap them in a container, you can delegate that container keep track of the buttons. For example, if you have:
<div id="container">
<div id="section">
<input type="text" id="myInput">
</div>
<div id="section2">
<input type="text" id="myInput2">
</div>
</div>
you can delegate the task to the container like this:
$("#container").on("click","input",function(){
var newSection = $("#section").clone();
$(newSection).attr('id', "section" + ($("div[id^=section").length + 1));
$(newSection).find("input").attr('id', "myInput" +
($("input[id^=myInput").length + 1));
$("div[id^=section").last().after(newSection);
}
This way you can manipulate them if not defined while binding
EDIT: Updated from .delegate() to .on()

error on removing divs dynamically

I'm trying to add 3 fields dynamically (2 text fields and 1 remove button) per row. The add button is working fine. The problem is the remove function. When I add 2 fields or more, and I try to remove the first, both added fields/rows are deleted
This is my html code:
<div class="col-lg-12">
<div class="field_wrapper form-group col-sm-12">
<div class="form-group col-sm-4">
<input type="text" name="id[]" value="" class="form-control"/>
</div>
<div class="form-group col-sm-4">
<input type="text" name="name[]" value="" class="form-control"/>
</div>
<div class="form-group col-sm-4">
Adicionar Valor
</div>
</div>
</div>
This is the javascript:
<script type="text/javascript">
$(document).ready(function(){
var maxField = 10; //Input fields increment limitation
var addButton = $('.add_button'); //Add button selector
var wrapper = $('.field_wrapper:last'); //Input field wrapper
var wrapper_delete = $('.field_wrapper');
//var fieldHTML = '<div><input type="text" name="field_name[]" value=""/>Remover</div>'; //New input field html
var fieldHTML = '<div class="field_wrapper form-group col-sm-12"><div class="form-group col-sm-4"><input type="text" name="id[]" value="" class="form-control"/></div><div class="form-group col-sm-4"><input type="text" name="name[]" value="" class="form-control"/></div><div class="form-group col-sm-4"><i class="fa fa-trash-o"></i></div></div>'; //New input field html
var x = 1; //Initial field counter is 1
$(addButton).click(function(){ //Once add button is clicked
wrapper = $('.field_wrapper:last'); //Input field wrapper
if(x < maxField){ //Check maximum number of input fields
x++; //Increment field counter
var count = $('.field_wrapper').length;
fieldHTML = '<div class="field_wrapper form-group col-sm-12"><div class="form-group col-sm-4"><input type="text" name="id_'+ count +'" value="" class="form-control"/></div><div class="form-group col-sm-4"><input type="text" name="name_' + count +'" value="" class="form-control"/></div><div class="form-group col-sm-4"><i class="fa fa-trash-o"></i></div></div>'; //New input field html
$(wrapper).append(fieldHTML); // Add field html
}
});
$(wrapper_delete).on('click', '.remove_button', function(e){ //Once remove button is clicked
wrapper_delete = $('.field_wrapper');
e.preventDefault();
$(this).closest('.field_wrapper').remove();
x--; //Decrement field counter
});
});
</script>
How can I fix this?
You're appending the new field_wrapper element to field_wrapper:last. You should place it after, so instead of .append() you should use .after().
$(wrapper).after(fieldHTML); // Add field html
And delegate click event on document (or closest static ancestor), because .field_wrapper element is also dynamicaly added and you can't attach event to it.
$(document).on('click', '.remove_button', function(e){
JSFiddle
Looking at what you're trying to do. I'd recommend to use .clone([with events]). You don't actually need to change input names (unless the reason is other than avoiding name duplicates), as they are set to arrays.
This way, all your code could be as simple as below:
$('.add_button').click(function(){
$('.field_wrapper').length >= maxField ||
wrapper.clone(true).find('a.btn').toggle().end().insertAfter('.field_wrapper:last');
});
$('.remove_button').hide().click(function(){
$(this).closest('.field_wrapper').remove();
});
var maxField = 10, wrapper = $('.field_wrapper').clone(true);
JSFiddle

How to remove input group in bootstrap?

This is what I have right now. I'm trying to add fields to the form dynamically using jQuery add() and append() method. But I want to remove the particular added field when the remove button is clicked.
<div class="col-md-12">
<h3>Added Description Fields</h3>
<div class="col-md-12" id="descFields">
</div>
</div>
JS
$(document).ready(function() {
console.log(descFields);
$('#addDesc').click(function(e) {
var descFields = $('#descFields');
var descLabel = $('#descLabel').val();
var large = '<div class="form-group" id="descField"><div class="input-group"><input type="text" class="form-control" placeholder="Enter Value For ' + descLabel + '" /><span class="input-group-btn"><button class="btn btn-danger" id="removeDesc" type="button">Remove</button></span></div>';
descFields.add(large).appendTo(descFields);
e.preventDefault();
});
$('#removeDesc').click(function(e) {
$(this).remove();
});
});
When the user click on the #removeDesc button , the the field that is added should be removed. I cannot figure out how to achieve this.
There are many ways of doing this, but the simpler for your problem is this one:
$(document).ready(function() {
console.log(descFields);
$('#addDesc').click(function(e) {
var descFields = $('#descFields');
var descLabel = $('#descLabel').val();
var large = '<div class="form-group" id="descField"><div class="input-group"><input type="text" class="form-control" placeholder="Enter Value For ' + descLabel + '" /><span class="input-group-btn"><button class="btn btn-danger" id="removeDesc" type="button">Remove</button></span></div>';
descFields.add(large).appendTo(descFields);
e.preventDefault();
});
$('#descFields').on('click', '#removeDesc', function(e) {
$(this).parents('.form-group').remove();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="descLabel"/>
<button id="addDesc">Add Desc</button>
<div class="col-md-12">
<h3>Added Description Fields</h3>
<div class="col-md-12" id="descFields">
</div>
</div>
Your problem is in the callback to delete the rows. When the document has finished loading you are trying to attach a click event to an object #removeDesc that is still not present in the DOM because it's created on the fly when the user clicks the #addDesc.
That's why you should use:
$('#descFields').on('click', '#removeDesc', function(e) {
$(this).parents('.form-group').remove();
});
As #vijayP suggested before you can use the on() to attach an event handler to the container where you'll be adding the object that is still not present in the DOM. Then you pass in the query selector as the second parameter to filter in execution time which of its children will trigger the event and execute the callback.
My additional trick is that I'm using .parents('.form-group') to select the div containing the group and remove all of the fields that were added instead of removing only the button.
Happy coding!
Add click event for remove button like follows:
$(document).on("click","#removeDesc",function(e) {
$(this).remove();
});

Categories