Adding new input using Jquery breaks tooltips - javascript

I'm writing a form and I have to let the user add as many rows as required.
As you can see, my inputs are treated as arrays to later save the data to the DB. (That will be another new thing to me)
$(document).ready(function() {
var maxField = 10; //Input fields increment limitation
var addButton = $('.add_button'); //Add button selector
var wrapper = $('.field_wrapper'); //Input field wrapper
var fieldHTML = '<tr> <td><input type="text" id="NombreProyecto" name="NombreProyecto[]"></td> <td><input type="text" id="Descripcion" name="Descripcion[]"></td> <td><input type="text" id="AplicacionesProyecto" name="AplicacionesProyecto[]"></td> <td style="width: auto"> <div class="range-field "> <input type="range" name="NivelTRL[]" min="1" value="1" max="9" /> </div> </td> </tr>'; //New input field html
var x = 1; //Initial field counter is 1
//Once add button is clicked
$(addButton).click(function() {
//Check maximum number of input fields
if (x < maxField) {
x++; //Increment field counter
$(wrapper).append(fieldHTML); //Add field html
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<div class="step-content">
<div class="container">
<div id="table" class="table-editable ">
<table class="table field_wrapper">
<tr>
<th>Nombre</th>
<th>DescripciĆ³n</th>
<th>Aplicaciones</th>
<th>Nivel TRL</th>
<th><i class="material-icons">add</i>
</th>
</tr>
<tr class="">
<td><input type="text" id="NombreProyecto" name="NombreProyecto[]"></td>
<td><input type="text" id="Descripcion" name="Descripcion[]"></td>
<td><input type="text" id="AplicacionesProyecto" name="AplicacionesProyecto[]"></td>
<td>
<div class="range-field">
<input type="range" name="NivelTRL[]" min="1" value="1" max="9" />
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
</body>
</html>
Everything looks perfect but when the user adds a new row and interacts with the range input, this won't feedback the user about the value he/she is picking.
Just the original one will have the tooltip.
After some testing, it even affects the 'tooltipped' class used to, well, show tooltips over any element.
This is the codepen, It's all ready to show you the problem
How to reproduce it:
In the codepen provided, you will see the blue cross, when you click on it a new row will be added.
Play around with the first range input, it will show you the value on the tooltip.
In the later added range input, it wont.
Thank you for reading, have a nice day.

You should reinit your range elements.
Simply add this code
M.Range.init($('input[type=range]'));
after this
$(wrapper).append(fieldHTML); //Add field html

First, it's not a tooltip on that range input... It's the Materialize nouiSlider effect. So you have to initialyse this on the new element.
M.Range.init(element);
By the way, I did not found this specific is the documentation about range... But I got inspired by this other initialisation example.
CodePen updated

Related

Fill input with max value on click

I'm currently trying to find a way to fill the max value of an input according to the
max="#value"
Currently I'm using asp.net mvc, I'm getting data from a datatable and I render this information inside a html table where in my tr> /tr> I have a td> /td> that looks like this
<td align="center"><input type="number" name="txtID" class="txtID" oninput="setValueAttr(this)" min="0" max="#monto.Trim()" value="" step="any" style="width: 100px" /></td>1
Can anyone tell me how to make a javascript function that automatically fills the max="" value inside a Html TableRow?
The problem is that each row has its unique max #value
Assume the following HTML:
<td align="center">
<input type="number" name="txtID" class="txtID" oninput="setValueAttr(this)" min="0" max="#monto.Trim()" value="" step="any" style="width: 100px" />
<button class="set-max">Max value</button>
</td>
You can add an event listener on the button via JavaScript e.g. put this code in the bottom of your table or in the bottom of the <body> tag.
<script>
var buttons = document.querySelectorAll('.set-max');
buttons.forEach(function (button) {
button.addEventListener('click', function (event) {
var input = event.currentTarget.parentElement.querySelector('input[type="number"]');
input.value = input.max;
});
};
<script>
If the button ends up somewhere else you'd need to adjust the event listener to find the actual target element by navigating through the DOM hierarchy

Initially Hiding and then Dynamically Adding and Removing Rows

I'm working on a request form. It needs to list the study team members on a research study besides the PI and submitter of the form. However, some studies will have no additional team members so I would like the row to remain hidden until someone clicks the Add Team Member button.
What's working:
1. I've got the element hidden on initially loading the page.
2. Clicking add rows adds the correct rows.
3. Clicking remove will remove a row.
Current problems:
1. If someone adds a team member then removes all the team members, clicking add team member will not add a row.
2. When the element is hidden on initial page load, the first time the Add Team Member button is clicked it adds two rows.
Here's my current code with only the relevant section of the form.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="assets/css/test.css" />
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript">
function addTableRow(jQtable){
jQtable.each(function(){
var tds = '<tr>';
jQuery.each($('tr:last td', this), function() {tds += '<td>'+$(this).html()+'</td>';});
tds += '</tr>';
if($('tbody', this).length > 0){$('tbody', this).append(tds);
}else {$(this).append(tds);}
});
}
</script>
<script>
function myDeleteFunction() {
document.getElementById("stmember").deleteRow(0);
}
</script>
<script type="text/javascript">
$(function() {
$('#add').click(function() {
$('#stmember').show();
});
});
</script>
<style>
#stmember {
display: none
}
</style>
</head>
<body>
<h3><strong>Other Study Team Members:</strong></h3>
<FORM>
<table id="stmember">
<tr>
<td>Name:
<label for="namest1"></label>
<input type="text" name="namest1" id="namest1" placeholder="First Name, Last Name" />
</td>
<td>JHED ID:
<label for="jhedst1"></label>
<input type="text" name="jhedst1" id="jhedst1" />
</td>
<td>Email:
<label for="emailst1"></label>
<input type="email" name="emailst1" id="emailst1" placeholder="you#example.com" />
</td>
</tr>
</table>
<CENTER>
<button type="button" id="add" onclick="addTableRow($('#stmember'));">Add Study Team Member</button>
<button type="button" onclick="myDeleteFunction()">Remove Study Team Member</button>
</CENTER>
</FORM>
</body>
</HTML>
Here are a couple solutions for you:
Solution 1
Store the HTML of the row in your addTableRow function within a variable. That way you can use tokens for the input IDs to ensure they are unique. Also, you won't have to provide the first row in your HTML, as it will be created through your JS function. Something like:
var template = "<tr><td>Name:<label for="namest1"></label><input type="text" name="namest!!TOKEN!!" id="namest!!TOKEN!!" placeholder="First Name, Last Name" /></td><td>JHED ID:<label for="jhedst1"></label><input type="text" name="jhedst!!TOKEN!!" id="jhedst!!TOKEN!!" /></td><td>Email:<label for="emailst1"></label><input type="email" name="emailst!!TOKEN!!" id="emailst!!TOKEN!!" placeholder="you#example.com" /></td></tr>";
Solution 2
Use a templating engine like jsRender or Mustache.
Conclusion
The cleanest method would be to use a templating engine, if you're game for that. But using a string to store the template within your function will work.
If you're using jQuery, I'd fully commit to using that instead of mixing vanilla JS, as with jQuery you can use clone and remove effectively for what you're trying to achieve. Also, if you plan on submitting this as a form, please be sure to add [] to your input names so you can parse each row properly as the names are the same on the input fields. Please see the below snippet:
function addTableRow() {
var $tableRow = $('tr.model-row:first-child');
var $clonedRow = $tableRow.clone().show();
$('#stmember').append($clonedRow);
}
function myDeleteFunction() {
var $memberTRs = $('tr', '#stmember');
// If rowcount === 1, hide first row, don't remove it!!
var rowCount = $memberTRs.length;
if (rowCount === 1) {
$('tr.model-row:first-child').hide();
return;
}
$memberTRs.last().remove();
}
jQuery(function() {
$('#delete').click(function() {
myDeleteFunction();
});
$('#add').click(function() {
addTableRow();
});
});
.model-row {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<h3><strong>Other Study Team Members:</strong></h3>
<FORM>
<table id="stmember">
<tbody>
<tr class="model-row">
<td>Name:
<label for="namest1"></label>
<input type="text" name="namest1[]" id="namest1" placeholder="First Name, Last Name" />
</td>
<td>JHED ID:
<label for="jhedst1"></label>
<input type="text" name="jhedst1[]" id="jhedst1" />
</td>
<td>Email:
<label for="emailst1"></label>
<input type="email" name="emailst1[]" id="emailst1" placeholder="you#example.com" />
</td>
</tr>
</tbody>
</table>
<CENTER>
<button type="button" id="add">Add Study Team Member</button>
<button type="button" id="delete">Remove Study Team Member</button>
</CENTER>
</FORM>
</body>
When you create a row, you use the last existing row to create it. But if you remove all the row you lose your example of row.
You can easily fix your problem by checking when you remove a Row, if it's the last one, add a new row before remove the last one.

jQuery remove too many fields

I am creating a form where the user can add fields one after the other. For each field I am setting a "remove" button. Each field is in a table, so I give a random id to the table, and pass this id to a removing function doing: $(random-id).remove().
The strange thing is that jQuery is removing all of the tables created by the user, as if the id is not taken into account
Why that can be?
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="http://code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
<script>
function delete_field(id)
{
$("#"+id+"").remove();
}
function add_form_field()
{
id = Math.random();
html = '<table id='+id+'>\
<tr><td>Label </td></tr>\
</table>\
\
<button onclick=delete_field('+id+')>remove</button>';
$("form").append(html);
}
</script>
</head>
<body>
<form>
</form>
<button onclick=add_form_field()> Add a field </button>
</body>
</html>
Don't use Math.random, rather increment a number and create ID like: #tab_NN.
Add an ID to your Form Element id=myForm
Delegate click events to dynamically generated delete buttons using .on()
While removing the table that matched the button data-* attribute, delete the button too using .add( this ) (where this stays for the clicked button)
var id = 0;
function delete_field(event){
event.preventDefault();
$("#tab_"+ $(this).data("remove")).add(this).remove();
}
function add_form_field(){
id += 1;
var html = '<table id="tab_'+ id +'">'+
'<tr><td>Label</td></tr>'+
'</table>'+
'<button data-remove="'+id+'" class="remove">remove</button>';
$("#myForm").append(html);
}
$('#addField').on('click', add_form_field);
$('#myForm').on('click', '.remove', delete_field);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="myForm"></form>
<button id="addField"> Add a field </button>
The code above allows you to have changes in the future markup cause it targets a specific ID, but in case your DELETE buttons will always be exactly after table than you can do it without assigning ID's, by simply using .prev("table"):
http://jsbin.com/wuqati/1/edit
function delete_field(event){
event.preventDefault();
$(this).prev("table").add(this).remove();
}
function add_form_field(){
var html = '<table>'+
'<tr><td>Label</td></tr>'+
'</table>'+
'<button class="remove">remove</button>';
$("#myForm").append(html);
}
$('#addField').on('click', add_form_field);
$('#myForm').on('click', '.remove', delete_field);
Math.random() produces a floating point number less than 1 which is invalid for an id. You can use a global variable to keep count of the rows created. Keep in mind that a CSS ID can not start with a digit. So append the number to a string before using it as an ID.
<script>
function delete_field(id)
{
$("#"+id+"").remove();
}
tableID = 1;
function add_form_field()
{
id = 'table-'+tableID;
html = '<table id='+id+'>\
<tr><td>Label </td></tr>\
</table>\
\
<button onclick=delete_field('+id+')>remove</button>';
$("form").append(html);
tableID++;
}
</script>
Why not simplify this by doing something like below.
$(".remover").click(function() {
$(this).parent().remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td>
<input type="text" placeholder="input One"/> <input type="button" class="remover" value="remove" />
</td> </tr>
<tr>
<td>
<input type="text" placeholder="input Two"/> <input type="button" class="remover" value="remove" />
</td> </tr>
<tr>
<td>
<input type="text" placeholder="input Three"/> <input type="button" class="remover" value="remove" />
</td> </tr>
</table>

Losing Styling When Dynamically Adding New Items Onclick

I have code that displays a table row with 2 inputs styled using jquerymobile.
I'm using jquery to dynamically add rows when a "plus" button is clicked.
The problem:
When I append a row the static items retain their styling, but the appended row isn't styled.
What am I doing wrong?
Here's the code:
http://jsfiddle.net/Trident/o9r4csc9/
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.1/jquery.mobile-1.2.1.min.css" />
<script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
<script src="http://code.jquery.com/mobile/1.2.1/jquery.mobile-1.2.1.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header">
<h1>Test</h1>
</div>
<!-- /header -->
<div data-role="content">
<div class="input_fields_wrap">
<table width="100%" border="0" cellspacing="5" cellpadding="5">
<tr>
<td width="180px">Entry price</td>
<td>Percent of position</td>
</tr>
<tr>
<td width="180px"><input type="number" name="entryprice" size="5" min="0" placeholder="100"></td>
<td><input type="range" name="slider-fill" id="slider-fill" value="10" min="0" max="100" data-highlight="true" /></td>
</tr>
<tr>
<td width="180px"><input type="number" name="entryprice" size="5" min="0" placeholder="100"></td>
<td><input type="range" name="slider-fill" id="slider-fill" value="10" min="0" max="100" data-highlight="true" /></td>
</tr>
</table>
</div>
<div align="left">
<button class="add_field_button" data-icon="plus" data-inline="true" >Add</button>
</div>
<!-- When "Add" is clicked, execute python script -->
</div>
<!-- /content -->
</div>
<!-- /page -->
<script language="javascript">
<!-- adds or deletes input fields dynamically -->
$(document).ready(function() {
var max_fields = 1000; //maximum input boxes allowed
var wrapper = $(".input_fields_wrap"); //Fields wrapper
var add_button = $(".add_field_button"); //Add button ID
var addline = '<tr>\
<td width="180px"><input type="number" name="entryprice" size="5" min="0" placeholder="100"></td>\
<td><input type="range" name="slider-fill" id="slider-fill" value="10" min="0" max="100" data-highlight="true" /></td>\
</tr>';
var x = 1; //initlal text box count
$(add_button).click(function(e){ //on add input button click
e.preventDefault();
if(x < max_fields){ //max input box allowed
x++; //text box increment
$(wrapper).append(addline); //add input box
}
});
$(wrapper).on("click",".remove_field", function(e){ //user click on remove text
e.preventDefault(); $(this).parent('div').remove(); x--;
})
});
</script>
</body>
</html>
In JQuery mobile you can manually update dynamic content by the following code:
$(wrapper).trigger('create');
Just one line and all done.
Note: You have to add jquery script for this. I have added it + the css. Please update the UI issue by your self. The point is that the style is working.
http://jsfiddle.net/o9r4csc9/9/
Happy coding :)
In the fiddle you are appending the new table rows into the containing div rather than the table. Change your wrapper variable to reference the table instead.
var wrapper = $(".input_fields_wrap table"); //Fields wrapper
Your rows are recieving jquery-ui styling dynamically, which you haven't included in your 'addrow' html.
A better way would be to clone another row's html, in your case the best would be the last row.
var addline = wrapper.find('tr').last();
And then change the appending line:
$(wrapper).append(addline.clone()); //add input box
I changed a couple of lines in your code:
The first one to append the table row to the table, not the wrapping div
var wrapper = $(".input_fields_wrap table"); //Fields wrapper
And the second one to get the right HTML, now and in the future
var addline = wrapper.find('tr:last')[0].outerHTML;
I have modify your html as required at
http://jsfiddle.net/o9r4csc9/6/
Changes :
1. ID at table <br>
2. Append Row to Table not at div <br>
3. Few css added <br>
i have modified your script section and test on http://jsfiddle.net/o9r4csc9/12/ please change your code as below
$(document).ready(function() {
var max_fields = 1000; //maximum input boxes allowed
var wrapper = $(".input_fields_wrap"); //Fields wrapper
var add_button = $(".add_field_button"); //Add button ID
var addline = '<tr>\
<td width="180px"><input class="ui-input-text ui-body-c ui-corner-all ui-shadow-inset" name="entryprice" size="5" min="0" placeholder="100" type="number"></td>\
<td><input class="ui-input-text ui-body-c ui-corner-all ui-shadow-inset ui-slider-input" name="slider-fill" id="slider-fill" value="10" min="0" max="100" data-highlight="true" data-type="range" type="number"><div class="ui-slider ui-btn-down-c ui-btn-corner-all" role="application"><div style="width: 10%;" class="ui-slider-bg ui-btn-active ui-btn-corner-all"></div><a style="left: 10%;" aria-labelledby="slider-fill-label" title="10" aria-valuetext="10" aria-valuenow="10" aria-valuemax="100" aria-valuemin="0" role="slider" data-theme="c" data-wrapperels="span" data-iconshadow="true" data-shadow="true" data-corners="true" class="ui-slider-handle ui-btn ui-btn-up-c ui-shadow ui-btn-corner-all" href="#"><span class="ui-btn-inner ui-btn-corner-all"><span class="ui-btn-text"></span></span></a></div></td>\
</tr>';
var x = 1; //initlal text box count
$(add_button).click(function(e){ //on add input button click
e.preventDefault();
if(x < max_fields){ //max input box allowed
x++; //text box increment
$(wrapper).find("table").append(addline); //add input box
}
});
$(wrapper).on("click",".remove_field", function(e){ //user click on remove text
e.preventDefault(); $(this).parent('div').remove(); x--;
})
});

jQuery - Cloned datepicker calendar not appearing next to datepicker field

I have created a cloned datepicker element (with the help of #Aamir Afridi) and I am now trying to make the calendar appear with the cloned datepicker field.
I have created a jsfiddle here to illustrate the problem: http://jsfiddle.net/dalepotter/xTvfx/3/
The calendar displays with the field for elements which load with the page, but it does not position correctly for cloned fields - does anyone have any pointers on how to fix this?
Many thanks for any help that you can give...
Here's the code:
HTML
<h2>Action points</h2>
<table width="100%">
<tr><td width="50%" valign="top">
<h3>For the Associate</h3>
<div class="clone_Associate">
<table width="300" style="background-color:#EBEBEB; margin: 0 0 30px 0; padding: 5px;">
<tr><td class="associate_column_left">
Date set:</td><td class="associate_column_middle">
<input type="text" name="DATE_SET[]" class="datepick" value="04/12/2013">
</td></tr>
<tr><td class="associate_column_left">
Date due for completion:</td><td class="associate_column_middle">
<input type="text" name="DATE_DUE[]" class="datepick" value="">
</td></tr>
</table>
<!-- End clone_Associate -->
</div>
<div class="placer_Associate"></div>
<p>Add another action step for the Associate </p>
</td><td width="50%" valign="top">
<h3>For us</h3>
<div class="clone_upReach">
<table width="300" style="background-color:#EBEBEB; margin: 0 0 30px 0; padding: 5px;">
<tr><td class="associate_column_left">
Date set:</td><td class="associate_column_middle">
<input type="text" name="DATE_SET[]" class="datepick" value="04/12/2013">
</td></tr>
<tr><td class="associate_column_left">
Date due for completion:</td><td class="associate_column_middle">
<input type="text" name="DATE_DUE[]" class="datepick" value="">
</td></tr>
</table>
<!-- End clone_upReach -->
</div>
<div class="placer_upReach"></div>
<p>Add another action step for upReach </p>
</td></tr>
</table>
<link rel="stylesheet" type="text/css" href="http://brenda.upreach.org.uk/plugins/jquery.datepick.package-4.1.0/redmond.datepick.css">
<script type="text/javascript" src="http://brenda.upreach.org.uk/plugins/jquery.datepick.package-4.1.0/jquery.datepick.js"> </script>
jQuery
$('.datepick').datepick({
dateFormat: 'dd/mm/yyyy', showTrigger: '#calImg'});
// Start code for duplicating a div box
$(document).ready(function(){
// Set datepicker options
var options = {dateFormat: 'dd/mm/yy'}
$(".clone_trigger_Associate").click(function () {
// Prevent default link action
event.preventDefault();
$('input.cl:last').val('');
var $newInput = $('.clone_Associate:last').clone(true).removeAttr('id');
$(this).before($newInput);
// Calculate correct number for the checkbox array
var total = $('[name^="UPDATE_METHOD"]').length;
var index = Math.round(total / 2) - 1;
$('.clone_Associate').last().find("input[type='checkbox']").prop("name","UPDATE_METHOD["+index+"][]");
// Reinitialise the datepicker
$newInput.datepicker('destroy').datepicker(options);
});
});
$(document).ready(function(){
// Set datepicker options
var options = {dateFormat: 'dd/mm/yy', showTrigger: '#calImg'}
$(".clone_trigger_upReach").click(function () {
// Prevent default link action
event.preventDefault();
$('input.cl:last').val('');
var $newInput = $('.clone_upReach:last').clone(true).removeAttr('id');
$(this).before($newInput);
// Reinitialise the datepicker
$newInput.datepicker('destroy').datepicker(options);
});
});
// End code for duplicating a div box
You had two problems:
typo - .datepicker() instead of .datepick()
$newInput.datepicker('destroy').datepicker(options);
should be
$newInput.find('.datepick').datepick('destroy').datepick(options);
because you should attach datepicker to inputs, not to cloned div.
http://jsfiddle.net/xTvfx/4/

Categories