I have a table where if X has a value, display X, otherwise, add a link which when clicked will display a textbox where user can input the value. I dynamically assign IDs/classes to the link and textboxes but when I run the application, each click on any link only seems to trigger the first row. I put in alerts to show what row is being clicked and I always get the first row. Looking at the browser DOM explorer, I can see that each row has its own unique ID. How do I get each OnClick event to grab the correct corresponding ID?
C#/Razor code:
<td>
Unmapped
<input type ="submit" class="editAction hidden" value="#string.Format("tr{0}",i)" name="action:ChangeToEditSubAction" />
<input type="hidden" name="#Html.Raw("EntityMapping.EMREntityID")" value="#Html.Raw(Model.DisplayResults[i].EMREntityID)" />
<span class="#string.Format("tr{0}accountTxtBox",i) hidden">#Html.TextBoxFor(m => m.EntityMapping.AssignedHOAccountID)</span> </td>
Javascript Function
function UnmappedClick() {
//$(".accountTxtBox").removeClass("hidden");
//$(".unmapped").addClass("hidden");
//$("#btnSave").removeAttr('disabled');
//$(".editAction").click();
//$(".editAction").val(null);
alert($(".unmapped").attr('id'));
var txtBox = $(".editAction").val();
var actTextBox = "." + txtBox + "accountTxtBox";
$(actTextBox).removeClass("hidden");
alert(txtBox);
}
DOM Explorer Image
You can pass a parameter from your onclick event using the "this" keyword.
onclick="UnmappedClick(this.id)"
function UnmappedClick(id){
//now you have the specific ID
}
or if necessary pass the whole control over
onclick="UnmappedClick(this)"
you can try this
$(this).attr('id') // use this
instead of
$(".unmapped").attr('id')
This will give you the current elements id when you click
As you can see here, using $('.class') will return a list all the elements with that class. When you use $(".unmapped").attr('id') you'll always get the value of the first element in the list, that's why you always get the first row.
The same will happen with var txtBox = $(".editAction").val();. With $(actTextBox).removeClass("hidden"); you'll remove the class hidden from all the elements matched.
To get the id of an element you can use onclick="unmapped(this) or onclick="unmapped(this.id)" using the following code depending on the onclick attribute
function unmapped(element) {
var id = $(element).attr('id')
alert(id)
}
function unmapped(id) {
alert(id)
}
You can check this fiddle to see them in action.
Related
Get the value of a button and print it to the console.
I currently have a number of buttons (html) all have the same ID but different values.
when a button is clicked I want to print its value to the console.
document.getElementById("calcButtonID").addEventListener("click", btnPress);
function btnPress() {
var x = document.getElementById("calcButtonID").value
console.log(x);
}
It always displays the value of the first button ("1") regardless of the button I click,
What am i doing wrong? I think i need to pass the event listener to the function so it knows what button was clicked and not just the first ID it comes across
Thanks for the help (im getting there :) )
As pointed in the comments to the question, you may use e.target.value, or add data-attributes to your buttons, but since you asked about what you're doing wrong, I'll answer that particular question for you to avoid such problems in future.
Basically, an ID must be unique on page, proof here. So your main error is that several buttons have the same ID. What they can share though, is the name attribute, if for some reason you need them to be processed as a single element.
However, in this latest case, I would recommend using <input type="radio">, i.e., a group of radio buttons with the same name, but again, with different unique IDs.
You cannot have more than one element with id="calcButtonID" (or any other given id value). id must be unique at all times.
Instead of id, use the class attribute. Here's an example:
// get a NodeList of the buttons
const buttons = document.querySelectorAll('.report-value');
// turn the NodeList into an Array so we can use array methods on the list
const buttonsArray = Array.from(buttons);
// now iterate over the button list...
buttonsArray.forEach(function(button) {
// ... so we can give each button a click listener
button.addEventListener('click', function(event) {
// inside the event listener function, `this` points to the button that was clicked
console.log(this.value);
// alternatively, you can get the clicked button from the event object that is implicitly passed as event.target
console.log(event.target.value);
});
})
<input type=button value=foo class="report-value" />
<input type=button value=bar class="report-value" />
<input type=button value=baz class="report-value" />
An id is a unique identifier for only one html element. If you wnat to find several element, use class. Here is an example.
var buttons = document.getElementsByClassName("calcButton")
for(var i = 0; i<buttons.length; i++){
buttons[i].addEventListener("click", btnPress)
}
function btnPress(ev) {
console.log(ev.target.value);
}
<!-- begin snippet: js hide: false console: true babel: false -->
<button class="calcButton" value="1">1</button>
<button class="calcButton" value="2">2</button>
<button class="calcButton" value="3">3</button>
<button class="calcButton" value="4">4</button>
But as specified, it's better to use the onclick attribute rather than find the element by its classname
Suppose there is Table with variable number of rows of fixed number of columns, and suppose each row has a button too, now I want to select for example a column's value(let's say this selected column is textarea, so I select it's content) when that row's button is clicked.
For example in above image I want that if submit is pressed than all data of 'textarea' of corresponding row should be stored in a variable.
You can use the jQuery closest() function to find an element near the clicked button. Add click handlers to the buttons and then traverse up to find the textarea.
$('.button').on("click",function(){
var thisRowsTA = $(this).closest("textarea");
console.log($(thisRowsTA).val());
});
A simply way is to:
Put an ID pattern to your textareas, like: txt_area_1, txt_area_2, txt_area_3.
Then, on the Click Event of your buttons, make them catch the corresponding textarea in their row. Use the ID patterns to do this.
Post your code for further help.
You will need to ad an event handler for each button. Inside of that you can write something like this.
function eventHandler(e){
var row = this; // start at the button
while(row.nodeName != 'TR' && row.parent){
// go up till we find the row
row = row.parent;
}
var textArea = row.querySelector('textarea');
var value = textArea.value;
// do something with supplied feedback.
}
In order to attach the handlers, you would do something like this.
function attachTableEvents(){
var table = document.querySelector('table'); // or more specific selector if needed
var buttons = table.querySelectorAll('button');
for (var i = buttons.length; i--;){
buttons[i].addEventListener(eventHandler);
}
}
Counting on the DOM structure is really BAD.
I would put an attribute in my controls that holds the line number. Then when clicking an element you can easily query the DOM by element type and the property value to get any elements in this line.
Later if you change to DIVs or change structure your will still run correctly
I've got a dynamic table of items with checkboxes next to each item. When a user selects a checkbox I want to grab the "Name" item from the table and add it to a textbox. See image:
The way I'm trying to accomplish this is by adding a "change" event to every checkbox and populating it's "data-name" element with the name of the text.
<tbody>
#foreach (var item in Model.Items)
{
<tr>
<td><input type="checkbox" name="selectBox" data-name="#item.Name" /></td>
As you can see I'm populating data-name with the item name as a way to get around pulling it directly (which I don't know how to do). Now in javascript/jquery I'm tying an event to every checkbox and attempting to get the data element using the following code:
$('input[name=selectBox]').change(function (item) {
var text = $(item).attr('data-name');
});
When the code runs the event is firing for all checkboxes, but "text" is undefined when I expect it to be the name data.
Looking for an answer to my method of doing this AND/OR a better way involving skipping the data element all together and getting the name value directly. Thanks for looking.
Try this:
var text = $(this).data('name');
The first parameter of your change function is the event, not the element itself. Also, jQuery automatically sets the function scope (this) to the element being changed.
See Documentation
In your case item is event object not DomElement, you can get element through event property currentTarget
$('input[name=selectBox]').change(function (item) {
var text = $(item.currentTarget).attr('data-name');
});
or use this because this refer` on current Element, it is the same as in previous example but shorter
$('input[name=selectBox]').change(function (item) {
var text = $(this).attr('data-name');
});
I'd like to do something that at least for me is complicated.
I have this in a much larger table:
<table><tr>
<td class="editC" id="comments:942" onchange="TimeLine();" onclick="empty('comments:942');" title="Click to edit..."> Second test of new comment behavior
</td></tr></table>
Here is what is going on:
1) class="editC" = I use Editable to edit and write to the DB.
2) id="comments:942" = the id value
3) onchange="TimeLine();" = The timeLine() function gets information from another DB and puts it into a second HTML table on screen. This works.. no worries.
4) onclick="empty('comments:942')" = empty is a function to empty the field but it does not update the DB. I just want a clean input field to enter new data in place of the existing data.
What I'd like to happen is this.
a) If something is typed into this now empty field, all is good, my save.php code will save it to the DB. This works great.
b) But if nothing is typed into the now empty field, I want the old value put back in place without updating the DB. In my head this would be equivalent to first having cut the current value then pasting it back if nothing new had been typed.
It seems to me that jQuery should be able to do this with the input event.
function empty(thisID){
$(thisID).on('input',function(){
$(this).val() // should get current value
});
document.getElementById(thisID).innerHTML = ''; // empty the field
... but now what? How do I determine if a change was made? How do I replace the original value if a change wasn't made?
}
But now what? How do I determine if a change was made? How do I replace the original value if a change wasn't made?
td elements do not have an input event. It is however possible to nest an <input> tag inside a td.
$("td input").on("focusin", function() {
currentValue = $(this).prop("value");
$(this).prop("value", "");
}).on("focusout", function() {
if($(this).prop("value") === "") {
$(this).prop("value", currentValue);
}
});
Here, when the input is clicked, found using the focusin event, the value of the input is stored in a global variable. It needs to be global, because we have to use this variable in the next function. After the variable is stored, the input field is erased, by setting the value attribute to an empty string.
If the user didn't make any changes and leaves the input field, detected with the focusout event, the value attribute will be reset to what it once was.
Current Fiddle
http://jsfiddle.net/a592awoo/1/
One problem is you are passing in 'comments:942' to your empty function.
So when you do $(thisID) it is trying to find an element <comments:942>. To select by an id you need a #.
You could do this:
$('#'+thisID)
Or simply pass in '#comments:942'.
However, that won't work either. Using a : in an id is typically a bad idea, as it has a special meaning in CSS and jQuery selectors, so you may want to use a - instead. If that's not an option, you can escape the :.
Even with the jQuery selector fixed, I'm not sure how you are trying to get user input on a <td> element. You need an <input> element.
I believe you are trying to accomplish something like this:
$(document).ready(function() {
//this will add a click function to all elements with a class of 'editC'
$('.editC').on('click', function() {
//clear the current value
$(this).empty();
//append an input element
$(this).append($('<input type="text" placeholder="Enter new value">'));
//append a button
var btn = $('<button>Submit</button>');
//add click function on submit button to replace old td value with what is in the input
$(btn).on('click', function() {
//get the parent <td> element
var td = $(this).parent();
//get the previous element's value (the value of the <input> element)
var val = $(this).prev().val();
//remove the input element and button from the td
$(td).empty();
//set the text of the <td> to what was entered in the input element
$(td).text(val);
});
$(this).append(btn);
//unbind the click event, so that it does not perform this function when you click in the input element
$(this).unbind('click');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td class='editC' id='comments-1'>Value 1</td>
<td class='editC' id='comments-2'>Value 2</td>
</tr>
</table>
On my aspx page I dynamically create html controls on client side using javascript. For example, after page load you can click button in a browser, by clicking button html input and select elements appear. You may click once again, and this elements (input and select) will added again. So, you can create so many inputs and selects as you want (all this using javascript, no postbacks)
After user created some inputs and selects and entered some information in it, he posted form. I want on server side to find all this dynamically added elements and perform some actions depends on values in this controls.
How can I find dynamically added elements, and what is the best and elegant way to achieve this?
Thanks in advance.
In the Javascript that creates the new elements, increment a counter each time an element is created. Add the value of the counter to the name of the input element so each element has a unique name.
Add the final value of the counter to a hidden form field when the form is posted.
In your server side code, create a loop that starts at zero and continues until you have reached the value of the counter. Within the loop, fetch the posted value of the corresponding form field.
When you add the elements, assign unique IDs to them, and then retrieve their values using Request.Form["UniqueIdHere"] (C#) or Request.Form("UniqueIdHere") (VB.NET).
Create a loop that loops through each input and select object, that grabs the name/id of the current object and its corresponding value. Then add those items to an array and once the loop is completed, pass those values to your aspx file.
You can view an example with this approach at: http://jsfiddle.net/euHeX/. It currently just alerts the values, but you could easily modify it to pass the values as a parameter via ajax to your handler aspx file. The code will add new inputs or select boxes based off of the input provided. This would of course be modified to reflect your current setup.
HTML:
<div id="dynamic"></div>
<input type="button" id="submit-form" value="Submit>>">
JavaScript (using jQuery):
function createInput(type){
for(var i=0; i<5; i++){
if(type==0){
var obj = '<input type="text" id="'+i+'" class="dynamicContent">';
}else if(type==1){
var obj = '<select id="'+i+'" class="dynamicContent"><option>--Select--</option></select>';
}
$("#dynamic").append(obj);
}
}
function getContent(){
var inputArray = [];
$(".dynamicContent").each(function(k,v){
var o = $(this);
var oType;
if(o.is("input")){ oType = "input"; }
if(o.is("select")){ oType = "select"; }
var oID = oType+o.attr("id");
var oValue = o.val();
inputArray.push(oID+'='+oValue);
});
alert(inputArray);
}
$("#submit-form").click(function(){
getContent();
});
// Set type to 0 for input or 1 for select
var type = '1';
createInput(type);
If you're using jQuery you can use .live() to achive this like a peace of cake!
http://api.jquery.com/live/
I don't know if your controls will survive the postback the way you're creating them, but a good technique for accessing dynamically generated controls (assuming that you've figured out how to persist them) is to do something like the following:
Add a panel to your page. Add your dynamically created controls to this panel.
In the OnClick event handler (or other method), do something like the following:
foreach (DropDownList ddl in Panel1.Controls.OfType<DropDownList>())
{
//put code here
}
foreach (TextBox txt in Panel1.Controls.OfType<TextBox>())
{
//put code here
}