Selecting a dynamically generated option element with a c# webbrowser control - javascript

I am using a c# webbrowser control to navigate through a commercial website I work with. I log in and navigate to a particular list. The list is prospective jobs. Then I continue through some links to bid on those jobs. In the process I ran into a problem.
On one of the forms there are 2 select elements (drop down lists). The options on those lists are generated dynamically by means of some javascript scripts - most of which are available in the source.
In the page source code there is nothing to select. The options appear dynamically when navigating the page manually - but I am trying to navigate it by means of c# in a webbrowser.
Here's the form. (I cut out styles and changed some of the text - and I know it is badly formed, but it is not mine)
<form name="frm1" id="frm1" action="/tab/Transport/LoadAssigned2.asp" method="post">
<table class="section">
<tr>
<td>Name</td>
<td>
<input type="text" name="s_name" id="s_name" size="25" maxlength="50"></td>
</tr>
<tr>
<td>Fax</td>
<td>
<input type="text" name="txtFaxNumber" id="txtFaxNumber" size="25" maxlength="15" value="1234567890"></td>
</tr>
<tr>
<td>Email</td>
<td>
<input type="text" name="txtEmail" id="txtEmail" size="25" maxlength="225"></td>
</tr>
<tr>
<td>Pickup will occur on or before</td>
<td>
<select name="stransp_pickup_date" id="stransp_pickup_date" style="width: 173px;" onchange="setDeliveryDate()">
</select>
</td>
<tr>
</tr>
<td>Delivery will occur on or before</td>
<td>
<select name="stransp_delivery_date" id="stransp_delivery_date" style="width: 173px;">
</select>
</td>
</tr>
</table>
<input type="hidden" name="nload_id" id="nload_id" value="123456789">
</form>
As you can see the two select elements have no option children. Those are created by the scripts, starting with setDeliveryDate:
function setDeliveryDate(){
var distance = 226;
var delivery = $("#stransp_delivery_date");
var pickupDate = $("#stransp_pickup_date option:selected").val();
$("#stransp_delivery_date option").remove();
delivery.append("<option value='-1'>SELECT DATE</option>");
if(distance <=200){
generateDeliveryDates(delivery,pickupDate,2);
}else if(distance >=201 && distance <= 400){
generateDeliveryDates(delivery,pickupDate,3);
}else if(distance >=401 && distance <= 700){
generateDeliveryDates(delivery,pickupDate,4);
}else if(distance >=701 && distance <= 1400){
generateDeliveryDates(delivery,pickupDate,5);
}else if(distance >=1401 && distance <= 1800){
generateDeliveryDates(delivery,pickupDate,6);
}else if(distance >=1801 && distance <= 2200){
generateDeliveryDates(delivery,pickupDate,7);
}else if(distance >=2201 && distance <= 2500){
generateDeliveryDates(delivery,pickupDate,8);
}else if(distance >=2501 && distance <= 4000){
generateDeliveryDates(delivery,pickupDate,9);
}
}
And the generateDeliveryDates functions is:
function generateDeliveryDates(delivery,pickupDate,index){
for (var i = 0; i < index; i++) {
if (moment(pickupDate).add('days', i).format('dddd') == 'Sunday') {
index++;
delivery.append("<option value='" + moment(pickupDate).add('days', i).format('MM/DD/YYYY') + "'>" + moment (pickupDate).add('days', i).format('dddd')+" - "+ moment(pickupDate).add('days', i).format('MM/DD/YYYY') + "</option>");
} else {
delivery.append("<option value='" + moment(pickupDate).add('days', i).format('MM/DD/YYYY') + "'>" + moment (pickupDate).add('days', i).format('dddd')+" - "+ moment(pickupDate).add('days', i).format('MM/DD/YYYY') + "</option>");
}
};
}
IfI can keep showing more of the scripts - but I'm hoping the idea is clear. The options under the select element are created based on an onchange event in the first select element. It is a list of dates.
What I want to do is to select the last of the date options in both cases - but I can't see how to do it before the exist. Also, the number of options in the list varies based on the distance, as you can see above.
How can I access those elements when I can't see them in the page source code?
Very appreciative of any help or guidance.

In case anyone reads this in the future, I ended up solving this myself, and want to share the solution, which is pretty straight forward.
1 - please note that the first "select" element has an onchange function- setDeliveryDate. So the first think I do is invoke that script function once:
webBrowser1.Document.InvokeScript("setDeliveryDate");
Then I collect the child nodes in a collection, and select the last of them:
HtmlElementCollection colOptions =
webBrowser1.Document.GetElementById("stransp_pickup_date").Children;
int colCount = colOptions.Count;
colOptions[colCount - 1].SetAttribute("selected", "selected");
The I re-run the same script, which also creates the options for the second select, and do the same thing (get the option elements into a collection and select the last one):
webBrowser1.Document.InvokeScript("setDeliveryDate");
HtmlElementCollection colOptions2 =
webBrowser1.Document.GetElementById("stransp_delivery_date").Children;
int colCount2 = colOptions2.Count;
colOptions2[colCount2 - 1].SetAttribute("selected", "selected");
The last step is of course to submit the form:
webBrowser1.Document.GetElementById("frm1").InvokeMember("submit");
Hope this helps other newbies like me.

Related

How to create a html/javascript table that automatically selects radiobuttons?

I have only very basic html/javascript understanding.
I am trying to make what is probably only a slight modification to an existing code. Below is, first the original code, and then how I'd like to change it.
Original code:
A table gives the user a choice between left and right for several rows. The table enforces at most a single switch point from left to right going down the table, meaning that if the user chooses right at some row, the table automatically selects right for all rows below, and if the user chooses left at a given row, the table automatically selects left for all rows above. No switch point at all is allowed (meaning left is selected for all rows, or right is selected for all rows). A selection is required for each row (the app checks for this by default already).
{{ block content }}
<table class="table table-striped">
<colgroup>
<col width="45%">
<col width="10%">
<col width="45%">
</colgroup>
<tr>
<td align="right"><b>Option A</b></td>
<td></td>
<td align="left"><b>Option B</b></td>
</tr>
{{ for amount in player.right_side_amounts }}
<tr>
<td align="right">
<b>{{ player.left_side_amount }}</b> now
<td align="middle">
<input type="radio"
value="left"
name="{{ amount|json }}"
required>
<input type="radio"
name="{{ amount|json }}"
value="right" data-amount="{{ amount|json }}"
required>
</td>
<td align="left">
<b>{{ amount }} </b> next month
</tr>
{{ endfor }}
</table>
{{ formfield_errors 'switching_point' }}
<input type="hidden" name="switching_point" id="id_switching_point"
value="9999">
{{ next_button }}
{{ endblock }}
{{ block scripts }}
<script>
$(document).ready(function () {
$('input[type=radio]').change(
function () {
var clickedRadio = this;
var afterClickedRadio = false;
var radios = document.querySelectorAll('input[type=radio]');
for (i = 0; i < radios.length; ++i) {
var radio = radios[i];
if (radio === clickedRadio) {
afterClickedRadio = true;
continue;
}
if (!afterClickedRadio && clickedRadio.value === 'left' && radio.value === 'left') {
radio.checked = true;
}
if (afterClickedRadio && clickedRadio.value === 'right' && radio.value === 'right') {
radio.checked = true;
}
}
}
);
$('.otree-btn-next').click(function () {
var radios = document.querySelectorAll('input[type=radio]');
for (i = 0; i < radios.length; ++i) {
var radio = radios[i];
if (radio.value === 'right' && radio.checked) {
$('#id_switching_point').val(radio.dataset.amount);
break;
} else {
$('#id_switching_point').val(9999);
}
}
});
});
</script>
{{ endblock }}
This is how the original table looks:
original table
Modification:
Just as in the original, I'd like to have the table with a left/right choice, and enforce at most a single switch point. But, I'd like user to have the possibility to express indifference between the left and right choice at the switch point.
In other words, at the row the user chooses to switch from option A to option B, he could choose either "I prefer B" or "I am exactly indifferent between A and B".
I envision a table with three radio buttons per row, where the center button means “I am indifferent”. At whichever row the user chooses to switch ($17 in this image: what I envision) the user could select either the center button (which would express exact indifference) or the right button (which would express preference for option B). Regardless of whether the user chooses center or right button, all rows above would get checked for A, and all rows below would get checked for B. The center button can be selected at most once, since all rows below would be automatically selected right, and all rows above would be automatically selected left.
I think a second variable would need to be created relative to the original code, to record not just the switching point, but also whether the switching point occurred with indifference or strict preference.
Thank you so much for any help.
How's this? If I understood you correctly, then the rules are:
Selecting A checks all A inputs
Selecting B checks all B inputs
Selecting X will make all inputs below the X selection to be the opposite of the first checked input and everything above the X selection defaults to the first checked input selection. (If A, then B after the X. If B, then A after the X)
Prevents selecting more than one X. If more than X, the last checked X will prevail, the previous X changes according to rule 3.
In addition to those rules, I disabled the first and last middle inputs because you didn't say what happens if the first or last middle inputs are checked. Also, I added logic that prevents the user from checking any middle input before anything else is selected since you didn't say what happens in that situation either.
There are some edge cases I didn't code for, but this is more than enough to cover your rules.
https://jsfiddle.net/j1vas2x8/
<table>
<tr>
<th>A</th>
<th>X</th>
<th>B</th>
</tr>
<tr>
<td><input type="radio" name="r1[]" value="A"></td>
<!-- if the first middle selection is not disabled, then which column is the opposite of it? -->
<td><input type="radio" name="r1[]" value="X" disabled="disabled"></td>
<td><input type="radio" name="r1[]" value="B"></td>
</tr>
<tr>
<td><input type="radio" name="r2[]" value="A"></td>
<td><input type="radio" name="r2[]" value="X"></td>
<td><input type="radio" name="r2[]" value="B"></td>
</tr>
<tr>
<td><input type="radio" name="r3[]" value="A"></td>
<td><input type="radio" name="r3[]" value="X"></td>
<td><input type="radio" name="r3[]" value="B"></td>
</tr>
<tr>
<td><input type="radio" name="r4[]" value="A"></td>
<td><input type="radio" name="r4[]" value="X"></td>
<td><input type="radio" name="r4[]" value="B"></td>
</tr>
<tr>
<td><input type="radio" name="r5[]" value="A"></td>
<!-- if the last middle selection is not disabled, then what should should happen if it's selected last? -->
<td><input type="radio" name="r5[]" value="X" disabled="disabled"></td>
<td><input type="radio" name="r5[]" value="B"></td>
</tr>
</table>
var header_row = document.querySelectorAll('table tr th');
var column = {
'left': header_row[0].innerText,
'middle': header_row[1].innerText,
'right': header_row[2].innerText
};
var radios = document.querySelectorAll('input[type="radio"]');
var rows = document.querySelectorAll('table tr');
Array.from(radios).forEach(function(radio) {
radio.addEventListener('click', function(event) {
var is_more_than_one_middle_column_selected = document.querySelectorAll('input[type="radio"][value="' + column.middle + '"]:checked').length > 1;
if (is_more_than_one_middle_column_selected === true) {
// loops through all radio inputs with the middle column checked
Array.from(document.querySelectorAll('input[type="radio"][value="' + column.middle + '"]:checked')).forEach(function(input) {
if (input !== event.target) {input.checked = false;}
});
}
var current_row_index = Array.from(rows).findIndex(function(row) {
var current_input = Array.from(row.querySelectorAll('td input[type="radio"]')).find(function(input) {
return input === event.target;
});
return !!current_input;
});
var middle_selected_input_row_index = Array.from(rows).findIndex(function(row) {
return row.querySelector('input[type="radio"][value="' + column.middle + '"]')?.checked === true;
});
var is_middle_input_selected = middle_selected_input_row_index > -1;
let first_input_column = rows[1].querySelector('input[type="radio"]:checked')?.value || '';
// if the first input has not been checked but a middle input somewhere else has
if (!first_input_column && is_middle_input_selected === true) {
// uncheck the current input, and stop the script here; if script keeps going it will run into null errors
return event.target.checked = false;
}
for (var row_index = 1; row_index < rows.length; row_index++) {
// if the middle input is not checked yet
if (is_middle_input_selected === false) {
// whatever selection the current value, change all inputs to that
rows[row_index].querySelector('input[type="radio"][value="' + event.target.value + '"]').checked = true;
}
else if (is_middle_input_selected === true && row_index < middle_selected_input_row_index) {
// check the previous input to whatever the first checked input value was
rows[row_index].querySelector('input[type="radio"][value="' + first_input_column + '"]').checked = true;
}
else if (is_middle_input_selected === true && row_index > middle_selected_input_row_index) {
// check the previous input to whatever the first checked input value was
rows[row_index].querySelector('input[type="radio"][value="' + (first_input_column === column.left ? column.right : column.left) + '"]').checked = true;
}
// if the current input checked was the input that triggered this logic, and a there was more than one middle input that was checked
else if (row_index === current_row_index && is_more_than_one_middle_column_selected === true) {
// get the first checked input value
let first_input_column = rows[1].querySelector('input[type="radio"]:checked').value;
// check the previous input to whatever the first checked input value was
rows[row_index - 1].querySelector('input[type="radio"][value="' + first_input_column + '"]').checked = true;
}
}
});
});

Trying To Move Input Element to Another Div

I am creating a form that shows one question at a time. I would like to show all questions, though, on a different view when "View Complete Form" is clicked. The problem I am having is showing the questions in said form. There's no issue with the single view questions.
I am able to display the value, on said form but I cannot actually enter anything. That's not what I want.
Ex. in case any one is confused:
(In single view)
Question 1: (input box) Answer 1
(In full view)
Question 1: Answer 1 (All text, no input boxes)
I would like to do:
(In single view)
Question 1: (input box) Answer 1
(In full view)
Question 1: (input box) Answer 1
Like I said, I see how I can get the value (I used answer[i-1] = document.getElementById(i-1).value) then I print the answer BUT WITHOUT THE INPUT BOX.
I realized my mistake so I tried document.getElementById(x) which gives me [object HTMLInputElement]. Again, I just want the input box with the answer already filled in IF it's filled on the single view.
Did some searching on here and tried to use appendTo, descendants and appendChild (object does not support these) but nothing helped.
html
<div id="questionnaire-question">Click 'Start' to begin...</div>
<div id="input-questionnaire">
<input type='text' class='form-control' name='reqEng' id='1' style="display:none" placeholder="Requesting Engineer" required>
</div>
<button id="view-form" onclick="viewForm()">View Complete Form</button>
<form id="full-form" style="display:none">
<div id="full-form-question"></div>
<input type="reset" name="reset" value="Reset Fields">
<input type="submit" name="submit" id="submitQuestionnaire" value="Submit Questionnaire">
</form>
</div>
js
function viewForm() {
for (var x = 0; x < 44; x++) {
//form.appendChild(document.getElementById(x)); // Didn't work
//form.insert(document.getElementById(x).descendants()[x]); // Not supported
//document.getElementById(x).style.display = "block"; // Loop for questions and answers to populate
//document.getElementById(x+1).appendTo(form);
//fullForm.innerHTML += questions[x]+ ": " + answer[x+1] + " <br>";
fullForm.innerHTML += questions[x] + ": " + document.getElementById(x + 1) + " <br>";
}
}
This is what I want (from a previous form. I populated the inputs in an array but found it easier with some functionalities if I had just hard coded it)
https://imgur.com/cgarzSd
This is what I currently have :
https://imgur.com/Uj4FlvZ
Your question could possibly use some clarification, however I am taking a stab at it hoping that we can get you on the right track.
Below is an example of simply moving the input from one div to another:
function viewForm(){
//gets all of the inputs held in the "input-questionnaire" div
var inputs = document.getElementById('input-questionnaire').getElementsByTagName('input');
//loop through the collection of inputs
for(var i = 0;i < inputs.length; i++)
{
//if you want to ensure input is no longer hidden when moved
//inputs[i].style.display = "block";
//move the element to the new div
document.getElementById("full-form-question").appendChild(inputs[i]);
}
//probably want to show the hidden form at this point
document.getElementById("full-form").style.display = "block";
}
Here is another option if you actually want to "copy" the input to the new div:
function viewForm(){
//gets all of the inputs held in the "input-questionnaire" div
var inputs = document.getElementById('input-questionnaire').getElementsByTagName('input');
//loop through the collection of inputs
for(var i = 0;i < inputs.length; i++)
{
//clone the current input
var clone = inputs[i].cloneNode();
//make sure the question is visible?
clone.style.display = "block";
//append the clone to your "full-form-question" div
document.getElementById("full-form-question").appendChild(clone);
}
//probably want to show the hidden form at this point
document.getElementById("full-form").style.display = "block";
}
Hope this helps. Cheers!
Here's a basic example of how you can "move" input elements from one form to another. In reality you're making a copy of it and removing the old one from the previous form.
It looks like the main problem you're having is that you're not defining the form.
Take a look at how you could go about it:
function viewForm() {
const form1 = document.getElementById('form-1')
const form2 = document.getElementById('form-2')
for (var x = 1; x <= 1; x++) {
let input = document.getElementById(x)
form1.remove(input)
form2.append(input);
const span = document.createElement('span');
span.innerText = `${x} is now in form2`
form2.appendChild(span)
}
}
document.getElementById("btnMove").addEventListener('click', viewForm);
<div>
Form 1
<form id="form-1">
<input type='text' class='form-control' name='reqEng' id='1' placeholder="Requesting Engineer" required>
</form>
</div>
<div>
Form 2
<form id="form-2">
</form>
</div>
<input type="button" id="btnMove" value="move input">

how to dynamically increment input control by JavaScript....?

I used for loop to copy the table to n times. The code below works only in first table. How can i get to work in all tables?. I am a beginner.
function copy() {
var text1 = document.getElementById("Name1").value;
document.getElementById("Name2").value = text1;
var text2 = document.getElementById("Name3").value;
document.getElementById("Name4").value = text2;
}
<td rowspan="3" style="height:100px;">Name <input type="text" name="Emp name" placeholder="enter your name" id="Name1" /><br> ID <input type="id" name="Emp Id" placeholder="enter id" id="Name3"> </td>
<tr id="p001">
<td colspan="10" style="border:1px solid #ffffff;height:150px;"><input type="button" value="Get data" onclick="copy();" /><label for="text"> Name : <input type="text" id="Name2"></label>
<label for="text"> ID : <input type="id" id="Name4"></label> </td>
</tr>
ID's should always be unique. When using duplicate ID's it will only work on the first one and ignore the rest. By pushing in the selector to the function you can reuse your function for multiple tables.
https://jsfiddle.net/m5aqdswe/
onclick="copy('Name');"
function copy(selector) {
var text1 = document.getElementById(selector + "1").value;
document.getElementById(selector + "2").value = text1;
var text2 = document.getElementById(selector + "3").value;
document.getElementById(selector + "4").value = text2;
}
Hope this helps
EDIT TO HELP WITH YOUR FIDDLE MISTAKE
After checking your code I can see that you haven't implemented my fix. You have an onclick on the button calling copy();. You're not passing in any arguments so your JS is static. So when you add another table you're creating duplicate ID's.
When searching for an ID document.getElementById("Name1") it will search through the DOM until it finds that first id="Name1" and then stop. That is why your second table never works.
To fix that we need to push in your ID name to the function so that the JS becomes dynamic. copy('Name') where "Name" is the first part of your ID. The numbers will still be used.
In the function you need to grab that arguments by passing it in to the function and calling it whatever you like. I chose 'selector' because it is most descriptive. onclick="copy(selector)"
No the function will replace all the 'selector' variables with the string you passed through, namely "Name" so document.getElementById(selector + "1") will actually be document.getElementById("Name1"). This way you can create as many clones as you like but remember to change the clone table ID's and pass in the correct argument to the onclick.
Here is your fixed fiddle. https://jsfiddle.net/3shjhu98/2/
Please don't just copy, go see what I did. You'll need to fix your clone function to use dynamic arguments instead of static ones.
function check() {
var rowCount = $('table.mytable tbody tr');
for (var index = 0; index < rowCount.length; index++) {
var tr = $('table.mytable tbody tr')[index];
var td = $(tr).find('td');
for (var j = 0; j < rowCount.length; j++) {
copy('table.mytable tbody tr[data-index=' + index + '] td[data-index=' + j + ']');
}
}
}
function copy(selector) {
var val_1 = $(selector).find('input:first').val();
$(selector).find('input:last').val(val_1);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<table class="mytable">
<tbody>
<tr data-index="0">
<td data-index="0">
<input type="text" onblur="check()" />
<input type="text" />
</td>
</tr>
</tbody>
</table>
Hi. try it...
I think you need to pass table selector like [ table.className ] etc. then you find input text box and get the value this and paste into another text box.
Like this.
///it mean you pass first table row of first table data.
copy('table.className tbody tr[data-index=1] td[data-index=1]');
function copy(selector) {
var val_1 = $(selector).find('input#Name1').val();
$(selector).find('input#Name2').val(val_1);
}

Retrieving values from input elements in a table in HTML

I have a table set up as such:
<table id="mantab" style="cursor:pointer;" onkeypress="scan(event)">
<tr>
<td><input type='text' placeholder="Term" id='inp1' class="inp1" /></td>
<td><input type='text' placeholder="Definition" id='inp2' class="inp2" /></td>
</tr>
</table>
An action can be taken to add a row to this table, which is done by inserting a cell via the insertCell method and setting that cell's innerHTML appropriately.
What I've been trying to do is iterate through the first column of the table and add up all the values from inputs in each cell (after they've been entered) in a comma separated string. This process should be repeated for the second column.
The problem:
Everything I attempt to read is undefined
I've tried the following approaches to retrieving the contents of a cell:
document.getElementById("id").value,
document.getElementByClassName("classname").value,
table.rows[0].cells[0].value,
table.rows[0].cells[0].val(),
table.rows[0].cells[0].innerHTML,
table.rows[0].cells[0].children[0].val()
None work, some return blank, most undefined. The innerHTML one returns the input element inside the cell, but there is no actual text input data.
If a clearer picture of what I'm looking at is needed, see the following:
This should return one variable containing a string: "KeyA,KeyB,KeyC" and another with: "ValueA,ValueB,ValueC"
I'm somewhat new to javascript, but I have a basic knowledge of a couple other languages. I'm not sure why iterating through a table is posing such a challenge. Any help clarifying how I can extract these "invisible" values would be appreciated. Thanks.
Here is one of many approaches that isn't working for me:
for (var i = 0, row; row = table.rows[i]; i++) {
for (var j = 0, col; col = row.cells[j]; j++) {
if(j == 0) { //if first column
words += col.getElementsByClassName("inp1").value + ","; //inp1 refers to first column input class name
} else {
defs += col.getElementsByClassName("inp2").value + ","; //inp2 refers to second column input class name
}
}
}
In this example, words is analagous to the first variable from the image above, and defs to the second.
Update: logging the values and the element responsible for providing the values resulted in this:
The first log is blank, and the second has no value assigned, even though I typed in something.
You can do something like this using jQuery selectors
$("#bt").click(function()
{
var keys = [], values = [];
$('table tr input').each(function(i,e){
//access the input's value like this:
var $e = $(e);
if($e.hasClass('key')){
keys.push($e.val());
}else{
values.push($e.val());
}
});
keys = keys.join(',');
values = values.join(',');
console.log(keys);
console.log(values);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="mantab" style="cursor:pointer;">
<tr>
<td><input type='text' placeholder="Term" id='inp1' class="key" /></td>
<td><input type='text' placeholder="Definition" id='inp2' class="value" /></td>
</tr>
<tr>
<td><input type='text' placeholder="Term" id='inp1' class="key" /></td>
<td><input type='text' placeholder="Definition" id='inp2' class="value" /></td>
</tr>
</table>
<button id="bt">
Get Value
</button>
what about using jQuery and finding all inputs in a table:
$('table input').each(function(i,e){
//access the input's value like this:
console.log($(e).val());
});

Autofill Amount

I have this split function which I can add more fields by clicking the button. My Problem are if I add a field I can't get the exact amount and back the amount if I remove the field.
Sample Scenario:
The above image show the initial amount -1,000.50. Now these are my problems.
I input 50 in the amount of first field which result to Payee: 1 [-950.50] as the remaining amount for payee. When I add another field it's auto fill the amount and I expect -950.50 because that's the remaining amount. But what I get is the initial amount -1,000.50 in the second field. How to get the updated remaining amount?
If I remove the added field I want to added back the amount. For ex. if the field has 50 and the remaining amount is -950.50. If I remove the field that contains amount of 50 it must be added back in the remaining amount and it will be -1,000.50. How to added back the amount?
Here are what I have tried:
split.html
<table id="dataTable" class="calendar fluid" data-calendar-options='{"maxHeight":70}'"
<caption> Payee: 1
[<span id="remaining">-1,000.50</span>]
</caption>
<tbody>
<tr>
<td class="week-end" id="p_scents"><br/>
*Note: Amount totals must equal transaction total and envelopes must be specified to
enable the split button.<br/><br/>
<p class="button-height">
<span class="input">
<label class="button orange-gradient">Envelope #1</label>
<select name="env[]" class="envelope select compact">
<option value="none">(Select)</option>
<optgroup label="Category">
<option value="1">Internet</option>
<option value="2">Savings</option>
</optgroup>
</select>
<input type="text" name="amt[]" placeholder="0.00" size="10"
id="validation-required" class="input-unstyled input-sep validate[required]"
onkeyup="calculate(0)">
<input type="text" name="note[]" placeholder="note" class="input-unstyled" id="note">
</span>
<span class="with-tooltip">
<img src="{{STATIC_URL}}img/icons/tick.png" title="Default">
</span>
</p><br/>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>
<a href="javascript:{}" id="addScnt" class="button orange-gradient icon-plus-round">
Another Envelope
</a>
</td>
</tr>
</tfoot>
</table>
<script>
function calculate(difference) {
var sum = 0;
$(":text").each(function() {
amt = replaceCommaDollar(this.value);
if(!isNaN(amt) && amt.length!=0) {
sum += parseFloat(amt);
total = sum;
difference = -1,000.50 + total
}
});
$("#remaining").html(numberWithCommas(difference.toFixed(2)));
if(difference == 0){
$("#split").html("<button type='submit' class='button orange-gradient'>Split Amount</button>");
}else{
$("#split").html("<button type='submit' class='button orange-gradient' disabled='disabled'>Split Amount</button>");
}
}
$(function() {
var scntDiv = $('#p_scents');
var i = $('#p_scents p').size() + 1;
var remain_amount = Math.abs(replaceCommaDollar($("#remaining").text())).toFixed(2);
$('#addScnt').live('click', function() {
$('<p class="button-height">'+
' <span class="input">'+
' <label class="button orange-gradient">' + 'Envelope #' + i + '</label>' +
' <select name="env[]" class="envelope select compact">'+
' <option value="none" selected="selected">(Select)</option>' +
' <optgroup label="Category">' +
' <option value="1">Internet</option>' +
' <option value="2">Savings</option>' +
' </optgroup>' +
' </select>' +
' <input type="text" name="amt[]" id="split-amount' + i + '" placeholder="0.00" size="10" class="input-unstyled input-sep" onkeyup="calculate(0)" value="'+ remain_amount +'">'+
' <input type="text" name="note[]" placeholder="note" class="input-unstyled">'+
' </span>'+
' Remove</p><br/\>'
).appendTo(scntDiv);
$("#remaining").html('0.00');
$("#split").html("<button type='submit' class='button orange-gradient'>Split Amount</button>");
i++;
return false;
});
$('#remScnt').live('click', function() {
if( i > 2 ) {
test = $('#split-amount'+i).val();
alert(test);
$(this).parents('p').remove();
i--;
}
return false;
});
});
</script>
How to get the updated remaining amount? You are calculating remain_amount on document ready, instead of when you click the add button. You need to move its calculation within the click handler for #addScnt. Just make it the first line of that function and it should recalculate accordingly.
How to added back the amount? We can do this by reading the value out of the input field we are removing. Here is the modified remove click handler to demonstrate.
$('#remScnt').live('click', function() {
// Might not need the if statement
if (i > 2) {
//test = $('#split-amount' + i).val();
//alert(test);
var $p = $(this).parents('p');
// Consider this approach to getting the removed value
var textValue = $p.find('input[name="amt[]"]').val();
var numValue = replaceCommaDollar(textValue);
var $remaining = $("#remaining");
var remainingValue = replaceCommaDollar($remaining.text());
var difference = remainingValue - numValue;
var newRemainingValue = numberWithCommas(difference.toFixed(2)))
$("#remaining").text(newRemainingValue);
$p.remove();
// This might not be needed anymore
i--;
}
return false;
});
Note that given my approach to obtaining the removed value, you might be able to get rid of the logic involving i unless you have other work to do. Consider searching the DOM based on the element you're removing. This is probably slower to execute, but not unreasonably so. It's your choice though and it shouldn't matter too much either way. I think my suggestion is easier to maintain, and if I were to optimize there are other aspects of this page that deserve more attention.
I also recommend creating a functional jsFiddle in the future, your problem would have been much easier to test and solve with a functioning example. I tried creating one, but I had to alter the HTML and JavaScript too significantly, as there are missing JavaScript functions in the source you provided.
I hope that helps! Feel free to ask any questions regarding my answer, but please don't expand the scope of your original problem.

Categories

Resources