How to edit this code to make it use the current element? - javascript

I'm working on Symfony project, so I have a form that is generated by data-prototype. Basically is a form with 6 inputs, and I have a function that takes values of date.input and duration.input and must calculate a endingDate and paste it in a <h5>.
So, this form can be generated as many times as you want, and all inputs have same structure, like loan_charges_1_date, loan_charges_1_duration ... next one will be with same id, except the number... loan_charges_2_date... or any other number.
I implemented a script that is collecting all id's of date inputs, and all of duration, and make a array that contain this values in pair, like
pairs = [
[loan_charge_1_date, loan_charge_1_duration],
[loan_charge_2_date, loan_charge_2_duration],
[loan_charge_151_date, loan_charge_151_duration],
[loan_charge_302_date, loan_charge_302_duration],
];
From my requirements, each generated form is a table row with inputs in td.
First I introduce the date, then duration, and onkeyup of introducing duration, it must .html() (for now) value of date input, but from this form.
What I have now is that it works with .last.html(dateValue);, which makes me problem, cause if I generate at once more than 1 additional form, and start fill the first one, the hint h5 of output of LAST form is filled. Or if I fill forms one-by-one, but after that I want to edit a date or duration of previous form inputs, it will show a result not at current hint, but at the last one.
Please, watch my JSFiddle code with comments : https://jsfiddle.net/x2j72xou/3/ (but it is impossible to sent all the code, cause it's from many files and it's rendered from Symfony, and so on). A screenshot how it is now you can see here : http://imgur.com/IEORqHB
How it is possible to detect the index or id of each input was changed, and based on it, to fill that h5 hint, not the last one?
Thank you!

You are over-complicating the whole thing with those arrays and trying to use id selectors
Can do it something like:
// assign input event listener to date and duration <input>s
$('input[id$="_duration"], input[id$="_date"]').on('input', function(event){
// `this` is matching element that the event occurred on
// work within each row instance
let $row = $(this).closest('tr'),
// find() the inputs in this row
$durInput = $row.find('input[id$="_duration"]'),
startDate = $row.find('input[id$="_date"]').val(),
duration = $durInput.val();
// do some validation before proceeding
if(!startDate || ! duration){
return;
}
let endDate = calcEndDate(startDate, duration);
// add the <h5> if it isn't there yet
if(!$durInput.siblings('h5').length){
$durInput.after("<h5></h5>")
}
$durInput.siblings('h5').text(endDate)
});
function calcEndDate(startDate, duration){
// do whatever needed , returning start for now
return startDate
}
The important part of any repeating components such as this is to work within the main repeating container...in this case each <tr>
DEMO

I'm not exactly sure why you're making those pairs first, but it seems that you're only doing this so you know which date belongs to which duration. You don't really need to do that though, since you can easily find the matching elements inside the event handler. You know that the element that triggered the event is a duration input, so you just need to find the date input that is in the same row.
I've made an example below that does just that. I've stripped down your code to a bare minimum for running this snippet.
You also say that you can make a lot of these rows and I'm not sure if you mean to do this dynamically, so just to be safe I delegated the events.
$(function() {
$(document).on('keyup', '.loan_charges_duration', function() {
var $duration = $(this);// this is your duration input for this row
var $row = $duration.closest('tr');
var $date = $row.find('.loan_charges_date');// this is your date input for this row
// check for an h5 element after duration, else create and insert it
var $h5 = $duration.next('h5');
if ($h5.length==0) {
$h5 = $('<h5>').insertAfter($duration);
}
// set the html of the h5 element for this row
$h5.html('date: '+$date.val()+' | duration: '+$duration.val());
});
});
td {
vertical-align: top;
}
h5 {
border: 2px solid red;
padding: 4px;
margin: 4px 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<table>
<tr>
<td>1</td>
<td>
<label for="loan_charges_0_date">Date</label>
<input type="text" id="loan_charges_0_date" name="loan[charges][0][date]" class="form-control loan_charges_date" value="13/12/2001">
</td>
<td>
<label for="loan_charges_0_duration">Duration</label>
<input type="text" id="loan_charges_0_duration" name="loan[charges][0][duration]" class="form-control loan_charges_duration" value="11">
</td>
</tr>
<tr>
<td>2</td>
<td>
<label for="loan_charges_1_date">Date</label>
<input type="text" id="loan_charges_1_date" name="loan[charges][1][date]" class="form-control loan_charges_date" value="01/01/2001">
</td>
<td>
<label for="loan_charges_1_duration">Duration</label>
<input type="text" id="loan_charges_1_duration" name="loan[charges][1][duration]" class="form-control loan_charges_duration" value="24">
</td>
</tr>
<tr>
<td coslpan="3">...</td>
</tr>
<tr>
<td>151</td>
<td>
<label for="loan_charges_151_date">Date</label>
<input type="text" id="loan_charges_151_date" name="loan[charges][151][date]" class="form-control loan_charges_date">
</td>
<td>
<label for="loan_charges_151_duration">Duration</label>
<input type="text" id="loan_charges_151_duration" name="loan[charges][151][duration]" class="form-control loan_charges_duration">
</td>
</tr>
</table>

Related

How to fetch the value of the second input tag in the html snippet below?

<td>
<input class="checkboxColumn" name="An" value="9FFF8546C9E9A200F7780550E6A4B6F9610B29D3A" type="checkbox">
<input id="AList" name="AList" value="9FFF8546C9E9A200F710550E6694B6F9610B29D3A|Disabled" type="hidden">
</td>
I have above td as first column in the Jquery datatable. I Need to fetch the value of the #AList using below javascript logic. But the alert below shows the value
of first input tag for all rows when iterates. What are the changes I need to make to display value of second tag?
var rows = oTable.fnGetNodes();
for (var i = 0; i < oTable.fnSettings().aiDisplay.length; i++) {
debugger;
// Get HTML of 3rd column (for example)
alert($($(rows[i]).find("td:eq(0)").html()).val());
}
On displaying
alert($(rows[i]).find("td:eq(0)").html());
The alert shows complete markup of contents of <td>
I need output as "9FFF8546C9E9A200F710550E6694B6F9610B29D3A|Disabled"
Because the html() gets the content as html. You need to access the input in the td and then get it's value with val().
alert($(rows[i]).find("td:eq(0) #AList").val());
For Example you can see here(In example I intentionally get the table then the td)
console.log($('table').find("td:eq(0) #AList").val());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td>
<input class="checkboxColumn" name="An" value="9FFF8546C9E9A200F7780550E6A4B6F9610B29D3A" type="checkbox">
<input id="AList" name="AList" value="9FFF8546C9E9A200F710550E6694B6F9610B29D3A|Disabled" type="hidden">
</td>
</tr>
</table>
alert($(rows[i]).find("td #AList").val());
This should work. You will be able to get the value desired.
If you generalize the case for all second input box in the td then use the pseudo selector - nth-child(n).
alert($(rows[i]).find("td>input:nth-child(2)").val());

How to extract value from table with mixture of html elements

I have a table which contains a combination of plain text, input textboxes, selects, and spans. I need to iterate through the table row by row and pull out the value in each cell. Within my table all <tr> have a particular css class.
$(".gridBody").each(function(rowindex){
$(this).find("td").each(function(cellIndex){
var cell = $(this).first()
})
In my debugger I can see what kind of object is being returned by $(this).first() but I can't find out how to get into its attributes. I have tried using jqueries html parser to turn it back into a dom element, but instead of getting, for example, a textbox, I get something like [[html inputtextbox]]. Most of the methods that work on regular dom elements are not working for me.
If I use $(this)[0].innerText it returns the correct value when the contents of the cell are plain text, but not when they are a form of input or nested in a span element. What I would really like to be able to do is get a regular html dom element back that I can then check the type of with $.is() and then vary much logic from there.
How do I get the first child element in a table cell as an html dom element that I can manipulate with jquery like any other dom element?
var collected = $("#myTable td").find("input, textarea, span").map(function(){
return this.value || this.textContent;
}).get();
console.log( collected ); // an array holding values or text
http://jsbin.com/zewixe/2/edit?html,css,js,console,output
If you want only the immediate children than use the right > selector
(">input, >textarea, >span")
Heres how I would do it:
<table>
<tr>
<td>
<h1>Some stuff.</h1>
</td>
</tr>
<tr>
<td>
<input type="text" value="1"/>
</td>
<td>
<input type="text" value="2"/>
</td>
</tr>
<tr>
<td>
<input type="text" value="3"/>
</td>
</tr>
<tr>
<td>
<input type="text" value="4"/>
</td>
</tr>
</table>
$(function() {
function getFormData(selector){
'use strict';
var formTypes = {
text: 'text',
radio: 'radio',
select: 'select'
},
values = [];
$(selector).children().each(function(idx, childNode) {
if (childNode.getAttribute('type') && formTypes[childNode.getAttribute('type')]) values.push(childNode.value);
});
return values;
}
alert(
getFormData('table tr td.someClass')
);
})();
http://codepen.io/nicholasabrams/pen/RaKGjZ

Select closest control element regardless of type (Input, Select etc.) for Validation

Let me explain:
I have a table form and some fields are required and I am trying to create custom validation.
example:
<table>
<tr>
<td class="required">Description</td>
<td>
<input id="input1" />
</td>
<td>Phone</td>
<td>
<input id="input2" />
</td>
</tr>
<tr>
<td class="required">Location</td>
<td>
<select id="select1"/>
</td>
<td>Email</td>
<td>
<input id="input3"/>
</td>
</tr>
</table>
What I wanna do is find all elements with class required
which is pretty easy using:
var requiredElements = document.querySelectorAll(".required");
And then I want to find their closest control element and check if it's value is empty. The problem is I don't know if it's gonna be input or select. I was thinking of using the .closest() function but it could lead to unwanted results if two different inputs are equally close to a required (like in the example above).
Any help would be much appreciated.
You can select a control regardless of type with jQuery by using any one of a number of selectors and combining it with one or more additional selectors.
In the code snippet you provide, the controls you want to select (input1 and select1) are child elements of a table cell element that is a sibling of the cell with the class "required", so we can build a selection thus:
$(".required + td").child
which breaks down as:
Find the elements with the "required" class applied to them.
This will give us the 2 table cells:
<td class="required">Description</td>
and
<td class="required">Location</td>
For each element returned by 1. use the "next adjacent" selector + with td to get the next table cell:
<td><input id="input1" /></td>
and
<td><select id="select1" /></td>
For each element returned by 2. get the child element:
<input id="input1" />
and
<select id="select1" />
There is also a jsFiddle to illustrate actions on the targets (change border to dark red).
Edit
This works because the layout in your snippet consistently places the elements you want to target in the same position relative to the element with your selection criteria. You must have some consistent way of finding elements that are not marked with a class/id otherwise you can't achieve your objective.
Although I like Raad's answer I'd like to post this answer to say what I did to solve my problem.
First of all I added a custom attribute labelFor to every label td with value equal to the id of it's corresponding input as follows:
<table>
<tr>
<td class="required" labelFor="input1">Description</td>
<td>
<input id="input1" />
</td>
<td labelFor="input2">Phone</td>
<td>
<input id="input2" />
</td>
</tr>
<tr>
<td class="required" labelFor="select1">Location</td>
<td>
<select id="select1"/>
</td>
<td labelFor="input3">Email</td>
<td>
<input id="input3"/>
</td>
</tr>
</table>
Then I used the following Validation function:
function validateForm () {
var self = this;
var validationPassed = true;
//First I will gather every .required element in an Array
var requiredTags = document.querySelectorAll(".required");
//Then I will loop through the array
for (var i = 0; i < requiredTags.length; i++) {
//Get value of attribute "labelFor" which would be the controlId that this label refers to
var controlId = $(requiredTags[i]).attr("labelFor");
//Then I use this to check if that control's value is empty.
if ($("#" + controlId).val() == ('' || null)) {
validationPassed = false;
}
}
if (!validationPassed) {
alert("Please fill all the required fields");
}
return validationPassed;
}
This way I check if all required fields are not empty and return true, or return false and an alert to warn user.
I find that the problem Raad described in his Edit is the main reason why this approach could be more useful. You don't have to worry if your input element is always in the same position relatively to your label td element.

jQuery: Duplicate a table row and then alter the name of the inputs therein based on a specific naming convention?

I have a tricky situation where I need to duplicate a table row, and then alter the names of the inputs to a very specific format. The inputs are named as follows:
data[ProjectRequirement][0][description]
data[ProjectRequirement][0][qty]
...
Now, when the above row is duplicated, the inputs need to be named as follows:
data[ProjectRequirement][1][description]
data[ProjectRequirement][1][qty]
...
And so the pattern must continue. Duplicating the row is not a problem, and I have used the following method:
$j(\'table.WfTable tr\').live(\'mousedown\', function(e){
if($j(e.target).hasClass(\'add\')){
var clone = $j(e.target).parents(\'tr\').clone();
$j(\'table.WfTable\').find(\'tbody\').append($j(clone));
// NOW I WANT TO DO THE INPUT NAME CHANGE
};
});
Ignore the escaped quotes, the JS is output via PHP. So at present, the row is duplicated and the names are the same. Is there a method whereby once duplicated, I can say:
"get the name of each input in the row, look for a field like [0] or [1] etc and change that value to the value of the rows index number in the table DOM element (ie row 1 is index 0, 2 is index 1...)?"
I can only assume that row 1 of table is at index 0 in the DOM tree of that table, and therefore think there must be a way to use that index data to apply to the input names?
Any help is much appreciated.
Simon
EDIT: Here is one table row, created dynamically (cakePHP view)
<tr class="repeat">
<td valign="top" style="width:250px;padding:10px 10px 10px 0;"><input type="hidden" name="data[ProjectRequirement][1][project_id]" value="1" id="ProjectRequirement1ProjectId"><input type="hidden" name="data[ProjectRequirement][1][id]" value="2" id="ProjectRequirement1Id"><div class="input text"><input name="data[ProjectRequirement][1][resource]" style="width:240px;" maxlength="40" type="text" value="Teachers" id="ProjectRequirement1Resource"></div></td>
<td valign="top" style="padding:10px 0;"><div class="input text"><input name="data[ProjectRequirement][1][description]" type="text" value="Any volunteer (part time) teachers" id="ProjectRequirement1Description"></div></td>
<td valign="top" style="width:150px;padding:10px 0;"><input name="data[ProjectRequirement][1][qty]" style="width:70px;float:left;clear:none;" maxlength="10" type="text" value="20+" id="ProjectRequirement1Qty"> <img src="/trusthau.net/img/buttons/btn_plus.png" style="float:right;clear:none;margin:10px 0 0 0;" class="add" alt=""></td>
</tr>
Something like this:
$().ready(function(){
$('#table tr.repeat:last').clone().appendTo('#table');
$('#table tr.repeat:last td input').each(function(){
var input = $(this),
name = input.attr('name');
name = name.replace(/(\d+)/, function(i) {
return ++i;
});
input.attr('name', name);
})
});​
http://jsfiddle.net/ZFNDD/4/
Can you use last(jQuery('selector').last()) function in the jQuery code which would give you the last row every time.This would give you the appended row and then you can alter the input values by first collecting the number of rows present in the table.
I'm considering that there is going to be duplication of each and every row

JQuery add class with name of closest label

I have a table that needs some custom theming. It has a lot of text inputs and they all need custom widths. I figured it would be nice to simply add custom CSS classes based on the label name of each field. I am part of the way there but for some reason I am picking up all the label names for any given label in the table, not simply the closest one as I desire.
Here is my JQuery:
$('td.label-text', this).each(function() {
// add class with name of the label text
$('td.input-text').addClass($(this).text().replace(/[^a-z]/gi,'').toLowerCase() + ' ').closest("td.label-text");
});
Here is some sample HTML output:
<tr>
<td class="label-text">Rule Name*:</td>
<td class="input-text effectivedate rulename employeeid createrulefor ipaddress active searchby">
<input type="text" name="ruleName" value="">
</td>
</tr>
<tr>
<td class="label-text">Employee ID:</td>
<td class="input-text effectivedate rulename employeeid createrulefor ipaddress active searchby">
<input type="text" name="employeeId" value="" id="empnotext">
</td>
</tr>
As you can see all label names get added to every td .input-text class, not the nearest (closest) one. I am sure I am doing something wrong but not sure what.
I am also wondering if a class can be added based on the input name
You have to use this inside the loop. Currently, you're selecting all elements with selector td.input-text (at each iteration). Fiddle: http://jsfiddle.net/WCTyz/2/
$('td.input-text input', this).each(function() {
// add class with name of the label text
var $this = $(this);
var addclass = $this.parents("tr:first").children("td:first")
.text().replace(/[^a-z]/gi,'').toLowerCase();
$this.addclass(addClass);
});
Also, the addClass method automatically deals with separating spaces. You don't have to manually postfix your class name by a space.
Explanation of selector:
td.input-text input For each <td class="input-text"> ???? <input> ??? </td> :
Get class name:
.parents("tr:first") Select the current row
.children("td:first") Select the first cell
.text() Get the textual value

Categories

Resources