jQuery selector when a table is created dynamically - javascript

I have a table (generated at run time) and a dropdown. Before the page is up, the table does not exist. Once the page is up, the table and the dropdown look similar to this fiddle:
$("#aDropDown").val($("WhatToPutHere?").text());
I am trying to do the following: when the user select the Select button, I need the dropdown selected item to match the Type for the row.
Any example would be appreciated.
Thanks
Mike

first, you have multiple button with the same id. They should share a class.
<button class="aButton">Select</button>
next, what you want is the .text() of the prev <td>
$('.aButton').on('click', function() {
var type = $(this).closest('td').prev('td').text();
$("#aDropDown").val(type);
});
JSFIDDLE
as #Mackan pointed out, you might encounter a problem if you're not using a
delegated event, as you're creating the table dynamically. in that case the following code would work better :
$(body).on( 'click', '.aButton' , function() {
var type = $(this).closest('td').prev('td').text();
$("#aDropDown").val(type);
});

$('.aButton').click(function(e) {
var btn = $(e.target);
$("#aDropDown").val(btn.data('category'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<td>item</td>
<td>Type</td>
<td>Action</td>
</thead>
<tr>
<td class="anItem">Apple</td>
<td class="aType">Fruit</td>
<td>
<button class="aButton" data-category="Fruit">Select</button>
</td>
</tr>
<tr>
<td class="anItem">Orange</td>
<td class="aType">Fruit</td>
<td>
<button class="aButton" data-category="Fruit">Select</button>
</td>
</tr>
<tr>
<td class="anItem">collard</td>
<td class="aType">Veggie</td>
<td>
<button class="aButton" data-category="Veggie">Select</button>
</td>
</tr>
</table>
<br/>
<br/>aDropDown:
<select id="aDropDown">
<option value="Fruit">Fruit</option>
<option value="Veggie">Veggie</option>
</select>
Removed id attribute from each button (id should be use for unique elements).
Added aButton class to each button.

As I said above, your code must run on some event. Here's how I'd do it with minimal markup changes (just a class on the buttons):
$('.selectBtn').click(function() {
var myVal = $(this).closest('tr').find('.aType').text();
console.log(myVal);
$("#aDropDown").val(myVal);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<td>item</td>
<td>Type</td>
<td>Action</td>
</thead>
<tr>
<td class="anItem">Apple</td>
<td class="aType">Fruit</td>
<td>
<button id="aButton" class="selectBtn">Select</button>
</td>
</tr>
<tr>
<td class="anItem">Orange</td>
<td class="aType">Fruit</td>
<td>
<button id="aButton" class="selectBtn">Select</button>
</td>
</tr>
<tr>
<td class="anItem">collard</td>
<td class="aType">Veggie</td>
<td>
<button id="aButton" class="selectBtn">Select</button>
</td>
</tr>
</table>
<br/>
<br/>aDropDown:
<select id="aDropDown">
<option value="Fruit">Fruit</option>
<option value="Veggie">Veggie</option>
</select>

Since you said your table is created dynamically, you should use a bind to a persistent element, using a delegated event (like document or body):
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time. By picking an element that is guaranteed to be present at the time the delegated event handler is attached, you can use delegated events to avoid the need to frequently attach and remove event handlers
All of the other answers (time of writing) uses binds that will add the event handlers to the actual buttons. This means that if the button doesn't exist, or gets temporarily removed, the bind will be lost or can't be created to start with.
Using a delegated event:
$(document).on('click', '.aButton', function() {
or..
$('body').on('click', '.aButton', function() {
Also notice that the above binds use a class selector, .aButton, because id's must be unique (and yours were not).
<button class="aButton">Select</button>
Full example at jsFiddle:
$(document).on('click', '.aButton', function() {
$("#aDropDown").val($(this).parent().prev('td').text());
});
Edit:
If the table structure is in danger of changing (adding more td's or tr's), the below script will be better at finding the correct td (by class .aType):
$(document).on('click', '.aButton', function() {
$("#aDropDown").val($(this).closest('tr').find('.aType').text());
});

Related

How do I highlight a table row when checkbox is selected? Angular 7

So let's skip the the table headers to my table body. I have a populated table:
HTML:
<tbody>
<tr *ngFor="let e of emails; let i = index">
<td <input type="checkbox" id="email-checkbox" (change)="addToSelectedList($event, e)"></input></td>
<td id="subject-{{i}}">{{e.sender}}</td>
<td id="subject-{{i}}">{{e.subject}}</td>
<td id="subject-{{i}}">{{e.date}}</td>
</tbody>
I want the table whole row to display a CSS class when the user checks the checkbox. And then the color should go back to normal when the user deselects. Just UI stuff to show the user that an email has been selected. I currently have an empty CSS and .ts file.
The way you have done it here is more involved because presumably you have some logic inside addToSelectedList event that will add/remove the email depending on the checked state. The easiest way is to add a property on the email entity isSelected, and do this:
<input ... [checked]="e.isSelected" >
On your tr add the ngclass binding as suggested by others as follows:
<tr [ngClass]="{ 'selectedcssclass' : e.isSelected }"...
Other observation in your code there isn't a closing tr that should be wrapping around all the tds.
Not an Angular expert, but you can achieve just that using a JS onchange event bound to your checkbox:
$(".box").on("change", function() {
$(this).parents("tr").toggleClass("highlight");
});
.highlight {
background-color: #ffff00;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<td>Label 1</td>
<td><input type="checkbox" class="box"/></td>
</tr>
<tr>
<td>Label 2</td>
<td><input type="checkbox" class="box"/></td>
</tr>
</table>

How to click button under an element that have click event as well

I have a table in html. And I am having click event on each row of that table. I have 4 items on each row and the last item in dropdown. I want to prevent row click when I click on drop down item and vice versa.
<tr onclick="doSomething()">
<td>text</td>
<td>text</td>
<td>text</td>
<td onclick="doSomethingElse()">
<!-- drop down elements -->
</td>
</tr>
I know something about preventDefault(); but don't know how to use that here.
preventDefault is not needed here. You can easily achieve it using stopPropogation()
<tr onclick="doSomething()">
<td>text</td>
<td>text</td>
<td>text</td>
<td onclick="doSomethingElse(); event.stopPropagation(); ">
<!-- drop down elements -->
</td>
</tr>
Hope it helps.
You can pass the event as one of the arguments in the doSomething function, then check whether the event target is the father element. See this example
function doSomething(e) {
if(e.target == document.getElementById('father')) {
//do stuff
}
};
Then in the HTML you just need to add the event argument to the javascript function.
<tr id="father" onclick="doSomething(event)">
<td>text</td>
<td>text</td>
<td>text</td>
<td id="son" onclick="doSomethingElse(event)">
<!-- drop down elements -->
</td>
</tr>
You need to look for e.target or Event Target function
function somefunction(e) {
var target = e.target || e.srcElement;
target.style.display= 'block';
}
Another stuff you might need
var target = event.target;
var parent = target.parentElement;//parent of "target"

Why I can't have a click listener on a checkbox, when I have a listener on the <tr>

I have a really newbie question here, but I can't understand what is going on.
I have this table:
<table class="activeTrackersTable" id="allTrackersTable" data-page-navigation=".pagination">
<thead>
<tr>
<th>ID</th>
<th>1</th>
<th>2</th>
<th>3</th>
<th class="reactivateTH">Reactivate</th>
</tr>
</thead>
<tbody data-bind="foreach: ObjArray">
<tr data-bind="click: loadT">
<td><span data-bind="text: id"></span>
</td>
<td><span data-bind="text: tName"></span>
</td>
<td><span data-bind="text: pName"></span>
</td>
<td><span data-bind="text: creator"></span>
</td>
<td class="reactivateTD">
<input type="checkbox" name="reactivate" data-bind="event:{change: reactivate}">
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5">
<div class="pagination"></div>
</td>
</tr>
</tfoot>
</table>
Now as you see I have placed a listener on the tr and it works just perfectly, But when I click on the checkbox I'm getting the loadT function executed and this is the fnction listening to the tr click. Why the reactivate function is not running? It is supposed to get executed once I have clicked on the checkbox.
I know that I'm missing something extremely small here, but I really can't spot my mistake at this momment.
P.S Here are the 2 functions:
loadT = function() {
console.log('test1');
};
reactivate = function(){
console.log('inside');
};
When I click on the checkbox it prints just: 'test1', I can't understand why the listener is not working. I have used it hundreds of times in previous projects, without any issues. My guess is that something is messed up in teh view model, but again, there are 2 seperate functions and 2 seperate listeners.
Your example works with the click event if you add clickBubble: false to your markup to prevent the event from bubbling:
<input type="checkbox" name="reactivate"
data-bind="event:{click: reactivate}, clickBubble: false" />
Working fiddle
Note that you will need to return true; to allow the default action (the box actually getting checked).
reactivate: function () {
console.log('checkbox');
return true;
}
See doc
Note: I am not sure why, but I can't make it work with the change event (if someone can explain in the comments) Non working fiddle
Since its a checkbox I guess you need to react on if its checked or unchecked?
The KO way of doing that would be
ViewModel = function() {
this.checked = ko.observable(false);
this.checked.subscribe(this.onChecked, this);
};
ViewModel.prototype = {
onChecked: function(value) {
console.log(value);
}
};
<input data-bind="checked: checked" type="checkbox" />
http://jsfiddle.net/EG5HU/
If you do not want to act on checkstate but rather just format something you can use a computed
http://jsfiddle.net/EG5HU/1/

jQuery replace and add new element

I have the following HTML
<tbody class="t_bdy">
<tr class="Quotation_List_td">
<td class="item"><a class="button2 crm_insert" href="#">Insert</a><a class="button2 crm_delta" href="#">Delete</a></td>
<td class="Quotation_List_ItemTD description"> </td>
<td class="quantitiy"> </td>
<td class="unit_price"> </td>
<td class="discount"> </td>
<td class="total"> </td>
</tr>
<tr class="Quotation_List_td">
<td class="item"><a class="button2 crm_insert" href="#">Insert</a><a class="button2 crm_delta" href="#">Delete</a></td>
<td class="Quotation_List_ItemTD description"> </td>
<td class="quantitiy"> </td>
<td class="unit_price"> </td>
<td class="discount"> </td>
<td class="total"> </td>
</tr>
</tbody>
I need to insert new <tr> when I click on button with .crm_insert class.
When .crm_insertis clicked, it need to insert a new row at the current location. All
other rows will move down. For example, if insert against row 3 is clicked then
row 3 will be new row inserted and current row 3 etc will move down to become
row 4 etc.
How can I achieve this ?
All answers are good, but I can only accept one : Thanks all
I'd try something like this using closest() and before()
$('a.crm_insert')
.click(function()
{$(this).closest('tr.Quotation_List_td').before(htmlcodeofyounewTRhere);}
)
Hope this will help
Assuming:
Your new row is in the same structure as your current row
You want the new row to also have the 'Insert' functionality
You want a click event handler which does something to this effect:
$('.crm_insert', '#table').on('click', function() {
var currentRow = $(this).closest('tr');
currentRow.clone(true).insertBefore(currentRow);
});
Where #table is the id of your table.
Here's a simple example
If you are inserting something completely different, then you do not need to use on() or clone(), and the code becomes simpler:
$('.crm_insert').click(function() {
var currentRow = $(this).closest('tr');
$('<tr />').insertBefore(currentRow);
});
Where <tr /> would be whatever you are trying to insert.
This might work for you. It'll find the parent tr of the button you just clicked, clone it (including the onClick functionality of the button) and insert that before the parent tr. This will result in a new row containing the same information as the target row though. Depending on what results you want to show in the new row, you might want to alter the code to clear out any copied values too.
$(".crm_insert").live("click", function(){
var tr = $(this).parents("tr.Quotation_List_td");
tr.clone().insertBefore(tr);
});
You can try this
$('.crm_insert').live('click', function(){
var self = $(this);
self.parents('tr.Quotation_List_td').before('add your row here');
});
The latest versions of jquery employ on instead of live.

Quickest way to find an element with jQuery

Given the following html:
<tr>
<td>Content</td>
<td>Content</td>
<td>Content</td>
<td><img id="imgProductPurchased" runat="server" visible="true" alt="Product Purchased" title="Product Purchased" src="/sitecore/shell/Themes/Standard/Applications/16x16/checkbox.png" /></td>
<td>
<asp:PlaceHolder ID="plhPurchased" runat="server">
<span class="roundButton roundButtonLarge"><a id="hypPurchased" class="registryPurchased" href="#" title="Mark product as purchased" runat="server"><span>
<em class="registryPurchased"></em>Purchased</span></a> <span class="buttonEndLarge">
</span></span>
</asp:PlaceHolder>
</td>
</tr>
<tr>
Repeats above
</tr>
I have a click event on "hypPurchased". When that event fires, I need to access the plhPurchased element, and "imgProductPurchased" elements of THAT row.
EDIT:
I should have stated that this is being built with ASP.NET, and as such, the id's are all unique.
If the click event is on the particular row and the element is a child of that row, you can use context to get the result.
$(".myRow").click(function() {
var somethingFromMyRow = $(".myChildClassName", this).text();
alert(somethingFromMyRow);
});
Please note, you shouldn't be duplicating the same ID anywhere on your page, so the example I have supplied uses a class name instead - so imagine you have HTML like this for your example.
<tr class="myRow">
<td><span class="myChildClassName">Some Text In Row 1</span></td>
<td>More Stuff</td>
</tr>
<tr class="myRow">
<td><span class="myChildClassName">Some Text In Row 2</span></td>
<td>More Stuff</td>
</tr>
<tr class="myRow">
<td><span class="myChildClassName">Some Text In Row 3</span></td>
<td>More Stuff</td>
</tr>
id's can't be duplicated in HTML,
Anyway, what you need to do is get to a parent element (go up in the hierarchy until you get the parent element that encompasses the "current" row), then you run the query against it:
jQuery( your_query_string, parent )
Where parent is something you can get using:
parent = query.parent()
For instance:
function click_handler(element)
{
parent = jQuery(element).parent()
name = jQuery(".name", parent)
// do stuff
}
name = jQuery(".name", parent) will get all elements with class name under the parent element.
has Hasen said, you cant duplicate id's in html.
so, apply a class to "plhPurchased" and then:
at the hypPurchased you put onclick="yourFuntion(this)"
function yourFuntion(elem)
{
var tr=$(elem).closest('tr');
var _imgProductPurchased = tr.find('img');
// if you have more then a img per row, you should apply a class to the image to and get it by:
// tr.find('.imgClass');
var _plhPurchased=tr.find('.thatClassYouApplyed');
}

Categories