Reputation: 177
I've this javascript function:
function modifica(txtValoreID, txtRicalcolatoID, lblDeltaID) {
// Ricalcolo il valore aggiornato
var Valore = parseFloat($("#" + txtValoreID).val()).toFixed(2);
var Ricalcolato = parseFloat($("#" + txtRicalcolatoID).val()).toFixed(2);
$("#" + lblDeltaID).html(parseFloat(Valore - Ricalcolato).toFixed(2).replace('.', ','));
}
That refers to textbox and label in a gridview:
<asp:TemplateField>
<ItemTemplate>
<asp:TextBox ID="txtValore" Width="90%" Text='<%# string.Format("{0:N}", Eval("Valore"))%>' runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:TextBox ID="txtRicalcolato" Text='<%# string.Format("{0:N}", Eval("Ricalcolato")) %>' runat="server" />
</ItemTemplate>
</asp:TemplateField>
(...)
<asp:TemplateField HeaderText="Delta">
<ItemTemplate>
<asp:Label ID="lblDelta" Text='<%# string.Format("{0:N}", Eval("Delta"))%>' runat="server" />
</ItemTemplate>
</asp:TemplateField>
And I'm assigning it in the DataBound:
txtValore.Attributes.Add("onchange", "modifica('" + txtValore.ClientID + "', '" + txtRicalcolato.ClientID + "','" + lblDelta.ClientID + "')");
txtRicalcolato.Attributes.Add("onchange", "modifica('" + txtDaLiquidare.ClientID + "', '" + txtRicalcolato.ClientID + "','" + lblDelta.ClientID + "')");
and it's working perfectly. The problem is that when the gridview have a lot of records, databound is affecting the performance, so my first question is, am I improving this performance moving the assignment from databound server code to aspx page? And if yes, how can I do that? Because I'm trying like this:
asp:TextBox ID="txtValore" onchange="test(this.id)" Text='<%# string.Format("{0:N}", Eval("PremioLiquidare"))%>' runat="server" />
and this:
function test(txtID) {
alert('TEST ' + $(this));
alert('TEST ' + $(this).val());
alert('TEST ' + $("#" + txtID).val());
alert('TEST ' + $("#" + txtID).find("[id*='txtRicalcolato']").val());
alert('TEST ' + $("#" + txtID).closest("[id*='txtRicalcolato']").val());
alert('TEST ' + $(this).find("[id*='txtRicalcolato']").val());
alert('TEST ' + $(this).closest("[id*='txtRicalcolato']").val());
}
But the first is printing TEST Object object, the second blank and the third the correct value, but the others are undefined.. What I'm doing wrong?
The rendered HTML is:
<table class="mGrid" id="ctl00_MainContent_grid">
<tbody>
(...)
<tr>
(...)
<td>
<input name="ctl00$MainContent$grid$ctl03$txtValore" value="1.693,44" id="ctl00_MainContent_grid_ctl03_txtValore" onchange="test(this.id)" type="text">
</td>
<td>
<input name="ctl00$MainContent$grid$ctl03$txtRicalcolato" value="169,34" id="ctl00_MainContent_grid_ctl03_txtRicalcolato" onchange="test(this.id)" type="text">
</td>
(...)
<td>
<span id="ctl00_MainContent_grid_ctl03_lblDelta">-1.524,10</span>
</td>
(...)
</tr>
(...)
</tbody>
</table>
Upvotes: 1
Views: 2785
Reputation: 93601
You are trying to search from the element down with find
, and the element upwards with closest
but the target element is in another branch of the DOM.
find
only searches from the element downwards (its descendants)closest
searches the ancestors only (not literally the closest match).You need to search up with closest
, then find
down:
e.g. the 3rd and 4th ones should be:
alert('TEST ' + $("#" + txtID).closest('someCommonParentElementSelector').find("[id*='txtRicalcolato']").val());
Suggestion: Use a single Delegated Event Handler
Instead of adding attribute-based change handlers, use a single delegated event handler attached to a non-changing ancestor element (e.g. a surrounding table
or div
). This has a much lower overhead and keeps all the code in one place.
Based on your new HTML example, a delegated event handler would go something like this:
// Shortcut DOM ready handler
$(function(){
// Listen for change events bubbling up to the grid,
// then match elements with ID ending in "txtValore"
$('.mGrid').on('change', 'input[id$="txtValore"]' function(){
// this is the *txtValore field that changed
var $input = $(this);
// Find the matching input by looking up (to closest row) and then down the tree
// for an element with ID ending in "txtRicalcolato"
var $otherInput = $input.closest('tr').find('input[id$="txtRicalcolato"]');
// now do "something" with the two inputs :)
});
});
Notes:
onChange
attributes from your inputs.$('.mGrid input[id$="txtValore"]').on('change', function(){
or$('.mGrid input[id$="txtValore"]').change(function(){
but delegated events are more flexible.[id$=""]
selector is an ends-with selector as your actual IDs start with a generate prefix..mGrid
), then applying the jQuery selector to the elements in the bubble-chain that caused the event, then applying the function. This works for dynamically added elements too as the selector is run at event time and not event-registration time.Update: ID generation changed
In comment you mention the ID generation changed so that the suffix was no longer at the end of the id (a underscore and number was appended). jQuery also has an attribute contains selector *=
which would change the example code to:
// Shortcut DOM ready handler
$(function(){
// Listen for change events bubbling up to the grid,
// then match elements with ID containing "txtValore"
$('.mGrid').on('change', 'input[id*="txtValore"]' function(){
// this is the *txtValore field that changed
var $input = $(this);
// Find the matching input by looking up (to closest row) and then down the tree
// for an element with ID containing "txtRicalcolato"
var $otherInput = $input.closest('tr').find('input[id*="txtRicalcolato"]');
// now do "something" with the two inputs :)
});
});
Upvotes: 1