jQuery - reusing code without duplicating it - javascript

I have a page that is essentially a table which has its rows duplicated when the button is pushed. Each additional row has a unique id/name.
I now have this problem. I essentially have a similar table on a different page. Main difference is that it may have additional inputs. At the moment, it looks something like this:
JavaScript
var cloned;
$(function() {
initDatepickersAndSelect();
$('#add_row').on('click', function(evt) {
addRow();
});
$('#delete_row').on('click', function(evt) {
deleteRow();
});
$('#add_row2').on('click', function(evt) {
addRow(x);
});
$('#delete_row2').on('click', function(evt) {
deleteRow(x);
});
});
function initDatepickersAndSelect() {
cloned = $("table tr#actionRow0").eq(0).clone();
$(".dateControl").datepicker({
dateFormat: "dd-mm-yy"
});
$(".responsibility").select2({
tags: true
});
$(".campaignType").select2({
tags: true
});
}
function addRow() {
var $tr = cloned.clone();
var newRowIdx = $("table#actionTable tr").length - 1;
$tr.attr('id', 'actionRow' + newRowIdx);
$tr.find("input, select").each(function(i_idx, i_elem) {
var $input = $(i_elem);
if ($input.is("input")) {
$input.val("");
}
$input.attr({
'id': function(_, id) {
return id + newRowIdx;
},
'name': function(_, name) {
return name.replace('[0]', '[' + newRowIdx + ']');
},
'value': ''
});
});
$tr.appendTo("table#actionTable");
$(".dateControl", $tr).datepicker({
dateFormat: "dd-mm-yy"
});
$(".responsibility", $tr).select2({
tags: true
});
$(".campaignType", $tr).select2({
tags: true
});
}
function deleteRow() {
var curRowIdx = $("table#actionTable tr").length;
if (curRowIdx > 2) {
$("#actionRow" + (curRowIdx - 2)).remove();
curRowIdx--;
}
}
HTML
<div class="col-md-12 noPadding">
<table class="table table-bordered table-hover additionalMargin" id="reportTable">
<thead>
<tr>
<th class="text-center">Something</th>
<th class="text-center">Something else</th>
</tr>
</thead>
<tbody>
<tr id='actionRow0'>
<td>
<select class="campType" name='reportInput[0][campType]' id="reportInput">
<option value=""></option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
</td>
<td>
<input type="text" name='reportInput[0][campDelivery]' id="dateInput" class="form-control" />
</td>
</tr>
</tbody>
</table>
<a id="add_row" class="btn btn-default pull-right">Add Row</a>
<a id='delete_row' class="pull-right btn btn-default">Delete Row</a>
</div>
The last thing I want to do is duplicate all of my JavaScript and rename things to match the above.
What I am wondering, is there anyway I could reuse the JavaScript?
Any advice appreciated.
Thanks
(code also available as JSFiddle)

Based on my understanding of the question, I think you could do something like this. Assuming a function called addRow as seen in your fiddle, the first step is to include that JS on all pages where you want that functionality. You then mentioned that other pages might have additional controls. For this, I'd override the function...
On the page with normal controls
function addRow() {
// Row adding code...
}
On the page with extra controls
var oldAddRow = addRow;
var addRow = function(){
$('.some_other_control').click(ctrlHandler);
$('.some .input').val('');
oldAddRow();
}

I suggest to have an invisible "template row" in your table, which you can copy to add new rows.
Something like this:
<style>
tr.template { display: none; }
</style>
<table id="table1">
<tr class="template"><td><input id="blah">/td><td><input id="foo"></td></tr>
</table>
<button id="add">Add Row</button>
<script>
function add_row($table) {
var count = $table.find('tr').length - 1;
var tr_id = ""+(count+1);
var $template = $table.find('tr.template');
var $tr = $template.clone().removeClass('template').prop('id', tr_id);
$tr.find(':input').each(function() {
var input_id = $(this).prop('id');
input_id = tr_id + '_' + input_id;
$(this).prop('id', input_id);
});
$table.find('tbody').append($tr);
}
$('#add').on('click', function() { add_row($('#table1')); });
</script>
I think it will be easier to make the code generic in this way. If you don't want the inputs in the template to be submitted, you can disable them or remove them somehow.
Demo: http://sam.nipl.net/table-demo.html

You may just clone a row and reset attibutes within with something like:
function addRow(id) {
var c = $("table#"+id+" tr").last();
$("table#"+id+" tbody").append(c.clone().attr({id: "addedrow" + Math.random()*10+1}));
}
function deleteRow(id,index) {
var curRowIdx = $("table#"+id+" tr").length;
if (curRowIdx > 2) {
if(index != void 0) {
$("table#"+id+" tr")[index].remove();
}else{
$("table#"+id+" tr").last().remove();
}
}
}
Call it with
$('#add_row').on('click', function(evt){addRow("reportTable");});
$('#delete_row').on('click', function(evt){deleteRow("reportTable",1);});
Maybe you'll prepare new rows for your table with something like
var emptyRow[id] = $("table#"+id+" tr").last();
and change
$("table#"+id+" tbody").append(c.clone().attr({id: "addedrow" + Math.random()*10+1}));
to
$("table#"+id+" tbody").append(emptyRow[id].clone().attr({id: "addedrow" + Math.random()*10+1}));

Related

Jquery - check if checkbox was clicked

I have a jquery function, that activates only when a table row is clicked and if so, it invokes controller method. However, this row also contains checkbox, and if i click it i don't want this method to be called. I tried checking the clicked element type or other parameters like class, but it seems to only apply to the entire row. Any ideas how to make it work?
JQuery:
function AllowTableRowsToBeClicked() {
$('#pref-table tbody tr').click(function () {
var resourceName = $(this).attr('title');
var categoryName = $('#pref-table').attr('name');
var url = "/Home/GetSpecific";
$.post(url, { categoryName: categoryName, resourceName: myClass }, function (data) {
});
});
}
cshtml:
<table class="table table-striped table-hover margin-top-20 pref-table" id="pref-table" name=#Model.CurrentItemMode>
#for (int i = 0; i < Model.BiData.Count; i++)
{
<tr id=#Model.BiData[i].Name name=#i title="#Model.BiData[i].Name" class="tableRow">
#Html.Hidden("resourceList[" + i + "]", Model.BiData[i].Name)
<th>
#Html.CheckBox("checkBoxList[" + i + "]", Model.BiData[i].Selected, new { #class = "resourceCheckbox" })
</th>
<th>
#Model.BiData[i].Name
</th>
</tr>
}
</table>
If your checkbox has some id like box then you can check if the event originated from that checkbox and stop processing.
$('#pref-table').on('click',function (event) {
if(event.target.id === 'box'){
return;
}
var resourceName = $(this).attr('title');
var categoryName = $('#pref-table').attr('name');
var url = "/Home/GetSpecific";
$.post(url, { categoryName: categoryName, resourceName: myClass }, function (data) {
});
Here's a Pen to demonstrate the idea.
Try event.stopPropagation():
$('#pref-table input[type="checkbox"]').click(function(e) {
e.stopPropagation();
});
Using eventPropagation in the example below:
Html
<table width="100%">
<tr style="background:yellow">
<td>
<input type="checkbox" />
</td>
</tr>
</table>
javascript/jquery
$(document).ready(function() {
$('table tr').click(function(e) {
alert("row clicked");
});
$('input[type=checkbox]').click(function(e) {
e.stopPropagation();
alert("checkbox clicked")
});
});
Jsfiddle demo
I think your problem is you don't want to activate your event code when user clicks on checkbox, irrespective of checkbox state.
$('#pref-table tbody tr').click(function (event) {
if($(event.target).is(":checkbox")) return;
// your event code
});

Remove selected rows on a button click in angular js

I have a table with check box for each row .
I need to remove the rows for the selected check boxes in the table on a button click. (this button is outside ng-repeat).
The index of the selected rows are populated to an array using ng-change function but i'm unable to remove the selected rows on a single button click
Here is the Fiddle
HTML
<div ng-app="approvalApp">
<div ng-controller="SimpleApprovalController" >
<table style="width:90%" border="5" >
<tr>
<th><input type="checkbox" ng-model="CheckAllData" ng- change="selectAll()" /></th>
<th>Date</th>
<th>AssociateID</th>
<th>Check-In</th>
<th>Checkout</th>
</tr>
<tr data-ng-repeat="approval in approvalitems">
<td><input type="checkbox" value="{{approval.ReqId}}" data-ng-model="approval.selected" data-ng-change="SelectDeselect($index)"/></td>
<td>{{approval.Date}}</td>
<td>{{approval.AssociateID}}</td>
<td>{{approval.CheckIn}}</td>
<td>{{approval.Checkout}}</td>
</tr>
</table>
<input type="button" value="Approve" data-ng-model="ApproveIndex" data-ng-click="ApproveRequest()" />
Script
$scope.SelectDeselect=function(index)
{
$scope.getIndexvalues = [];
angular.forEach($scope.approvalitems, function (approval,index) {
if (!!approval.selected) {
$scope.getIndexvalues.push(index);
$scope.CheckAllData = false;
}
});
console.log($scope.getIndexvalues);
};
$scope.ApproveRequest = function () {
$scope.selectedIdsArray = [{}];
angular.forEach($scope.approvalitems, function (item) {
if (!!item.selected) {
$scope.selectedIdsArray.push({ Reqid: item.ReqId, Status: "Approved" });
$scope.CheckAllData = false;
}
});
};
};
So how to use getIndexvalues in approverequest function , or is there any better way to remove it using other angular directive.
I'm a newbie to angular js .
Fiddle: http://jsfiddle.net/jpk547zp/1/
$scope.ApproveRequest = function () {
$scope.selectedIdsArray = [{}];
$scope.approvalitemsNew = [];
angular.forEach($scope.approvalitems, function (item) {
if (!!item.selected) {
$scope.selectedIdsArray.push({ Reqid: item.Date, Status: "Approved" });
$scope.CheckAllData = false;
item.hideThis = true;
console.log($scope.selectedIdsArray);
} else {
$scope.approvalitemsNew.push(item);
}
});
$scope.approvalitems = $scope.approvalitemsNew;
$scope.getIndexvalues = [];
};
Hope this helps.
you can simply do
$scope.ApproveRequest = function () {
$scope.approvalitems = $scope.approvalitems.filter(function(i){
return !i.selected;
});
};

Hide element based on value of other elements

I am trying to hide a table based on the value of two fields, so that if field2 is equal to field1 the table is hidden.
JSfiddle
HTML:
<form>
Expected Number of Items: <input type="text" value="14" name="totalItems" id="totalItems">
<p>
Number of Items Entered: <input type="text" value="14" name="enteredItems" id="enteredItems">
</form>
<p>
<table border="1" style="width:100%" id="hideThis">
<tr>
<td>This should be hidden when "totalItems" equals "enteredItems"</td>
</tr>
</table>
JS:
function toggleClass(eid, myclass){
var theEle = document.getElementById(eid);
var eClass = theEle.className;
if(eClass.indexOf(myclass) >= 0){
theEle.className = eClass.replace(myclass, "");
}else{
theEle.className += "" +myclass;
}
}
See the comments in the code.
// Function to hide/show the table based on the values of inputs
function toggleTable() {
// Hides the table if the values of both input are same
$('#hideThis').toggle($('#totalItems').val() !== $('#enteredItems').val());
}
$(document).ready(function() {
// Bind the keyup event on both the inputs, call the function on event
$('#totalItems, #enteredItems').on('keyup', toggleTable).trigger('keyup');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<form>Expected Number of Items:
<input type="text" value="14" name="totalItems" id="totalItems">
<p>Number of Items Entered:
<input type="text" value="14" name="enteredItems" id="enteredItems">
</form>
<p>
<table border="1" style="width:100%" id="hideThis">
<tr>
<td>This should be hidden when "totalItems" equals "enteredItems"</td>
</tr>
</table>
jsfiddle Demo
$(document).ready( function() {
$('#totalItems, #enteredItems').keyup(function(){
if( $('#totalItems').val() == $('#enteredItems').val() ){
$('#hideThis').hide();
}else{
$('#hideThis').show();
}
});
});
If you need to check also at page load:
function checkFields(){
if( $('#totalItems').val() == $('#enteredItems').val() ){
$('#hideThis').hide();
}else{
$('#hideThis').show();
}
}
$(document).ready( function() {
$('#totalItems, #enteredItems').keyup(function(){
checkFields();
});
checkFields();
});
Plain JavaScript implementation:
function checkFields(){
if( document.getElementById('totalItems').value == document.getElementById('enteredItems').value ){
document.getElementById('hideThis').style.display = 'none';
}else{
document.getElementById('hideThis').style.display = 'inline-block';
}
}
document.getElementById('totalItems').addEventListener('keyup', function (){
checkFields();
}, false);
document.getElementById('enteredItems').addEventListener('keyup', function (){
checkFields();
}, false);
checkFields();
Here is the new JSFiddle
$(document).ready(function () {
var webpart_ID = 'hideThis';
var FieldA_id = 'totalItems';
var FieldB_id = 'enteredItems';
if ($('#' + FieldA_id).val() === $('#' + FieldB_id).val())
$('#' + webpart_ID).hide();
else
$('#' + webpart_ID).show();
});
This works.
You can bind a keyup events for both the text boxes, from where you can call a function to check if both the values are same..
compare();
$("#totalItems,#enteredItems").keyup(function() {
compare();
});
function compare() {
if ($("#totalItems").val() == $("#enteredItems").val()) {
$("#hideThis").hide();
} else {
$("#hideThis").show();
}
}
Fiddle

Dynamically Created Div Change Drop Down options

// function to add set of elements
var ed = 1;
function new_server() {
ed++;
var newDiv = $('#server div:first').clone();
newDiv.attr('id', ed);
var delLink = '<a class="btn btn-danger" style="text-align:right;margin-right:65px" href="javascript:deled(' + ed + ')" > Delete server ' + ed + ' </a>';
newDiv.find('tr:first th').text('Server ' + ed);
newDiv.find('select:first').attr('id', 'cat' + ed);
newDiv.append(delLink);
$('#server').append(newDiv);
newDiv.find('input:text').val('');
web = new Array('CF9', 'CF10', 'CF11', 'ASP.NET', 'PHP', 'CMS', 'JAVA');
db = new Array('MSSQL Express', 'MSSQL Web', 'MSSQL Standard', 'MYSQL');
app = new Array('IMIS', 'TERMINAL', 'AD');
populateSelect();
$(function() {
$('#cat' + ed).change(function() {
populateSelect();
});
});
function populateSelect() {
cat = $('#cat' + ed).val();
$('#item').html('');
if (cat == 'Web') {
web.forEach(function(t) {
$('#item').append('<option>' + t + '</option>');
});
}
if (cat == 'DB') {
db.forEach(function(t) {
$('#item').append('<option>' + t + '</option>');
});
}
if (cat == 'App') {
app.forEach(function(t) {
$('#item').append('<option>' + t + '</option>');
});
}
}
alert(ed);
}
// function to delete the newly added set of elements
function deled(eleId) {
d = document;
var ele = d.getElementById(eleId);
var parentEle = d.getElementById('server');
parentEle.removeChild(ele);
//ed--;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="server">
<div id="1">
<table border="3">
<tbody>
<tr>
<th colspan="4" style="background-color:#b0c4de;">Server 1</th>
</tr>
<br>
<tr>
<td>Technology
<br>
<select name="tech[]" id="cat1">
<option value="">Select</option>
<option value="Web">Web</option>
<option value="DB">DB</option>
<option value="App">App</option>
<option value="O">Other</option>
</select>
<br>
<select id="item" name="techtype[]">
</select>
<br>
</td>
<td>CPU?
<input type="text" name="cpu[]">
<br>
</td>
<td>Memory?
<input type="text" name="memory[]">
<br>
</td>
<td>Disk Space?
<input type="text" name="space[]">
<br>
</td>
</tr>
<br><a class="btn btn-info" href="javascript:new_server()"> Add New Server </a>
<br>
</tbody>
</table>
</div>
</div>
I have a form as follows:
On page load I cannot update any of the select items.
If i add a new server It will then allow me to change the selects from the first,
If i create a third same result.
I think what is happening is my id's for the select are not changing an im not sure why, I put a JS alert at the bottom to verify that 'ed' is changing as it loops.
End result Im looking for it to be able to change the values of the select from the first and then when another server is added be able to change those select values with out changing any others and so on.
ANy help would be great.
You are using a counter to dynamically create ID's for your servers, so they look like $("#"+cat+counter).
Probleme is you also use your counter to impact lists in populateSelect(), that means you only modify list content of your last created server.
Here is a demo of what I understand of your projet, and a solution that I can give you.
Most changes are about this :
$(function () {
$(document).on("change", '.cat', function () {
populateSelect($(this).val, $(this).attr("id"));
});
});
And this :
function populateSelect(listValue, listID) {
var serverItem = $("#" + listID).closest(".tableServer").find('.item')
cat = $("#" + listID).val();
serverItem.html('');
...
You can see that I changed id="item" for class="item" (this way, cloned servers won't duplicat id="item").
I moved your arrays on top of your code to be reachable from every function
I also moved your populateSelect function and $(function() { outside the new_server() function
I added newDiv.find('.item').html(''); into new_server() function to not clone previously selected option.
I added class="tableServer" to table wrapper in order to dynamically target them in populateSelect()

Table [Row] cannot be deleted using jquery

I am having trouble deleting the row off the table using the button.
Live: http://jsfiddle.net/Z7fG7/21/
HTML:
<select class="combobox form-control">
<option value="" selected="selected">Choose a Person</option>
<option>Bob</option>
<option>Kyle</option>
</select>
<br>
<!-- Table -->
<table class="table">
<thead>
<div class="container">
<tr>
<th>First Last Name</th>
</tr>
</div>
</thead>
</table>
JS/Jquery:
$('.combobox').change(function(e) {
var selectedVal = $(this).val();
$('.table').append('<tr><td>' + selectedVal + '</td><td><img class="delete" src="images/delete.png" width="25" height="25"/></td></tr>');
});
$('table td img.delete').click(function(){
$(this).parent().parent().remove();
});
I am using Bootstrap. Any help would be great!
Have a look into delegated events http://learn.jquery.com/events/event-delegation/
Demo: http://jsfiddle.net/robschmuecker/Z7fG7/20/
var i = 1;
$("#addbutton").click(function () {
$("table tr:first").clone().find("input").each(function () {
$(this).val('').attr({
'id': function (_, id) {
return id + i
},
'name': function (_, name) {
return name + i
},
'value': ''
});
}).end().appendTo("table");
i++;
});
$(document).on('click', 'button.removebutton', function () {
alert("aa");
$(this).closest('tr').remove();
return false;
});
The click handler for the delete image has to be added to every new row in the table.
$('.combobox').change(function(e) {
var selectedVal = $(this).val();
$('.table').append('<tr><td>' + selectedVal + '</td><td><img class="delete" src="images/delete.png" width="25" height="25"/></td></tr>');
$('table td img.delete').click(function(){
$(this).parent().parent().remove();
});
});
Or, in addition to above, when you use .clone by default it remove all events. A cleaner answer using your existing code:
EDIT: Forgot to explain! Using .clone(true) keeps the events. Your .on function is working correctly without needing to reapply it on each new row too.
var i = 1;
$("#addbutton").click(function() {
$("table tr:first").clone(true).find("input").each(function() {
$(this).val('').attr({
'id': function(_, id) {return id + i },
'name': function(_, name) { return name + i },
'value': ''
});
}).end().appendTo("table");
i++;
});
$('button.removebutton').on('click', function() {
alert("aa");
$(this).closest( 'tr').remove();
return false;
});

Categories