Add dynamic href to table with jquery - javascript

I have a table with a template to insert rows, I would like to make those rows clickable so that I can edit them. How do I append an href value to the template?
My Template
<tr class="template" style="display:none;">
<td><span class="item_num"> Num </span></td>
<td><span class="item_desc"> Description </span></td>
<td><span class="item_price"> Price </span></td>
<td><span class="item_ref">ref</span></td>
</tr>
My Javascript
var newRow = $('#quote .template').clone().removeClass('template');
var quoteItem = {
number: 1,
description: myDescriptionVariable,
price: myPriceVariable,
};
template(newRow, quoteItem)
.insertAfter('#quote tr.template')
.fadeIn()
function template(row, quoteItem) {
row.find('.item_num').text(quoteItem.number);
row.find('.item_desc').text(quoteItem.description);
row.find('.item_price').text(quoteItem.price);
row.find('.item_ref').attr('href','hello');
return row;
}

You can use .data()
row.find('.item_ref').data('ref','hello');
with
<span class="item_ref" data-ref="" > Edit</span>
Then you can use it like --
console.log($('.item-ref').data('ref'));
If you just wish to store data somehow then this might be useful. Let me know if there's something more you want to do. Or what kind of data href holds and how you want to use it further.
UPDATE
From what I understand up till now is, you want to add rows dynamically that needs to editable after insertion. Each row contain some fields with certain values. And you want to save ref in item_ref class.
So here's how you can do it -
var num = 1;
var myDescriptionVariable = 111;
var myPriceVariable = 999;
// You may have some other element triggers cloning
$("button").click(function(){
var newRow = $('#quote .template').clone().removeClass('template');
var quoteItem = {
number: num,
description: 'Description ' + myDescriptionVariable, // added to distinguish items
price: myPriceVariable + ' USD', // added to distinguish items
linkToPopup: myDescriptionVariable + '_link_goes_here' // added to distinguish items
};
template(newRow, quoteItem)
.insertAfter('#quote tr.template')
.show();
});
function template(row, quoteItem) {
row.find('.item_num').text(quoteItem.number);
row.find('.item_desc').text(quoteItem.description);
row.find('.item_price').text(quoteItem.price);
// here 'href' will hold desired link_to_popup
row.find('.item_ref').data('href',quoteItem.linkToPopup);
myDescriptionVariable+= 1; // added to distinguish items
myPriceVariable+=2; // added to distinguish items
num+=1; // added to distinguish items
return row;
}
$("#quote").on("click", ".item_ref",function(){
// this will give to desired link_to_pop_val
alert($(this).data('href'));
});
I've added a button to give demonstration. This approach definitely avoid unnecessary DOM elements like hidden inputs to be added for each row. With .data() you same multiple kind of information for every field like -
$("span").data('key_1', value_1);
$("span").data('key_2', value_2);
$("span").data('key_2', value_3);
fiddle for demonstration
I think that's what you want to do and should serve the purpose. :)

There are actually a few ways to do this, one of them being:
Add some inputs to your template that are hidden
Bind a click event to the row that will hide the spans and show the input
You would of course need a save button and do something with the values, but I didn't do that part.
A condensed not fully working demo: http://plnkr.co/edit/GGM0d9wfNcoZBd5kKCwA
<tr class="template" style="display:none;">
<td><span class="item_num"> Num </span><input type="text" style="display:none" /></td>
<td><span class="item_desc"> Description </span> <input type="text" style="display:none" /></td>
<td><span class="item_price"> Price </span><input type="text" style='display:none' /></td>
<td><span class="item_ref">ref</span><input type="text" style='display:none' /></td>
</tr>
jquery:
$(document).on('click', '#quote tr', function(e) {
$('span', this).hide();
$('input', this).show();
});
$('#add').on('click', function(e) {
var newRow = $('#quote .template').clone().removeClass('template');
var quoteItem = {
number: 1,
description: 'myDescriptionVariable',
price: 100,
};
template(newRow, quoteItem)
.insertAfter('#quote tr.template')
.fadeIn()
});
function template(row, quoteItem) {
row.find('.item_num').text(quoteItem.number).next().val(quoteItem.number);
row.find('.item_desc').text(quoteItem.description).next().val(quoteItem.description);
row.find('.item_price').text(quoteItem.price).next().val(quoteItem.price);
row.find('.item_ref').attr('href','hello').next().val('hello');
return row;
}

Related

loop using JavaScript based in html id

if i have a table with an infinite which has an input type checkbox. Each check box is marked with an id eg. #det1, #det2 , #det3 how would i write my JS loop to check if that certain checkbox is checked to perform the function on it, without writing out each id ,because this id is also incremented based on the product uploader so for each product uploaded it will just add 1 to the id,at the end i could sit with allot of id's.
javascript that works adding the id manually:
$('#details1, #details2').on('change', function(){
var row = $(this).closest('tr').next('tr');
if ($(this).prop('checked')) {
$(row).show();
}
else {
$(row).hide();
}
});
So that works but because have so many id's based on my tr's i would just like to do a loop and check if that id exist (it could be id = #details999) and if it does do function on.change.
(for each product ill upload the id adds 1 to it eg. product1 = #details1 , product2 = #details2, etc...)
There might be a better way of implementing the idea but as im newbie i am open to any suggestions.
What i tried:
for (var i = 0; i < ?; i++) {
$('#details'+ i).on('change', function(){
var row = $(this).closest('tr').next('tr');
if ($(this).prop('checked')) {
$(row).show();
}
else {
$(row).hide();
}
})
}
i know ? means nothing but i realized i cant set a limit to that also don't want a infinite loop so i'm kind of stuck.
Add a common class to the select elements and use that to target them
<input type="checkbox" id="details1" class="details-checkbox">
<input type="checkbox" id="details2" class="details-checkbox">
<input type="checkbox" id="details3" class="details-checkbox">
and then use
$('.details-checkbox').on('change', function(){
var row = $(this).closest('tr').next('tr');
if ($(this).prop('checked')) {
$(row).show();
}
else {
$(row).hide();
}
});
I would use event delegation:
Event delegation allows us to attach a single event listener, to a
parent element, that will fire for all descendants matching a
selector, whether those descendants exist now or are added in the
future.
$('table').on('change', 'input[type="checkbox"]', function(e) {
var row = $(this).closest('tr').next('tr');
$(row).toggle($(this).prop('checked'));
})
tr.hidden { display: none }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tbody>
<tr><td>1</td><td><input type="checkbox" /></td></tr>
<tr class="hidden"><td colspan="2">Details 1</td></tr>
<tr><td>2</td><td><input type="checkbox" /></td></tr>
<tr class="hidden"><td colspan="2">Details 2</td></tr>
<tr><td>3</td><td><input type="checkbox" /></td></tr>
<tr class="hidden"><td colspan="2">Details 3</td></tr>
<tr><td>4</td><td><input type="checkbox" /></td></tr>
<tr class="hidden"><td colspan="2">Details 4</td></tr>
</tbody>
</table>
$('input:checkbox[id*=details ]').on('change',function(){
var row = $(this).closest('tr').next('tr');
if ($(this).prop('checked')) {
$(row).show();
}
else {
$(row).hide();
}
});

Cloning a table row

I have the following table
<table id="customFields" class="table table-bordered table-hover additionalMargin alignment">
<thead>
<tr>
<th colspan="2"></th>
<th>Some Title</th>
</tr>
</thead>
<tbody>
<tr>
<td><label class="subjectline" for="User1">User NOC M1</label></td>
<td id="slLabel">SLA</td>
<td id="slInput"><input type="text" name="slOptions[User][NOC M1]" class="form-control" id="User1"></td>
<td><a class="addCF" href="javascript:void(0);">+ additional user</a></td>
</tr>
</tbody>
</table>
I then have the following javascript to add additional rows
$(function() {
$(".addCF").click(function(){
$("#customFields").append('<tr><td></td><td>SL_B</td> <td><input type="text" name="slOptions[User][NOC M1]" class="form-control" id="User1"></td> <td> Remove</td></tr>');
});
$("#customFields").on('click','.remCF',function(){
$(this).parent().parent().remove();
});
});
This currently works how I want it to. However, there are a couple of things I am having issues with.
Firstly, when you first view it, you will see the label SL_A. In the cloned version, I manually set it to SL_B. All other clones then have SL_B. What I am trying to do is have SL_ followed by the next letter in the alphabet. So the third row should be SL_C. I am not too sure how I can achieve this.
My second issue relates to the name of the cloned input. At the moment, they all have the same name e.g. slOptions[User][NOC M1]
When a new row is added, the name should change to something unique, maybe using the additional letter of the alphabet above e.g. slOptions[User][NOC M1B]
Would it be possible to achieve these things?
I have set up a Fiddle for demonstration
Thanks
You could store a reference to the possible letters as well as your current letter and then within your function determine the appropriate one to use :
// Store the possible letters
var possibleLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
// Store the current letter
var currentLetter = 'A';
$(function() {
$(".addCF").click(function(){
// Resolve the next letter to add
var nextIndex = possibleLetters.indexOf(currentLetter) + 1;
// Update your reference
currentLetter = possibleLetters[nextIndex];
// Append it
$("#customFields").append('<tr><td></td><td>SL_' + currentLetter + '</td> <td><input type="text" name="slOptions[User][NOC M1' + currentLetter + ']"...');
// More code omitted for brevity
});
// Still more code omitted for brevity
});
You can see an example of this in action here and demonstrated below :
Here is your solution for both the issues:
See: https://jsfiddle.net/pdxgrpqz/
$(function() {
alp = "A";
$(".addCF").click(function(){
alp = (alp.substring(0,alp.length-1)+String.fromCharCode(alp.charCodeAt(alp.length-1)+1));
$("#customFields").append('<tr><td></td><td>SL_'+alp+'</td> <td><input type="text" name="slOptions[User][NOC M1'+alp+']" class="form-control" id="User1"></td> <td> Remove</td></tr>');
});
$("#customFields").on('click','.remCF',function(){
$(this).parent().parent().remove();
});
});

jQuery Math Operation on Multiple Elements

I have a simple invoicing page so I can invoice my client, however when I am going to perform multiplication to the quantity and price, the row total is not adding. Here's my jQuery so far.
$(":input").bind('keypress keydown keyup change', function(){
var price = parseFloat($(this).closest('.tr').find('.price').val(),10),
var qty = parseFloat($(this).closest('tr').find('.quantity').val(),10);
var v = '';
if(!isNaN(price) && !isNaN(qty)) {
v = price * qty;
}
$(this).closest('tr').find('.rowtotal').val(v.toString());
});
And this is my HTML:
<table>
<tr>
<td>1</td>
<td><input name="item_name[]"class="form-control"></td>
<td><input name="item_description[]"class="form-control"></td>
<td><input name="item_price[]"class="form-control price"></td>
<td><input name="item_quantity[]"class="form-control quantity"></td>
<td><span class="rowtotal">0.00</span></td>
</tr>
<tr>
<td>2</td>
<td><input name="item_name[]"class="form-control"></td>
<td><input name="item_description[]"class="form-control"></td>
<td><input name="item_price[]"class="form-control price"></td>
<td><input name="item_quantity[]"class="form-control quantity"></td>
<td><span class="rowtotal">0.00</span></td>
</tr>
</table>
Now on my page, it shows no error while reviewing the console, but it does not perform the operation that I have created following this post "Automatically updating input field with math using jquery?"
Any help is appreciated.
TIA
You've got a typo in this line:
var price = parseFloat($(this).closest('.tr').find('.price').val(),10),
^^ Shouldn't be a class selector
Should be:
var price = parseFloat($(this).closest('tr').find('.price').val(),10),
Next line is fine. Additionally, you can replace all those events with:
$(":input").on("input", function() {
// Triggers on any input event
});
You also have a few other issues:
There is no overload for parseFloat which takes two parameters
You are using .val() to set the text of the span. You need to use .text() instead
You should probably cache the <tr> selector. You don't need to go find it each time.
$(":input").on('input', function(){
var $tr = $(this).closest("tr");
var price = parseFloat($tr.find('.price').val()),
qty = parseFloat($tr.find('.quantity').val());
var v = '';
if(!isNaN(price) && !isNaN(qty)) {
v = price * qty;
}
$tr.find('.rowtotal').text(v.toString());
});
Working Example

Add / Delete Rows from Table

I have created a table in Twitter Bootstrap here
I want to be able to do 2 things with it
Delete rows by pressing delete icon - will delete that row
Add a new name by adding text (name) to input field and then pressing "add new row"
DEMO - http://jsfiddle.net/qxdz4/2/
Looking for a way to do this with JavaScript / jQuery
My Code
<div class="input-prepend input-append"><span class="add-on"><i class="icon-picture"></i></span>
<input class="span2"
id="appendedInputButton" type="text" placeholder="Add New Name Here">
<button class="btn" type="button">Add New Row</button>
</div>
<table id="users" class="table table-bordered table-condensed">
<tr>
<th>name</th>
<th></th>
</tr>
<tr>
<td>Mike
</td>
<td class="taskOptions"> <a href="#deleteProject" rel="tooltip" data-toggle="modal" class="tip-top"
data-original-title="Delete Row"><i class="icon-remove"></i></a>
</td>
</tr>
<tr>
<td>John
</td>
<td class="taskOptions"> <a href="#deleteProject" rel="tooltip" data-toggle="modal" class="tip-top"
data-original-title="Delete Row"><i class="icon-remove"></i></a>
</td>
</tr>
<tr>
<td>Mary
</td>
<td class="taskOptions"> <a href="#deleteProject" rel="tooltip" data-toggle="modal" class="tip-top"
data-original-title="Delete Row"><i class="icon-remove"></i></a>
</td>
</tr>
</table>
Notes
Clicking the delete button should delete the row
Typing into the input field and pressing "add new row" button should add a new
row to the end of the table with the Name filled in
You can easily remove the row by doing this:
$('td.taskOptions a.tip-top').on('click', function(e) {
e.preventDefault();
$(this).tooltip('hide');
$(this).parents('tr').remove();
});
Similarly, adding a new row can be done as follows:
$('button.btn').click(function(e) {
e.preventDefault();
var the_name = $.trim($('#appendedInputButton').val());
var new_row = $('<tr>\
<td>\
'+the_name+'\
</td>\
<td class="taskOptions">\
<i class="icon-remove"></i>\
</td>\
</tr>');
new_row.appendTo($('#users'));
});
Please note that it might be worth adding a more specific class name to the button (when clicked to add the row) to avoid any confusion. An ID would work just as well.
I've updated your jsFiddle with the additional functionality. You can see here.
I don't know how you obtain each row's pk data (data-pk) attribute. That's up to you
On document.Ready
$('[rel=tooltip]').tooltip();
function bindCloseButtons(){
$("#users td.taskOptions a").click(function(e){
$(this).parent().parent().remove();
});
}
function addTableRow(name , pk){
// name column
var row = $("<tr></tr>");
row.append('<td>'+name+'</td>');
// close button
var btnClose = $('<td class="taskOptions"> <i class="icon-remove"></i></td>');
row.append(btnClose);
$("#users").append(row);
bindCloseButtons();
$('[rel=tooltip]').tooltip();
}
$("#addNew").click(function(e){
var name = $("#appendedInputButton").val();
var pk = 1; // TODO: set your pk here
addTableRow(name, pk);
});
bindCloseButtons();
Here's a fiddle:
http://jsfiddle.net/qxdz4/16/
First you create one method AddmultipleInput()
Inside the function,
.AddMultipleInput = function (btnAddId, btnDelId, inputContainerIdPrefix, inputContainerCss, firstChildInputIdPrefix) {
if ($('.' + inputContainerCss).length < 2) {
$('#' + btnDelId).attr('disabled', 'disabled');
}
$('#' + btnAddId).click(function () {
var num = $('.' + inputContainerCss).length; // how many "duplicatable" input fields we currently have
var newNum = new Number(num + 1); // the numeric ID of the new input field being added
// create the new element via clone(), and manipulate it's ID using newNum value
var newElem = $('#' + inputContainerIdPrefix + num).clone().attr('id', inputContainerIdPrefix + newNum);
newElem.children().each(function () {
var idPrefix = $(this).attr('id').substring(0, $(this).attr('id').length - 1);
var namePrefix = $(this).attr('name').substring(0, $(this).attr('name').length - 1);
$(this).attr('id', idPrefix + newNum).attr('name', namePrefix + newNum);
})
// insert the new element after the last "duplicatable" input field
$('#' + inputContainerIdPrefix + num).after(newElem);
// enable the "remove" button
$('#' + btnDelId).attr('disabled', '');
// business rule: you can only add 5 names
if (newNum == 5)
$('#' + btnAddId).attr('disabled', 'disabled');
});
$('#' + btnDelId).click(function () {
var num = $('.' + inputContainerCss).length;
$('#' + inputContainerIdPrefix + num).remove();
$('#' + btnAddId).attr('disabled', '');
if (num == 2)
$('#' + btnDelId).attr('disabled', 'disabled');
});
$('.icon-remove').live('click',function(){
$(this).parent('tr').remove();
});
If you are using jQuery 1.7 or above, then use .on instead of .live.
Add a class to your delete links (like delete-row) and use something like:
$(document).on("click",".delete-row",function(ev) {
ev.preventDefault();
$(this).tooltip('hide');
$(this).parents("tr").first().remove();
});
Note: "$(this).tooltip('destroy');" would be better than "hide", but your fiddle bootstrap version doesn't support destroy yet. Also, you can set $("#users") instead of $(document) as handler for this event if you want, so long as the delete-row buttons are children of the handler the event gets delegated properly.
To add a line the answer of BenM should work perfect.
PS:
.parents(selector) function travels more than one level up the DOM tree, while .parent() travels a single level up the DOM tree.
.parents(selector) function selects all parents that match the selector, so in case there is a change you end up putting a table inside a table (accidentally im sure) you should use .first(), ensuring you dont remove the wrong row.
Edit: As mentioned by BenM, the previous code would not work with new lines, forgot the add part of the question, the new code should work.
I would suggest you yo use following jQuery functions:
on(), click(), remove(), append()
Please do research on this, also look at the jQuery selectors in order to find how to select proper row.

Undefined error getting parents childs input value

I have a table that looks like this:
<table>
<tr>
<td class="packing-vol">0.19</td>
<td class="qty-cell"><input type="text" name="qty[]" class="qty" value="2" /></td>
</tr>
<tr>
<td class="packing_total">0.70</td>
<td class="qty-cell"><input type="text" name="qty[]" class="qty" value="1" /></td>
</tr>
</table>
I'm looping through each occurence of .packing-vol getting it's text, then I want to get the qty from the same row so I go up to it's parent then drill into the .qty class. But when I alert(qty) i get 'undefined' message.
var total = 0;
jQuery('.packing-vol').each(function(i) {
var qty = jQuery(this).parent("td.qty-cell .qty").val();
alert(qty);
var cur = parseFloat(jQuery(this).text());
if(!isNaN(cur)){
total = total + cur;
}
});
I think you should do this:
var qty = jQuery(this).parent().find("td.qty-cell .qty").val();
You need to go 1 level up (using .parent) and then find your field inside with .find
parent is just one level upwards. You can't use it to go inside trees again.
parents is multiple levels upwards. You can't use it to go inside trees again.
You can use parent/parents and then use find to do what you want, or even better:
var total = 0;
jQuery('.packing-vol').each(function(i) {
var qty = jQuery(this).parent().children('.qty-cell').children('.qty').val();
alert(qty);
var cur = parseFloat(jQuery(this).text());
if (!isNaN(cur)){
total = total + cur;
}
});
You could also use find, but it is slower than going directly inside, because it has to search the DOM object.
But you could also do:
var qty = jQuery(this).parent().find("td.qty-cell .qty").val();
Instead of
var qty = jQuery(this).parent("td.qty-cell .qty").val();
Try:
var qty = jQuery(this).parent().find(".qty").val();

Categories