I am relatively new to AngularJs and I am having trouble implementing a Fixed Header on my table. I am using a modified version of a library I am utilizing on other parts of my application with no problem however on this specific table it is not working. I even tried having two separate tables one for the head and one for the body but since the can be dynamic with Angular and a Maximize, this does not work.
js code:
<div id="test"
class="panel-body" style="height: 222px; overflow-y: scroll;">
<table id="data-sources-table" class="table table-striped drag-drop" fixed-header-custom >
<thead>
<tr>
<th style="position: relative">TestProperty</th>
<th style="position: relative" ng-repeat="ds in model.dataSamples"
style="line-height: 16px; vertical-align: top;">
<span tooltip="{{ds.dsName}}"
tooltip-placement="top">
{{ds.dsName.slice(0, 20)}}
</span>
<button class="btn-graphic-only btn-remove" type="button"
ng-show="ds"
ng-model="singleModel"
tooltip="Test data sample"
tooltip-placement="left"
ng-click="removeDs($index)">
</button>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="(property, linkedDs) in model.properties">
<td ng-class="{'narrow-column': $first}"
ng-style="highlightIfInDetails(model.properties[property])">
<span>
<ul style="margin-bottom: 0px; list-style-type: none; padding: 0px;">
<li dnd-draggable="ds.dsProfile[property]"
dnd-effect-allowed="copy"
dnd-copied="dragEnd(property, ds.dsProfile[property])"
dnd-selected="dropzoneModels.selected = ds.dsProfile[property]">
<label class="btn-property" style="font-size: 100%;">
{{property}}
</label>
<button class="btn-graphic-only btn-remove" type="button"
ng-model="singleModel"
tooltip="Remove property from schema"
tooltip-placement="right"
ng-click="removeProperty(property)">
</button>
<div ng-show="modifySchemaMode === true">
<!--keep the following on the same line to prevent spaces between values-->
{{model.properties[property]["main-type"]}}<span
ng-show="model.properties[property]['main-type']">:{{model.properties[property]["detail"]["detail-type"]}}</span>
</div>
</li>
</ul>
</span>
</td>
<td ng-repeat="ds in model.dataSamples"
ng-style="highlightIfInDetails(ds.dsProfile[property])">
<span class="btn-property">
<label class="btn-property"
style="font-size: 100%; font-weight: normal;
-webkit-user-select: none; -moz-user-select: none;
-ms-user-select: none;"
unselectable="on"
single-click="showInDetails1(ds, property, false)"
ng-dblclick="showInDetails2(ds, property);">
<div ng-show="ds.dsProfile[property]['original-name']">
<label style="font-size: 100%;">{{ds.dsProfile[property]['original-name']}}</label>
</div>
<!--keep the following on the same line to prevent spaces between values-->
{{ds.dsProfile[property]["main-type"]}}<span
ng-show="ds.dsProfile[property]['main-type']">:{{ds.dsProfile[property]["detail"]["detail-type"]}}</span>
<span class="btn-merge-indicator"
ng-show="ds.dsProfile[property]['merged-into-schema']">
</span>
</label>
<span class="btn-use-check"
ng-show="ds.dsProfile[property]['used-in-schema']">
</span>
<br>
<select name="altNameSelected" id="altNameSelected"
ng-options="option.name for option in ds.dsProfile[property]['match-names'].availableOptions track by option.id"
ng-model="ds.dsProfile[property]['match-names'].selectedOption"
ng-show="ds.dsProfile[property]['match-names'].availableOptions.length > 0"
ng-change="changeMatchedProperty(ds, property)">
</select>
</span>
</td>
</tr>
</tbody>
</table>
</div>
library:
/**
* AngularJS fixed header scrollable table directive
* #author Jason Watmore <jason#pointblankdevelopment.com.au> (http://jasonwatmore.com)
* #version 1.2.0
*/
(function () {
angular
.module('anguFixedHeaderTableCustom', [])
.directive('fixedHeaderCustom', fixedHeaderCustom);
fixedHeaderCustom.$inject = ['$timeout'];
function fixedHeaderCustom($timeout) {
return {
restrict: 'A',
link: link
};
function link($scope, $elem, $attrs, $ctrl) {
var elem = $elem[0];
// wait for data to load and then transform the table
$scope.$watch(tableDataLoaded, function(isTableDataLoaded) {
if (isTableDataLoaded) {
transformTable();
}
});
function tableDataLoaded() {
// first cell in the tbody exists when data is loaded but doesn't have a width
// until after the table is transformed
var firstCell = elem.querySelector('tbody tr:first-child td:first-child');
return firstCell && !firstCell.style.width;
}
function transformTable() {
// reset display styles so column widths are correct when measured below
angular.element(elem.querySelectorAll('thead, tbody, tfoot')).css('display', '');
// wrap in $timeout to give table a chance to finish rendering
$timeout(function () {
// set widths of columns
angular.forEach(elem.querySelectorAll('tr:first-child th'), function (thElem, i) {
var tdElems = elem.querySelector('tbody tr:first-child td:nth-child(' + (i + 1) + ')');
var tfElems = elem.querySelector('tfoot tr:first-child td:nth-child(' + (i + 1) + ')');
var columnWidth = tdElems ? tdElems.offsetWidth : thElem.offsetWidth;
if (tdElems) {
tdElems.style.width = columnWidth + 'px';
}
if (thElem) {
thElem.style.width = columnWidth + 'px';
}
if (tfElems) {
tfElems.style.width = columnWidth + 'px';
}
});
// set css styles on thead and tbody
angular.element(elem.querySelectorAll('thead, tfoot')).css('display', 'block');
angular.element(elem.querySelectorAll('tbody')).css({
'display': 'block',
'height': $attrs.tableHeight || 'inherit',
'overflow': 'auto'
});
// reduce width of last column by width of scrollbar
var tbody = elem.querySelector('tbody');
var scrollBarWidth = tbody.offsetWidth - tbody.clientWidth;
if (scrollBarWidth > 0) {
// for some reason trimming the width by 2px lines everything up better
scrollBarWidth -= 2;
var lastColumn = elem.querySelector('tbody tr:first-child td:last-child');
lastColumn.style.width = (lastColumn.offsetWidth - scrollBarWidth) + 'px';
}
});
}
}
}
})();
Related
I am working on a small application that displays a "users" JSON in an HTML5 table. I use Bootstrap 3, Axios and Vue.js 2 for this purpose.
The items displayed are paginated. Here is the code for all that:
var app = new Vue({
el: '#app',
data: {
users: [],
loading: true,
errored: false,
url: "https://randomuser.me/api/?&results=100&inc=name,location,email,cell,picture",
page: 1,
perPage: 10,
pages: [],
},
methods: {
getUsers() {
axios
.get(this.url)
.then(response => {
this.users = response.data.results
})
.catch(error => {
console.log(error)
this.errored = true
})
.finally(() => this.loading = false)
},
setPages() {
var numberOfPages = Math.ceil(this.users.length / this.perPage);
for (var index = 1; index <= numberOfPages; index++) {
this.pages.push(index);
}
},
paginate(users) {
var page = this.page;
var perPage = this.perPage;
var from = (page * perPage) - perPage;
var to = (page * perPage);
return users.slice(from, to);
}
},
created() {
this.getUsers();
},
watch: {
users() {
this.setPages();
}
},
computed: {
displayedUsers() {
return this.paginate(this.users);
}
},
filters: {
lowercase(value) {
return value.toLowerCase();
},
capitalize(value) {
return value.charAt(0).toUpperCase() + value.slice(1);
}
}
});
.table-container {
margin: 10px;
}
.table-container .panel-heading {
font-weight: bold;
}
.table-container .panel-body {
padding: 0;
}
.table-container table {
margin-bottom: 0;
border: none;
}
.table-container table tr:last-child td {
border-bottom: none;
}
.table-container table tr th {
font-weight: bold;
}
.table-container table tr th:first-child,
.table-container table tr td:first-child {
border-left: none;
}
.table-container table tr th:last-child,
.table-container table tr td:last-child {
border-right: none;
}
.table-container table tr td {
padding: 2px 8px !important;
vertical-align: middle;
}
.table-container table tr td .picture {
padding-right: 10px;
}
.table-container table tr td img {
max-height: 30px;
width: auto;
border: 1px solid #c7c7c7;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div id="app" class="container">
<div class="panel panel-default table-container">
<div class="panel-heading">Users</div>
<div class="panel-body">
<div class="table-responsive">
<table class="table table-striped table-bordered" id="dataTable">
<thead>
<tr>
<th class="text-right">#</th>
<th>Name</th>
<th>Email</th>
<th>City</th>
</tr>
</thead>
<tbody>
<tr v-for="(user, index) in displayedUsers">
<td class="text-right">{{perPage * (page - 1) + index + 1}}</td>
<td>
<span class="picture">
<img :src="user.picture.thumbnail" :alt="user.name.first + ' ' + user.name.last" class="img-circle">
</span>
<span>{{user.name.first | capitalize}} {{user.name.last | capitalize}}</span>
</td>
<td><a :href="'mailto:' + user.email | lowercase">{{user.email | lowercase}}</a></td>
<td>{{user.location.city | capitalize}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<nav class="text-center" aria-label="Page navigation">
<ul class="pagination pagination-sm">
<li>
<a href="#" #click="page = 1" aria-label="First">
<span aria-hidden="true">«</span>
</a>
</li>
<li>
<a href="#" v-if="page != 1" #click="page--" aria-label="Previous">
<span aria-hidden="true">‹</span>
</a>
</li>
<li v-for="pageNumber in pages.slice(page-1, page+4)" :class="{'active': page === pageNumber}">{{pageNumber}}</li>
<li>
<a href="#" #click="page++" v-if="page < pages.length" aria-label="Next">
<span aria-hidden="true">›</span>
</a>
</li>
<li>
<a href="#" #click="page = pages.length" aria-label="Last">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/axios#0.18.0/dist/axios.min.js"></script>
I have ran into a problem after adding a search/filter functionality to he application. I have added this to the template/view:
<div class="panel-heading clearfix">
<h2 class="pull-left">Users</h2>
<div class="searchbox">
<input type="text" v-model="search" class="form-control" placeholder="Search...">
</div>
</div>
and replaced <tr v-for="(user, index) in displayedUsers"> with <tr v-for="(user, index) in searchResults">.
Then, to computed section of the script the script, I added:
searchResults() {
return this.users.filter((user) => {
return user.name.first.match(this.search);
});
}
The search (through names) works, but neither the entire JSON, nor the search results are paginated.
I have failed to make them work together. The broken application can be seen HERE.
What is missing?
In order to make the pagination work together with the filtering you need to combine the pagination logic with your searchResults in displayedUsers
displayedUsers() {
return this.paginate(this.searchResults);
},
Then you will need to use displayedUsers everywhere where you are interested the combined result, so in your template:
<tr v-for="(user, index) in displayedUsers">
There is one more thing to fix in your code: the number of pages currently always uses the original user count, which has to be updated to use the "current" user count:
setPages(users) {
this.pages.length = 0; //we need to clear the previously set pages
var numberOfPages = Math.ceil(users.length / this.perPage);
for (var index = 1; index <= numberOfPages; index++) {
this.pages.push(index);
}
},
And update the pages whenever the dispayedUsers are changed:
watch: {
displayedUsers() {
this.setPages(this.searchResults);
}
},
If you also want to reset the page when on search you just need to set the page in searchResults
searchResults() {
this.page = 1;
return this.users.filter((user) => {
return user.name.first.match(this.search);
});
}
Working JSFiddle.
How can I use the simplePagination.js jQuery plugin with server side? I have a lot of divs loading with my page (not a table) and I am paginating those 'divs'. But, there will be cases that I will get a lot of things to paginate (like 2500+) and my page gets slow. This is my code now:
$("#pagination").pagination({
items: numItems,
itemsOnPage: perPage,
cssStyle: "light-theme",
// This is the actual page changing functionality.
onPageClick: function(pageNumber) {
// We need to show and hide `tr`s appropriately.
var showFrom = perPage * (pageNumber - 1);
var showTo = showFrom + perPage;
// We'll first hide everything...
items.hide()
// ... and then only show the appropriate rows.
.slice(showFrom, showTo).show();
}
});
And this is my page with all the divs loaded:
As you can see, I have a search option:
But everytime I search something, all the divs are reloaded, and the pagination is made again.
I want to know if its possible to change this code to not load all the content in client-side but something like if I select the content from server side. The divs are loaded by a SQL command, so, maybe I can use the functions of each page number to load each page correctly with only 20 itens and later I can do something about the search box.
EDIT
That is my html code (in php):
<html lang="pt-br">
<head>
<link rel="stylesheet" href="assets/css/simplePagination.css">
<script src="assets/js/jquery.simplePagination.js"></script>
<script type="text/javascript">
$(function(){
var keywordInput = document.querySelector("input[name='keyword']");
function performMark() {
$(".content.panel").show();
// Read the keyword
var keyword = keywordInput.value;
$('.content').removeClass('hidden');
$('.content:not(:contains(' + keyword + '))').addClass('hidden');
/* Tentar refazer paginação */
var items = $(".content.panel").not(".hidden");
var numItems = items.length;
var perPage = 16;
// Only show the first 2 (or first `per_page`) items initially.
items.slice(perPage).hide();
$("#pagination").pagination({
items: numItems,
itemsOnPage: perPage,
cssStyle: "light-theme",
// This is the actual page changing functionality.
onPageClick: function(pageNumber) {
// We need to show and hide `tr`s appropriately.
var showFrom = perPage * (pageNumber - 1);
var showTo = showFrom + perPage;
// We'll first hide everything...
items.hide()
// ... and then only show the appropriate rows.
.slice(showFrom, showTo).show();
}
});
};
// Listen to input and option changes
keywordInput.addEventListener("input", performMark);
});
</script>
<script type="text/javascript">
$(function() {
var items = $(".content.panel").not(".hidden");
var numItems = items.length;
var perPage = 16;
// Only show the first 2 (or first `per_page`) items initially.
items.show();
items.slice(perPage).hide();
// Now setup the pagination using the `.pagination-page` div.
$("#pagination").pagination({
items: numItems,
itemsOnPage: perPage,
cssStyle: "light-theme",
// This is the actual page changing functionality.
onPageClick: function(pageNumber) {
// We need to show and hide `tr`s appropriately.
var showFrom = perPage * (pageNumber - 1);
var showTo = showFrom + perPage;
// We'll first hide everything...
items.hide()
// ... and then only show the appropriate rows.
.slice(showFrom, showTo).show();
}
});
function checkFragment() {
// If there's no hash, treat it like page 1.
var hash = window.location.hash || "#page-1";
// We'll use a regular expression to check the hash string.
hash = hash.match(/^#page-(\d+)$/);
if(hash) {
// The `selectPage` function is described in the documentation.
// We've captured the page number in a regex group: `(\d+)`.
$("#pagination").pagination("selectPage", parseInt(hash[1]));
}
};
// We'll call this function whenever back/forward is pressed...
$(window).bind("popstate", checkFragment);
// ... and we'll also call it when the page has loaded
// (which is right now).
checkFragment();
});
</script>
<!--link href="assets/css/table.css" rel="stylesheet"-->
</head>
<body onload="myFunction()">
<div class="container">
<div id="loader"></div>
<div style="display:none;" id="myDiv" class="animate-bottom">
<div class="input-group input-group-lg" style="margin-bottom: 15px;">
<span class="input-group-addon glyphicon glyphicon-search" id="sizing-addon1" style="position: initial;"></span>
<input name="keyword" type="text" class="form-control" placeholder="Pesquisar" aria-describedby="sizing-addon1" onload="performMark()">
</div>
<div id="pagination" style="margin-bottom: 5px;"></div>
<div class='row centered'>
<?php
$sql = "SELECT * FROM USU_TDriCad";
$stid = oci_parse($conn, $sql);
oci_execute($stid);
while (($row = oci_fetch_array($stid, OCI_BOTH)) != false) {
$CodDri = 'test';
$CodDri = (isset($row['USU_CODDRI']) ? $row['USU_CODDRI'] : '');
echo '<div class="content warning">
<div class="content panel panel-warning">
<div class="panel-heading highlight">
<h3 class="panel-title">' . $StrLoc . '</h3>
</div>
<div class="panel-body warning highlight" style="padding: 2px">
' . $CodDri . '
</div>
<div class="panel-body warning highlight" style="padding: 2px; font-size: 16px">
<div class="col-xs-6">1000</div>
<div class="col-xs-6">#008</div>
</div>
</div>
</div>';
}
oci_free_statement($stid);
?>
</div>
</div>
</div>
</body>
</html>
Thanks
I will offer my solution.
var
search = $("#search"),
control = $("#pagination"),
table = $("#table tbody tr"),
pageParts = null,
perPage = 2;
search.on("keyup", function() {
var value = $(this).val().toLowerCase();
table.filter(function() {
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
});
updPagination();
});
control.pagination({
itemsOnPage: perPage,
cssStyle: "light-theme",
onPageClick: function(pageNum) {
var start = perPage * (pageNum - 1);
var end = start + perPage;
if (pageParts) {
pageParts.hide()
.slice(start, end).show();
}
}
});
function updPagination() {
pageParts = table.filter(function() { return $(this).css("display") !== 'none' });
pageParts.slice(perPage).hide();
control.pagination('selectPage', 1);
control.pagination('updateItems', pageParts.length);
}
updPagination();
table {
border-collapse: collapse;
border-spacing: 0;
empty-cells: show;
border: 1px solid #cbcbcb;
}
td,
th {
border-left: 1px solid #cbcbcb;
border-width: 0 0 0 1px;
font-size: inherit;
margin: 0;
overflow: visible;
padding: 0.5em 1em
}
td:first-child,
th:first-child {
border-left-width: 0;
}
thead {
background-color: #e0e0e0;
color: #000;
text-align: left;
vertical-align: bottom;
}
<link rel="stylesheet" href="https://cdn.bootcss.com/simplePagination.js/1.6/simplePagination.min.css">
<input id="search" type="text" placeholder="Search for..">
<table id="table">
<thead>
<tr>
<td>ID</td>
<td>Name</td>
</tr>
<tbody>
<tr>
<td>1</td>
<td>test 1</td>
</tr>
<tr>
<td>2</td>
<td>test 2</td>
</tr>
<tr>
<td>3</td>
<td>test 3</td>
</tr>
<tr>
<td>4</td>
<td>test 4</td>
</tr>
<tr>
<td>5</td>
<td>test 5</td>
</tr>
</tbody>
</table>
<div id="pagination"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/simplePagination.js/1.6/jquery.simplePagination.min.js"></script>
I have a table on my page and I was wondering if it was possible to change the values of the 2nd column when a user clicks on the heading of the 2nd column.
For example,
-----------------------------
| 1st heading | 2nd heading |
|-------------|-------------|
| | |
| | |
| | |
| | |
| | |
Now when the user clicks on "2nd heading" the value of the second column will change and the name of the heading will change too ( from 2nd heading to 3rd heading )
This is a simple task using jquery.
First add id to the columns. The second heading column should be like this
Without jQuery
<th id="th2" onclick="changeVal()">2nd Heading</th>
<script>
function changeVal() {
document.getElementById("th2").innerHTML = "3rd Heading";
}
</script>
With jQuery
This section has been updated. I added a data-state attribute the column head, so when you toggle values it will record the last change.
<th id="th2" data-state="2">2nd Heading</th>
Add jquery code like this after linking a jquery file
<script type="javascript" src="path_to_jquery.js" />
<script>
$("#th2").click(function() {
var state = $(this).attr("data-state");
if(state=="2") {
$(this).html("3rd Heading");
$(this).attr("data-state", "3");
} else if(state=="3") {
$(this).html("2nd Heading");
$(this).attr("data-state", "2");
}
});
//you can replace $(this) with $("#th2") or thr id of another element or table cell to manipulate the value inside
</script>
Try it out and give feedback
Add a event listener on each th elements and add change the innerHTML as you want.
The int value is, for now, just based on the th index so it will change only once (index + 1).
We need more informations to change the logic.
var ths = document.getElementsByTagName("th");
var tds = document.getElementsByTagName("td");
for (var i = 0; i < ths.length; i++) {
(function(i) {
ths[i].addEventListener('click', function(e){
changeText(i);
});
}(i));
}
function changeText(index) {
ths[index].innerHTML = "TH" + ( index + 1 );
tds[index].innerHTML = "TD" + ( index + 1 );
}
<table>
<thead>
<th>TH0</th>
<th>TH1</th>
</thead>
<tbody>
<tr>
<td>TD0</td>
<td>TD1</td>
</tr>
</tbody>
</table>
Here is a simple example with jQuery. Maybe it will help you
$(document).ready(function(){
$("table th:nth-child(2)").click(function(){
$(this).text("3rd heading");
$("tr td:nth-child(2)").text("changed");
});
});
table, th, td {
border: 1px solid black;
border-collapse: collapse;
padding: 5px;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<th>1st heading </th> <th>2nd heading</th>
</tr>
<tr>
<td>val1</td><td>val2</td>
</tr>
<tr>
<td>val1</td><td>val2</td>
</tr>
</table>
For the sake of argument (I would never recommend to do it like this - javascript is there for some reason!), here is a solution with pure CSS - though it is a hack using checkbox and label to simulate the CSS click and changing the content that is already hidden in the table - see demo below:
table {
border-collapse: collapse;
}
table td,
table th {
border: 1px solid #ddd;
padding: 10px;
}
.hide{
display: none;
}
#h1:checked ~ table > tbody > tr > td[data-attr='h1'] span.new {
display: block;
}
#h1:checked ~ table > tbody > tr > td[data-attr='h1'] span.new + span{
display: none;
}
#h2:checked ~ table > tbody > tr > td[data-attr='h2'] span.new {
display: block;
}
#h2:checked ~ table > tbody > tr > td[data-attr='h2'] span.new + span {
display: none;
}
<input type="checkbox" id="h1" class="hide"/>
<input type="checkbox" id="h2" class="hide"/>
<table>
<thead>
<tr>
<th>
<label for="h1">Heading 1</label>
</th>
<th>
<label for="h2">Heading 2</label>
</th>
</tr>
</thead>
<tbody>
<tr>
<td data-attr="h1">
<span class="new hide">New Content 1</span>
<span>Content 1</span>
</td>
<td data-attr="h2">
<span class="new hide">New Content 2</span>
<span>Content 2</span>
</td>
</tr>
<tr>
<td data-attr="h1">
<span class="new hide">New Content 1</span>
<span>Content 1</span>
</td>
<td data-attr="h2">
<span class="new hide">New Content 2</span>
<span>Content 2</span>
</td>
</tr>
</tbody>
</table>
Scenario:
I have a results table with a checkbox, when the checkbox is checked, the content of the row(actually 2 columns concateneted only, are copied to a new div, with the job code and job name). This works pretty well, and I am avoiding duplicated already.
However, in the new results div, I am creating an anchor tag to remove the div itself.
After the div has been removed, I should be able to add the selected job again with the checkbox.
Please note that there are many jobs in the results table, so putting the flag to false again will not work.
Also if you find a better title for this question, please let me know
//On every checkbow that is clicked
var flag = false;
$("#ctl00_PlaceHolderMain_myGrid input").change(function () {
if (this.checked && flag === false) {
flag = true;
var jobCode = $(this).parent().parent().parent().find("td:eq(2)").text()
var jobName = $(this).parent().parent().parent().find("td:eq(1)").text()
var displayvalue = jobCode.toUpperCase() + " - " + jobName.toUpperCase();
AddSelectedJob(jobCode, displayvalue);
//$(this).unbind('change'); //Unbind the change event so that it doesnt fire again
FillSelectedJobs();
}
});
//Add selected job in the results div
function AddSelectedJob(id, display) {
//create a div for every selected job
$("[id$=ResultsDiv]").append('<div class="selectedjobs" id=' + id + '>' + display + 'Remove selected job</div>');
}
//Removes the selected job from the resutls div
function removeSelectedJob(el) {
$(el).parent().remove();
}
The generated html is like this:
<div>
<div style="height: 300px; overflow: auto; float: left">
<div>
<table cellspacing="0" cellpadding="4" id="ctl00_PlaceHolderMain_myGrid" style="color:#333333;width:100%;border-collapse:collapse;">
<tr style="color:White;background-color:#5D7B9D;font-weight:bold;">
<th scope="col"> </th><th scope="col">JobCode</th><th scope="col">JobName</th><th scope="col">JobPartner</th><th scope="col">JobManager</th><th scope="col">ClientName</th>
</tr><tr style="color:#333333;background-color:#F7F6F3;">
<td>
<input id="ctl00_PlaceHolderMain_myGrid_ctl02_CheckBox1" type="checkbox" name="ctl00$PlaceHolderMain$myGrid$ctl02$CheckBox1" />
</td><td>jobcode01</td><td>jobname</td><td>xx</td><td>xx</td><td>xx</td>
</tr>
</table>
</div>
</div>
<div style="margin-top: 0px; margin-left: 10px; float: left">
<span>Selected :</span>
<div id="ResultsDiv" style="margin-top: 0px">
</div>
</div>
Firstly I suggest some changes to your HTML. Separate out the styles from your DOM and place them in classes.
This makes sure there is separation of concerns
HTML
<div>
<div class="divMain">
<div>
<table cellspacing="0" cellpadding="4"
id="ctl00_PlaceHolderMain_myGrid" class="table">
<tr class="rowHead">
<th scope="col"> </th>
<th scope="col">JobCode</th>
<th scope="col">JobName</th>
<th scope="col">JobPartner</th>
<th scope="col">JobManager</th>
<th scope="col">ClientName</th>
</tr>
<tr class="row">
<td>
<input id="ctl00_PlaceHolderMain_myGrid_ctl02_CheckBox1"
type="checkbox"
name="ctl00$PlaceHolderMain$myGrid$ctl02$CheckBox1"
data-flag="false" />
</td>
<td>column1</td>
<td>column2</td>
<td>column3</td>
<td>column4</td>
<td>column5</td>
</tr>
</table>
</div>
</div>
<div class="m0 selected">
<span>Selected :</span>
<div id="ResultsDiv" class="m0"></div>
</div>
CSS
.divMain{
height: 300px;
overflow: auto;
float: left
}
.table{
color:#333333;
width:100%;
border-collapse:collapse;
}
.rowHead{
color:White;
background-color:#5D7B9D;
font-weight:bold;
}
.row{
color:#333333;
background-color:#F7F6F3;
}
.m0{
margin-top: 0px;
}
.selected{
margin-left: 10px;
float: left
}
Javascript
$("#ctl00_PlaceHolderMain_myGrid input").change(function () {
// Next cache your selector
// so that you need not crawl the DOM multiple times
var $this = $(this),
$row = $this.closest('.row'),
currFlag = Boolean($this.data('flag'));
// As there might be multiple jobs , a single flag variable
// will not work. So you can set a data-flag attribute on the
// input that stores the current value
if (currFlag === false && this.checked) {
// Set the corresponding flag to true
$this.data('flag', true);
var jobCode = $row.find("td:eq(2)").text(),
jobName = $row.find("td:eq(1)").text(),
displayvalue = jobCode.toUpperCase() + " - "
+ jobName.toUpperCase(),
inputId = $this.attr('id')
// Pass the input name too as you need to set the value of
// the corresponding flag value again as you can add it multiple times
AddSelectedJob(jobCode, displayvalue, inputId);
FillSelectedJobs();
}
});
//Add selected job in the results div
function AddSelectedJob(id, display, inputId) {
//create a div for every selected job
// Use the inputId to save it as a data-id attribute
// on anchor so that you can set the value of the flag after
// removing it
var html = '<div class="selectedjobs" id=' + id + '>' + display ;
html += '<a href="javascript" data-id="'+ inputId
+'">Remove selected job</a></div>';
$('[id$=ResultsDiv]').append(html);
}
// Remove the inline click event for the anchor and delgate it to the
// static parent container
$('[id$=ResultsDiv]').on('click', 'a', function(e) {
var $this = $(this),
$currentCheckbox = $this.data('id');
// Set the flag value of the input back to false
$('#'+ $currentCheckbox).data('flag', false);
e.preventDefault(); // prevent the default action of the anchor
$this.closest('.selectedjobs').remove();
});
function FillSelectedJobs() {
//save values into the hidden field
var selectedJobs = $("[id$=ResultsDiv]").find("[class$='selectedjobs']");
var returnvalue = "";
for (var i = 0; i < selectedJobs.length; i++)
returnvalue += selectedJobs[i].id + ";";
$("[id$=HiddenClientCode]").val(returnvalue);
}
Check Fiddle
I want to appends ellipsis (…) to the end of row of datatable(in this comment column). For this I have added jQuery ellipsis js. how should I specify height to jQuery data table row so that it only show 2 line. Right now height is adjusted according to length of text.
This is my jQuery table
<div id="comments">
<c:choose>
<c:when test="${null ne comments and not empty comments}">
<table id="dataTable2" cellpadding="0" cellspacing="0" border="0" class="display" style="width:100%;">
<thead><tr><th>Id</th>
<th width="15%">User</th>
<th width="15%">Role</th>
<th width="45%">Comment</th></tr></thead>
<tbody>
<c:forEach items="${comm}" var="comm" varStatus="status">
<tr><td>${comment.commentId}</td>
<td width="15%">${comm.userFullName}</td>
<td width="15%">${comm.userRoleName}</td>
<td width="45%" style="height:20px" class="ellipsis multiline">${comm.CommentAbbreviation}</td></tr>
</c:forEach>
</tbody>
</table>
</c:when></c:choose>
</div>
jquery.autoellipsis.js
(function($) {
$.fn.ellipsis = function()
{
return this.each(function()
{
var el = $(this);
if(el.css("overflow") == "hidden")
{
var text = el.html();
var multiline = el.hasClass('multiline');
var t = $(this.cloneNode(true))
.hide()
.css('position', 'absolute')
.css('overflow', 'visible')
.width(multiline ? el.width() : 'auto')
.height(multiline ? 'auto' : el.height());
el.after(t);
function height() { return t.height() > el.height(); };
function width() { return t.width() > el.width(); };
var func = multiline ? height : width;
while (text.length > 0 && func())
{
text = text.substr(0, text.length - 1);
t.html(text + "...");
}
el.html(t.html());
t.remove();
}
});
};
})(jQuery);
css class
.ellipsis {
white-space: nowrap;
overflow: hidden;
}
.ellipsis.multiline {
white-space: normal;
}
How should I set height to datatable row ?
This worked great for me
.dataTable th, .dataTable td {
max-width: 200px;
min-width: 70px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
I found a solution. It isn't the most correct way but it works. I wrapped the data within the in a div and I have modified following line.
<td width="45%" style="height:20px" class="ellipsis multiline">${comm.CommentAbbreviation}</td>
Replace by
<td width="45%"><div class="ellipsis multiline" style="height: 35px;">${comm.CommentAbbreviation}</div></td>
It works for me
.td-limit {
max-width: 70px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}