How to create jQuery Datatable Drill-down rows? - javascript

In my MVC project, I am trying to use a single Datatable and collapse the rows for detail data as shown on Creating an expandable master-details table (jQuery DataTables and ASP.NET MVC integration - Part IV). On the other hand, I am looking for a similar examples of jQuery Datatable master-detail relations for ASP.NET MVC, but unfortunately I have not another suitable sample or tutorial from at least 50 pages on the web. Is there a similar examples like that? Thanks in advance...

I did similar work for one of the projects. I had one collapse/expand button that works for the whole table and each row has its one collapse expand icon. here is my code.
Note: I have renamed the variables to hide my data so the code might not work as it is.
function populateInstanceTable(tableData){
// Use to determine whether the child rows for all parents should be shown or hidden.
var SHOW_ALL_CHILDREN_FLAG = false;
var CHILD_DISPLAY_STATE_OVERRIDE = false;
var TABLE = $('#table_instance').DataTable(
{
'aaData': tableData,
'bProcessing': true,
'aoColumns': [
{
'sTitle': 'Column1',
'mData' : 'col1Data'
},
{
'sTitle': 'Column2',
'mData' : 'col2Data'
},
{
'sTitle': 'Column3',
'mData': 'col3Data'
},
{
'class': 'show-details',
'orderable': false,
'data': null,
'defaultContent': ''
}
]
}
);
function getDetailContent(details) {
return '<table cellpadding="5" cellspacing="0" border="0" style="padding-left:50px;">' +
'<tr>' +
'<td style="border:0px;">More Details:</td>'+
'<td style="text-align:left;max-width:100%;border:0px;">' + details + '</td>' +
'</tr>' +
'</table>';
}
//This function shows and hides multiple child rows with details, for following conditions
// when user clicks '+' or '-' icon
// When user uses search
// when user changes the number of entries per page
// when user navigates through the table
// #remark: With exception of expand all and collapse all events, the display state is retained for child rows
//that have been previously visited. Visited implies the parent row's show or hide details icon was individually clicked.
function collapseOrExpandRows() {
var numberOfVisibleParentRows = $('#table_instance tbody tr td.show-details').length;
for (var i = 0; i < numberOfVisibleParentRows; i++) {
var parentJQRow = $('.show-details').parents('tr').eq(i);
var parentDTRow = TABLE.row(parentJQRow);
// visited_child helps us retain the state of the child row display while
// searching, navigating, sorting or changing number of entries
// We always change the state of child if collapse all(- icon) or expand all(+ icon) is clicked.
if (parentJQRow.hasClass('visited_child') === false || CHILD_DISPLAY_STATE_OVERRIDE === true) {
if (SHOW_ALL_CHILDREN_FLAG === true) {
// We are populating a child row with a table because the parent datatable does not support colspan property.
parentDTRow.child(getDetailContent(parentDTRow.data().details)).show();
parentJQRow.addClass('shown');
}
else {
parentDTRow.child.hide();
parentJQRow.removeClass('shown');
}
}
}
}
//To display details, this event handler shows or hides a single child row
//when the show-details cell is clicked on the parent row
$('#table_instance tbody').on('click', 'td.show-details', function() {
var parentJQRow = $(this).parents('tr');
var parentDTRow = TABLE.row(parentJQRow);
//visited_child helps us retain the state of the child row display while
// searching, navigating, sorting or changing number of entries
parentJQRow.addClass('visited_child');
if (parentDTRow.child.isShown()) {
parentDTRow.child.hide();
parentJQRow.removeClass('shown');
}
else {
parentDTRow.child(getDetailContent(parentDTRow.data().details)).show();
parentJQRow.addClass('shown');
}
CHILD_DISPLAY_STATE_OVERRIDE = false;
});
// This event handler retains the state of the child row display
// when navigating through the table.
$('.dataTables_paginate').on('click', function() {
collapseOrExpandRows();
});
// This event handler hides child row for all visible parents.
$('.collapseall').on('click', function() {
CHILD_DISPLAY_STATE_OVERRIDE = true;
SHOW_ALL_CHILDREN_FLAG = false;
collapseOrExpandRows();
});
// This event handler shows child row of all visible parents.
$('.expandall').on('click', function() {
CHILD_DISPLAY_STATE_OVERRIDE = true;
SHOW_ALL_CHILDREN_FLAG = true;
collapseOrExpandRows();
});
// This event handler retains the state of the child row display
// when the user selects the number of entries to display in the table
$('div.dataTables_length select').on('change', function() {
collapseOrExpandRows();
});
// This event handler retains the state of the child row display
// when the user clicks on header to sort
$('thead > tr > th', '#table_instance').click(function() {
if ($(this).hasClass('show-details') === false) {
collapseOrExpandRows();
}
});
// This event handler retains the state of the child row display
// when the user searches
$('div.dataTables_filter input').keyup(function() {
collapseOrExpandRows();
});
}
I have attached the screenshot for your help.

There is a good example on Datatables Blog having also a wonderful sliding property. There is unfortunately not so much example on the web regarding to this issue, but I hope this example is useful for you.

I know this is an old thread. But I could not find any good examples since then. I created a working example which is fully scalable using jQuery (3.5.0) and Datatables (1.10.19). Table, columns, rows and sub tables are created on the fly based on data structure.
You can find the demo and code here - https://banglaonline.org/dashboard/temp/dt.html. The js code is in https://banglaonline.org/dashboard/temp/dt.js.
function dataStructure() - creates the first table
function dataStructure(){
$("#content_structure").html("<div id='content_structure_table' style='width:80%'></div>");
var groupBy=[fieldOrder[0].field];//level 1 order
var dtTextColumnIndex=[];
var dtNumColumnIndex=[];
var colCount=1;
var valuefunction=null;//dataCreateValueFunctions();
tblFormatParam = formatTblDataStructure('tblDataStructure',0,"1=1");
html = tblFormatParam[0];
tableDef = tblFormatParam[1];
$("#content_structure_table").html(html);
var table = $('#tblDataStructure').DataTable(tableDef);
//drill down event
$('#tblDataStructure tbody').on('click', 'td.details-control', function(){
e=$(this);
drillTblDataStructure(e,table,valuefunction);
});
$('#tblDataStructure' ).bind( 'xhr.dt', function () {
var json = table.ajax.json();
$('#tblDataStructure').unbind( 'xhr.dt');
//structureChart(json.data);
});
}
function drillTblDataStructure - controls the expansion and contraction of nested tables
function drillTblDataStructure(td,table,valuefunction) {
//console.log("td clicked -"+td.attr("datavalue"));
var tr = td.closest('tr');
var row = table.row( tr );
currentFieldOrder = parseInt(td.attr("fieldorder"));
//close all other open rows
tdDrillControls = document.querySelectorAll("td.details-control");
for (var i=0;i<tdDrillControls.length;i++){
tdi= $(tdDrillControls[i]);
tri = tdi.closest("tr");
r = table.row( tri);
if (r.child.isShown() && (tdi.attr("datavalue") != td.attr("datavalue"))) {//second condition is importatnt, otherwise the row will be keep on showing
r.child.hide();
tri.removeClass('shown');
tdi.html('<span class="ui-icon ui-icon-plus"></span>')
}
}
if (row.child.isShown()) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
td.html('<span class="ui-icon ui-icon-plus"></span>')
}
else {
td.html('<span class="ui-icon ui-icon-minus"></span>')
childFieldOrder = currentFieldOrder +1;
var whereClause = td.attr("whereClause")+" and "+td.attr("datacolumn")+" = '"+td.attr("datavalue")+"'";
var childTableID = childFieldOrder*10+iTableCounter;
tblFormatParam = formatTblDataStructure('tblDataStructure_' + childTableID,childFieldOrder,whereClause);
html = tblFormatParam[0];
tableDef = tblFormatParam[1];
// Open this row
row.child( html ).show();
tr.addClass('shown');
var oInnerTable = $('#tblDataStructure_' + childTableID).DataTable(tableDef);
$('#tblDataStructure_' + childTableID).bind( 'xhr.dt', function () {//table data is loaded via ajax
var json = oInnerTable.ajax.json();
$('#tblDataStructure_' + childTableID).unbind( 'xhr.dt');
});
$('#tblDataStructure_' + childTableID +' tbody').on('click', 'td.details-control', function(){
e=$(this);
drillTblDataStructure(e,oInnerTable,valuefunction);
});
iTableCounter++;
}
}
function formatTblDataStructure - used by the above two functions to create table structure and definition for Datatables
function formatTblDataStructure ( table_id, groupOrder, whereClause) {
var dtTextColumnIndex=[];
var dtNumColumnIndex=[];
var colCount=1;
if(groupOrder<fieldOrder.length-1) //it is not the last item in the order
var tdColumns=[
{ className: 'details-control',
orderable: false,
data: null,
defaultContent: '<span class="ui-icon ui-icon-plus style="cursor:pointer;"></span>'
}
];
else
var tdColumns=[
{ className: '',
orderable: false,
data: null,
defaultContent: ''
}
];
tdColumns.push({data:fieldOrder[groupOrder].field});
html="<table id='"+table_id+"' ><thead><tr><th></th>";
thtml="<tr><td></td>";
html+="<th>"+fieldOrder[groupOrder]["dataField"]+"</th>";
thtml+="<td></td>"
dtTextColumnIndex.push(colCount);
colCount++;
var valuefunction=[];
for(f in valueFields){//getting field names from json column names
html+="<th>"+valueFields[f]["dataField"]+"</th>";
thtml+="<td></td>"
dtNumColumnIndex.push(colCount);
colCount++;
txt = valueFields[f].groupFunction+"("+valueFields[f].field+") as `"+valueFields[f].field+"`";
valuefunction.push(txt);
tdColumns.push({data:valueFields[f].field});
}
html+="</tr></thead><tbody>"+thtml+"</tr></tbody></table>";
groupBy=[fieldOrder[groupOrder].field];
var tableDef={
"ajax":{
url: src,
data:{
request:'dataStructure'
,dbid:sessionID
,group:JSON.stringify(groupBy)
,where:whereClause
,value:JSON.stringify(valuefunction)
,dt:"assoc"
}
},
createdRow: function( row, data, dataIndex ) {
$( row ).find('td:eq(0)').attr(
{
'fieldOrder': groupOrder,
'datavalue': data[fieldOrder[groupOrder].field],
'datacolumn': fieldOrder[groupOrder].field,
'whereClause': whereClause
}
);
},
columns: tdColumns,
columnDefs: [
{
targets: dtTextColumnIndex,
className: 'dt-body-left dt-head-left'
},
{
targets: dtNumColumnIndex,
className: 'dt-body-right dt-head-right'
//,"render": function ( data, type, row, meta ) {
// return infGroup.format(data);
//}
}
]
}
return [html,tableDef];
}
In the example, data is retrieved as json via ajax from a php backend. Example json response:
{
"data": [
{ "dash_uploaded_data_text1": "Dept 1", "dash_uploaded_data_numeric1": "3", "dash_uploaded_data_numeric2": "11" },
{ "dash_uploaded_data_text1": "Dept 4", "dash_uploaded_data_numeric1": "4", "dash_uploaded_data_numeric2": "8" }
]
}

Related

jQuery Loop through selected rows of html element - Datatables

I am using JQUERY datatables to enhance my standard HTML table on the web page. Currently I have checkbox that users can select up to 5 items on the table. I have the below code which allows users to select on any row which then highlights a leaflet JS map (this bit works completely fine).
However, what I am trying to do is not allow users to click on every row but only the 5 selected rows. The issue now is table.rows.length is 2000 rather than 5 as I need to somehow change this to only look for the selected rows.
The below code currently works for every row in the table labelled ID: tabledt.
How can I change my code below to only allow this functionality on the 5 selected rows rather than every row they click on?
A class 'selected' gets added to the attribute which gets selected.
var prevHighlightMarker = undefined;
var table = document.getElementById("tabledt");
if (table) {
for (var i = 0; i < table.rows.length; i++) {
table.rows[i].onclick = function () {
highlightMarker(prevHighlightMarker, false);
tableText(this);
highlightMarker(cMarkers[$(this).data('id')], true);
};
}
}
The below code is how the data table gets defined and how I limit to only 5 rows:
var table = $('#tabledt').DataTable({
columnDefs: [{
orderable: false,
className: 'select-checkbox',
targets: [0]
}],
select: {
style: 'os',
selector: 'td:first-child'
},
order: [[1, 'asc']]
});
table.on('select', function (e, dt, type, ix) {
var selected = dt.rows({ selected: true });
if (selected.count() > 5) {
dt.rows(ix).deselect();
}
//var rowData = dt.rows({ selected: true }).data().toArray();
});
You can do something like this to check if the item contains the class:
var table = document.getElementById("tabledt");
if (table) {
for (var i = 0; i < table.rows.length; i++) {
table.rows[i].onclick = function () {
if (this.classList.contains('selected')) {
highlightMarker(prevHighlightMarker, false);
tableText(this);
highlightMarker(cMarkers[$(this).data('id')], true);
}
};
}
}

Why Jquery Datatable initComplete/onInit events are not working?

I am using Jquery Datatable in my code. I am loading the data via an ajax request. For each row created in my table there is one button called delete. The on-click event of this button reads an attribute called "r_id" and then applies a soft-deletion in my database. My code is like the following:
$(document).ready(function () {
var parity = 3;
var tr = "";
$.ajax({
url: "https://" + window.myLocalVar + "/api/rewards/findAllRewardsByStatusID/" + parity,
type: "GET",
dataType: 'json',
contentType: 'application/json',
success: function (rewards) {
if (rewards.length > 0) {
for (var i = 0; i < rewards.length; i++) {
var reward = rewards[i].Reward;
var reward_price = "$ " + rewards[i].Price;
var r_id = rewards[i].RewardID;
tr += '<tr r_id="' + r_id + '">\
<td>' + reward + '</td>\
<td>' + reward_price + '</td>\
<td>\
<button r_id="' + r_id + '" type="button" class="btn btn-danger delete">delete</button>\
</td>\
</tr>';
if (i % 10 == 0 || i == rewards.length - 1) {
$("#submitted_rewards > tbody").append(tr);
tr = "";
}
}
}
$('#submitted_rewards').on('init.dt', function () {
// click event for each tr
$("#submitted_rewards tbody tr td:not(:last-child)").on("click", function () {
var r_id = $(this).parent().attr("r_id");
window.location.href = "./reward-info.aspx?id=" + r_id;
});
$(".delete").click(function () {
var r = $(this).attr("r_id");
$("tr[r_id=" + r + "]").fadeOut();
});
}).DataTable({
"scrollX": true,
stateSave: true
});
},
error: function (err) {
if (err) {
console.log(err);
}
}
});
});
This code loads the data in my Jquery Datatable called "submitted_rewards" correctly. The page size of the table is set to '10' as a default (10 rows per page). Now, I tried to go to the second page and click on the row to redirect to another page OR if I tried to click on the delete button to delete a row and it did not work! Those events work only for the page that a user lands on the first time. I am saving the state of the table that mean if I switched from page 1 to page 2 then refreshed that page. The events of each row in page 2 ONLY will work.
I tried to use the event initComplete but it did not work. Any idea how to solve this problem.
Thanks!
If you attach handlers to DOM elements and those DOM elements are destroyed your handlers will be of no effect anymore and the related code will be garbage collected at some point.
When you change pages by doing window.location.href = ..., you are effectively replacing your DOM elements (and script) with a new set from the page that is replacing it. Consequently, your handlers will no longer apply.
You can address this in a couple ways.
1) You will need to add script to each page you are loading and have it execute when the DOM is ready, applying handlers to the DOM elements on that page.
2) Do another ajax request to get new data and replace certain elements on your page. Use jQuery's .delegate() to attach handlers automatically to certain elements even as you add them later.
The reason why it is not working because I am appending every 10 rows to the table.. I appended all the rows of the table at one shot and then have the clicking events then it is going to work.
If I want to keep loading every 10 rows. then I have to move the events inside the if statement like the following:
if (i % 10 == 0 || i == rewards.length - 1) {
$("#submitted_rewards > tbody").append(tr);
tr = "";
$("#submitted_rewards tbody tr td:not(:last-child)").on("click", function () {
var r_id = $(this).parent().attr("r_id");
window.location.href = "./reward-info.aspx?id=" + r_id;
});
$(".delete").click(function () {
var r = $(this).attr("r_id");
$("tr[r_id=" + r + "]").fadeOut();
});
}

jquery Datatables checkbox get all checked rows

I have a datatable in which in which I'm trying to get all the checked rows. This table has row grouping and uses a checkbox plugin from gyrocode. I've tried the code listed on the api, but I had no luck. I only get the first record returned, regardless of what is selected. The code I used for the is shown below:
var tbl;
$(document).ready(function (){
tbl = $('#example').DataTable({
columnDefs: [{
targets: 0,
data: 2,
'checkboxes': {
'selectRow': true
}
},
{ "visible": false, "targets": 1 }],
select: {
style: 'multi'
},
order: [[1, 'asc']],
iDisplayLength: 10,
drawCallback: function () {
var api = this.api();
var rows = api.rows({ page: 'current' }).nodes();
var last = null;
api.column(1, { page: 'current' }).data().each(function (group, i) {
if (last !== group) {
$(rows).eq(i).before(
'<tr class="group"><td colspan="6">' + group + '</td></tr>'
);
last = group;
}
});
}
});
});
function getSelected(){
alert(tbl.columns().checkboxes.selected().length);
}
I have the code in my jfiddle here. I'm not sure if their is interence between the checkbox and the row grouping? Please let me know where I am going wrong.
Note: The checkbox is based on the plugin by gyrocode The datatables is version 1.10.12
I'm too late to answer this question. But my answer can help others in the community.
//datatable has to be initialized to a variable
var myTable = $('#calltable').dataTable();
//checkboxes should have a general class to traverse
var rowcollection = myTable.$(".call-checkbox:checked", {"page": "all"});
//Now loop through all the selected checkboxes to perform desired actions
rowcollection.each(function(index,elem){
//You have access to the current iterating row
var checkbox_value = $(elem).val();
//Do something with 'checkbox_value'
});
I hope that helps.
I did a quick check and Eric Guan is correct. I'll just post a code snippet:
function getSelected() {
var selectedIds = tbl.columns().checkboxes.selected()[0];
console.log(selectedIds)
selectedIds.forEach(function(selectedId) {
alert(selectedId);
});
}
See: https://jsfiddle.net/nwmmbLso/3/
I just noticed you have duplicatie Student Id's which might also cause unexpected behavior from the library you are using. The code provided above should work if the Student Id's are unique.
Working and tested.
var id = "";
var oTable = $(".table").dataTable();
$(".check_quality:checked", oTable.fnGetNodes()).each(function() {
if (id != "") {
id = id + "," + $(this).data('id');
} else {
id = $(this).data('id');
}
});
Simple answer - use either table.rows( '.selected' ) or table.rows( {selected:true} )
var count = $('#datatable').DataTable().rows( '.selected' ).count();
var checked_rows = $('#datatable').DataTable().rows( '.selected' ).data();
for(var i=0; i<checked_rows.length; i++)
{
console.log( checked_rows[i] );
}
Document Link: https://datatables.net/reference/api/count()
for people still looking today for the answer
var rowcollection = table.columns(0).context[0].checkboxes.s.data;

Binding between UI and JavaScript: Different scopes?

I have a web app. In this app, I have a page of dynamically built editable items. I have the editing portion working just fine. My problem is, I'm unable to bind changes from the input element back to my data structure. I have a fiddle here. My relevant code looks like this:
var options = [];
$(document).ready(function() {
$(function() {
$.material.init();
});
// Initialize the options
options.push({ id:1, html:'' });
options.push({ id:2, html:'' });
options.push({ id:3, html:'' });
var optionEditors = $('.option-editor');
for (var i=0; i<optionEditors.length; i++) {
$(optionEditors[i]).summernote({
airMode: true,
popover: {
air: [
['font', ['bold', 'underline', 'clear']]
]
},
callbacks: {
onInit: function() {
var editor = $('.note-editor');
editor.addClass('form-control');
editor.bind('DOMSubtreeModified', onUpdate);
$(this).summernote('code', ' ');
var editable = editor.find('.note-editable');
editable.attr('data-id', $(this).attr('data-id'));
editable.attr('data-index', $(this).attr('data-index'));
}
}
});
}
});
function onUpdate(option) {
try {
var id = choice.target.getAttribute('data-id');
var index = choice.target.getAttribute('data-index');
alert(id + ' : ' + index)
options[index].html = choice.target.innerHTML;
} catch (ex) {
}
}
It's almost like the options variable is in a different scope. It's so weird. Basically, when the text in any of the input fields gets updated the options content should get updated as well. Such that when I click the Print button, I can see the contents of the options variable in the console window. I'm not sure what I'm doing wrong though.
var id = choice.target.getAttribute('data-id'); on this line choice is undefined. Maybe that's the problem?

Highlight and sorting issue when populating table dynamically

I'm trying to make my table have a checkbox column for each row, and also the rows to highlight on hover. It works properly when the data is static declared on html files, however when retrieving the data from server (I'm using $.getJSON) the sorting becomes a mess and the highlight stops working.
Also it shows this message for each row in the table.
DataTables warning: Requested unknown parametr '5' from the data
source for row 0
Here is my code:
$(function ()
{
var oTable;
var tRow;
var checkboxIdsArray = new Array();
var allChecked = false;
// To generate the checkbox for each row
var nCloneTh = document.createElement('th');
var nCloneTd = document.createElement('td');
nCloneTd.innerHTML = '<input type="checkbox" id="op_checkbox" />';
nCloneTd.className = "center";
// Deal with the checbox selection
$('#op_checkbox').live('click', function()
{
var operatorId = $(this).parents('tr').attr('id');
});
$('#example thead tr').each(function ()
{
this.insertBefore(nCloneTh, this.childNodes[0]); // Add the header before the first header
});
// Instantiate the DataTable
oTable = $('#example').dataTable({"aaSorting": [[ 0, "asc" ]]});
$.getJSON('../../controller/UserController.php/getUsers',
function(data)
{
$.each(data, function(i, item)
{
oTable.fnAddData(
[
item.idUser,
item.nameUser,
item.telephoneUser,
item.cnpjUser,
item.inscEstUser
]
);
});
$('#example tbody tr').each(function ()
{
this.insertBefore(nCloneTd.cloneNode(true), this.childNodes[0]); // Add the checkbox to the td's
});
});
// Deals with the highlight of the rows
$('#example tbody tr').hover(function()
{
tRow = this;
$(this).children().addClass('highlighted');
},
function()
{
var nTrs = oTable.fnGetNodes();
$(tRow).children().removeClass('highlighted');
}
);
// Deals with the export options
var oTableTools = new TableTools( oTable,
{
"aButtons":
[
{
"sExtends": "div",
"sButtonText": "Hello world"
}
]
});
$('#demo').before( oTableTools.dom.container );
// Deals with the check all button click
$('#checkall_link').live('click', function()
{
var i = 0;
if(!allChecked)
{
$(oTable.fnGetNodes()).each(function()
{
allChecked = true;
$('#checkall_link').text('Uncheck all');
this.childNodes[0].childNodes[0].checked = true; // Set all checkbox to checked
checkboxIdsArray[i] = this.childNodes[0].childNodes[0].id; // Store the current checkbox id the checkboxIds array
i++;
});
}
else
{
$(oTable.fnGetNodes()).each(function()
{
allChecked = false;
$('#checkall_link').text('Check all');
this.childNodes[0].childNodes[0].checked = false; // Set all checkbox to checked
checkboxIdsArray = [];
console.log(checkboxIdsArray);
});
}
});
$('#manage_del').click(function()
{
if($(this).attr('class') == 'disabled')
{
alert("disabled");
}
else
{
alert("enabled");
}
});
$('#manage_new').click(function()
{
if($(this).attr('class') == 'disabled')
{
alert("disabled");
}
else
{
alert("enabled");
}
});
});
Here is how my table looks like. http://imgur.com/gpiu8
As you can see in the arrow in the right side, it creates another column (maybe because the checkbox is being added), also the left arrows you can see that the 2nd column is highlighted, but the checked header is the 1st (with checkboxes). And when I hover the rows, it doesn't get highlighted.
Any help will be appreciated. Thanks.
UPDATE
Now using delegate(), but it doesn't work yet.
// Deals with the highlight of the rows
$('#example tbody').delegate('tr', 'hover', function()
{
tRow = this;
$(this).children().addClass('highlighted');
},
function()
{
var nTrs = oTable.fnGetNodes();
$(tRow).children().removeClass('highlighted');
});
I would use delegate personally (mostly because I never did get my hover example working for you with dynamic content)
Here is some example code to show you how to use delegate:
Sample setup for a thumbnail list:
<ul>
<li>
<img src="http://www.dummyimage.com/64x64/000/fff" />
<p>some title text</p>
</li>
</ul>​
// attach the handler via delegate()
$(document).delegate("li", "hover", function() { // this works because the delegate function looks for all li's that are children to the document.
$(this).children('p').fadeToggle("fast");
});
// after you've attached the handler create some elements.
setTimeout(function() {
var list = $('ul'),
node = list.children('li'),
i = 25;
while (i) {
list.append(node.clone());
i--;
}
}, 1000);​
Live Demo

Categories