$(document).ready(function(){
$("#myTable td").click(function() {
var column_num = parseInt( $(this).index() ) + 1;
var row_num = parseInt( $(this).parent().index() )+1;
$("#result").html( "Row_num =" + row_num + " , Rolumn_num ="+ column_num );
});
});
In component file you can define click event function like this
<td onclick="{!c.tdClickHandler}">Some text </td>
And in controller write the handler
({
tdClickHandler : function(component, event, helper) {
console.log('I am td click handler');
}
})
Related
I have to use AngularJS to build a dashboard and one of the components is a table.
Since I did not find relevant dependencies/libraries for angularjs (like tabulator or datatables), I am doing it myself.
Instead of using the native angular filter, I built a custom method, but I am not sure if I am following a good approach.
The main idea is that when I pull the data object (array of objects) via Ajax, I create both an "original" and a "current" data object,s and at the beginning, they are exactly the same of course.
Then I created an input field above every column heading and I linked the search function to the blur and keyup events (enter key).
When the search function is triggered, I start making changes to the "current" object. This way I can filter by multiple columns incrementally. I filter the data object using an awesome library called AlaSQL.
I also linked to a button the "reset" method, which simply makes the "current" object equal to the "original" object, and cleans up the input fields.
The point is, am I missing any best practices? Are there better ways to do so with AngularJS?
Any suggestions?
Thanks a lot.
HTML
<div ng-app="myApp">
<div ng-controller="divController">
<my-table></my-table>
</div>
</div>
JS
var app = angular.module('myApp', []);
app.controller('divController', function ($scope, $http) {
$scope.data = {};
$scope.data.current = null;
$scope.data.original = null;
$scope.filter = {
id: {
field: "id",
value: null
},
name: {
field: "name",
value: null
},
owner: {
field: "owner",
value: null
},
}
$scope.reset = function () {
console.log("reset");
$scope.data.current = $scope.data.original;
for (let prop in $scope.filter) {
$scope.filter[prop]["value"] = null;
}
}
$scope.filterExec = function (field, value) {
if (value) {
console.log(`Executing filter on field "${field.trim()}" by this value "${value.trim()}"`);
var filtered = alasql('SELECT * FROM ? where ' + field + ' LIKE "%' + value + '%"', [$scope.data.current]);
$scope.data.current = filtered;
}
}
$http.get("./workspaces_demo_obj.json")
.then(function (response) {
console.log(response);
$scope.data.original = response.data;
$scope.data.current = response.data;
});
});
app.directive('myTable', function () {
return {
template:
'<div>Total rows {{data.current.length}} <button ng-click="reset()">RESET</button></div>' +
'<table class="table table-responsive table-sm">' +
'<thead>' +
'<tr><th>Workspace ID</th>' +
'<th>Name</th>' +
'<th>Owner</th></tr>' +
'<tr><th><input ng-model="filter.id.value" ng-blur="filterExec(filter.id.field, filter.id.value)" ng-keydown="$event.keyCode === 13 && filterExec(filter.id.field, filter.id.value)" placeholder="Filter by id"></input></th>' +
'<th><input ng-model="filter.name.value" ng-blur="filterExec(filter.name.field, filter.name.value)" ng-keydown="$event.keyCode === 13 && filterExec(filter.name.field, filter.name.value)" placeholder="Filter by name"></input></th>' +
'<th><input ng-model="filter.owner.value" ng-blur="filterExec(filter.owner.field, filter.owner.value)" ng-keydown="$event.keyCode === 13 && filterExec(filter.owner.field, filter.owner.value)" placeholder="Filter by owner"></input></th></tr>' +
'</thead>' +
'<tbody>' +
'<tr ng-repeat="x in data.current">' +
'<td>{{ x.workspace_id }}</td>' +
'<td>{{ x.name }}</td>' +
'<td>{{ x.owner }}</td>' +
'</tr>' +
'</tbody>' +
' </table>',
restrict: 'E'
};
});
I want to delete a row from html table on button click using ReactJS. The problem is that on clicking delete button always last row is being deleted instead of the row that is clicked. Please tell what is the issue with my code?
code:
var RecordsComponent = React.createClass({
getInitialState: function() {
return {
rows: ['row1', 'row2', 'row3'],
newValue: "new value"
}
},
render : function() {
return (
<div>
<table>
<tbody>
{this.state.rows.map((r) => (
<tr>
<td>{r}</td>
<td>
<button onClick={this.deleteRow}>Delete</button>
</td>
</tr>
))}
</tbody>
</table>
<input trype="text" id={"newVal"} onChange={this.updateNewValue}></input>
<button id="addBtn" onClick={this.addRow}>ADD</button>
</div>
);
},
updateNewValue: function(component) {
this.setState({
newValue: component.target.value
});
},
addRow : function() {
var rows = this.state.rows
rows.push(this.state.newValue)
this.setState({rows: rows})
},
deleteRow : function(record) {
var index = -1;
var clength = this.state.rows.length
for( var i = 0; i < clength; i++ ) {
if( this.state.rows[i].value === record.target.value ) {
index = i;
break;
}
}
var rows = this.state.rows
rows.splice( index, 1 )
this.setState( {rows: rows} );
}
});
React.render(<RecordsComponent/>, document.getElementById('display'))
You need pass a param on func deleteRow
<button onClick={() => this.deleteRow(r)}>Delete</button>
I refactor a litte bit of your func
deleteRow : function(record) {
this.setState({
rows: this.state.rows.filter(r => r !== record)
});
}
In deleteRow you are looking for the index of the row that matches record.target.value (record is actually an event), but event.target.value is blank so the index remains -1, and rows.splice(-1, 1) deletes the last element.
You should pass the row data itself, like:
<button onClick={e => this.deleteRow(r)}>Delete</button>
The objective of this plunk is to have a table where the up and down keys will be used to select rows programmatically and scroll through the table. The selected row will have a different background color.
When keying up/down I use e.preventDefault() to avoid the rows to move up/down twice. Problem is that when I start scrolling down the rows stay fixed and the selected row disappears. How to fix this?
HTML
<div id="selector" tabindex="0" ng-keydown="scroll($event)"
style="width:300px;height:80px;border:1px solid gray;overflow-y:auto">
<table>
<tr ng-repeat="item in items">
<td class="td1" ng-class="{'tdactive' : $index==index }">{{item.col}}</td>
<td class="td1" ng-class="{'tdactive' : $index==index }">{{item.dsc}}</td>
</tr>
</table>
</div>
Javascript
var app = angular.module('app', []);
app.controller('ctl', function($scope) {
document.getElementById("selector").focus();
$scope.items = [ {col:"aaa", dsc:"AAA1"}, {col:"bbb", dsc:"BBB2"} , {col:"ccc", dsc:"CCC3"},
{col:"aaa2", dsc:"AAA21"}, {col:"bbb2", dsc:"BBB22"} , {col:"ccc2", dsc:"CCC23"},
{col:"aaa2", dsc:"AAA21"}, {col:"bbb2", dsc:"BBB22"} , {col:"ccc2", dsc:"CCC23"} ];
$scope.index = 0;
$scope.scroll = function(e) {
if (e.which === 40) { // down arrow
if ($scope.index<$scope.items.length - 1)
$scope.index++;
e.preventDefault();
}
else if (e.which === 38) { // up arrow
if ($scope.index>0)
$scope.index--;
e.preventDefault();
}
};
});
First of all you need to add table row id as id="tr-{{$index}}"
You can then prevent your scroll if tr is in the current viewport
$scope.scroll = function(e) {
var parentContainer = document.getElementById("selector");
if (e.which === 40) { // down arrow
if ($scope.index<$scope.items.length - 1)
{
var element = document.getElementById("tr-"+$scope.index);
if(isElementInViewport(parentContainer,element)){
e.preventDefault();
}
$scope.index++;
}
}
else if (e.which === 38) { // up arrow
if ($scope.index>0)
{
var element = document.getElementById("tr-"+$scope.index);
if(!isElementInViewport(parentContainer,element)){
e.preventDefault();
}
$scope.index--;
}
}
};
function isElementInViewport(parent, el) {
if(parent==undefined || el==undefined)
return false;
var elRect = el.getBoundingClientRect(),
parRect = parent.getBoundingClientRect();
//console.log(elRect)
//console.log(parRect)
var elementHeight = elRect.height;
return (
elRect.top >= parRect.top &&
elRect.bottom <= parRect.bottom &&
elRect.bottom+elementHeight<= parRect.bottom
);
}
Working Plunker
li
a.accordion-trigger(href='#accordion4', data-accord-group='group1')
p(style='color:white;') 2. Subjects Average Pass Percentage :
#accordion4.accordion-content.collapsed(ng-controller='ListController2', scroll='')
form(ng-submit='addNew()')
table.table.data.table-bordered
thead
tr
th Subject Name
th Year-Sem-Branch-Sec
th No.of.Students Appeared (A)
th Passed (B)
th Pass Percentage (B/A*100)
th
input.btn.btn-primary.add.pull-right(type='submit', value='Add New')
tbody
tr(ng-repeat='subjectAverage in subjectAverages')
td.data
input(type='text', ng-model='subjectAverage.subjectName', required='')
td.data
input(type='text', ng-model='subjectAverage.yearSem', required='')
td.data
input(type='text', ng-keyup='calculatePercentage(subjectAverage)', ng-model='subjectAverage.studentsAppeared', required='')
td.data
input(type='text', ng-keyup='calculatePercentage(subjectAverage)', ng-model='subjectAverage.studentsPassed', required='')
td.data
input(type='text', ng-model='subjectAverage.percentage', disabled='disabled')
td
input.btn.btn-danger.pull-right.delete(type='button', ng-click='removeRow($index)', value='Remove')
table
tr
td Average :
td
input(type='text', ng-model='subjectAverages[0].average')
h3 Faculty text box (optional):
.form-group
textarea#comment.form-control(rows='3', ng-model='subjectAverages[0].facultyComment')
button.btn.btn-default(type='submit', ng-click='saveavg()') Save
this is .pug code
angular controller code
var app = angular.module("myapp", []);
app.controller("ListController2", ['$scope','getAverage', '$rootScope','postSubAverage',function($scope,getAverage,$rootScope,postSubAverage) {
$scope.subjectAverages = [{
'subjectName': '',
'yearSem': '',
'studentsAppeared': '',
'studentsPassed':'',
'percentage':'',
'average':'',
'facultyComment':'',
'point':''
}];
$scope.calculatePercentage = function(val) {
val.percentage = (parseFloat(val.studentsPassed)*100)/parseFloat(val.studentsAppeared);
$scope.calAverage();
};
$scope.addNew = function(personalDetail) {
$scope.subjectAverages.push({
'subjectName': "",
'yearSem': "",
'studentsAppeared': "",
'studentsPassed':"",
'percentage':""
});
};
$scope.parseFloat = function(value) {
return parseFloat(value);
};
$scope.removeRow=function(index){
// remove the row specified in index
$scope.subjectAverages.splice( index, 1);
$scope.calAverage();
// if no rows left in the array create a blank array
if ($scope.subjectAverages.length() === 0){
$scope.subjectAverages = [];
$scope.calAverage();
}
};
$scope.calAverage=function()
{
var total =0;
angular.forEach($scope.subjectAverages,function(item){
total += item.percentage;
});
$scope.subjectAverages[0].average = (total/$scope.subjectAverages.length).toFixed(2);
if($scope.subjectAverages[0].average>=90)
$scope.subjectAverages[0].point=20;
else if(($scope.subjectAverages[0].average>=80)&&($scope.subjectAverages[0].average<90))
$scope.subjectAverages[0].point=15;
else if(($scope.subjectAverages[0].average>=70)&&($scope.subjectAverages[0].average<80))
$scope.subjectAverages[0].point=10;
else if(($scope.subjectAverages[0].average>=60)&&($scope.subjectAverages[0].average<70))
$scope.subjectAverages[0].point=5;
else
$scope.subjectAverages[0].point=0;
}
$scope.isDisabled = false;
$scope.saveavg=function(){
$scope.isDisabled = true;
$rootScope.progressBarValue=($rootScope.progressBarValue+$scope.subjectAverages[0].point);
$rootScope.progressBar=(10/8)*$rootScope.progressBarValue;
getAverage.subAverage($scope.subjectAverages[0].average);
postSubAverage.postData($scope.subjectAverages);
}
}]);
app.service("postSubAverage",['$http',function($http){
return{
postData:function(subAverage){
$http({
url: '/appraisalform/subaverage',
method: "POST",
data: subAverage,
headers: {
'Content-Type': 'application/json'
}
}).then(function(postData){ //.success is deprecated,so use .then
alert("Updated Successfully");
})
.catch(function(err){//using .catch instead of .error as it is deprecated
console.log("Error in request =>", err)
})
}
}}])
when i click on save button
router.post is fired
router.post('/subaverage',function(req,res){
console.log("deepak");
});
but the problem is deepak is written is console immediately but the after some time its again apperring
deepak
POST /appraisalform/subaverage - - ms - -
deepak
i am using angular + javascript in the pug file.
can anyone help with this.
thankyou
Could be tried this :
$scope.saveavg=function(event){
$scope.isDisabled = true;
$rootScope.progressBarValue=($rootScope.progressBarValue+$scope.subjectAverages[0].point);
$rootScope.progressBar=(10/8)*$rootScope.progressBarValue;
getAverage.subAverage($scope.subjectAverages[0].average);
postSubAverage.postData($scope.subjectAverages);
event.preventDefault();
}
Because the second called could be by native navigator.
And other idea is using ng-submi t only, and not using click and submit.
Expect it helps.
tks
Is it possible to turn off certain dropdown filters in the footer? This is the API I'm using: https://datatables.net/examples/api/multi_filter_select.html
I don't want all columns to be filterable. Also, is it possible to have the header labels be the default in the dropdown instead of a blank?
Here is my live example: http://live.datatables.net/cufawibi/3/
A usual approach is to use a css class to filter which columns can be filterable.
You could also add the column name as selected and disabled in order to display it as the default (included an all values options to disable the filter).
initComplete: function () {
var api = this.api();
api.columns('.filtersearch').indexes().flatten().each( function ( i ) {
var column = api.column( i );
var select = $('<select></select>')
.appendTo( $(column.footer()).empty() )
.on( 'change', function () {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column
.search( val ? '^'+val+'$' : '', true, false )
.draw();
} );
select.append('<option selected disabled>"'+$(column.header()).text()+'"</option>');
select.append('<option value="">All values</option>');
column.data().unique().sort().each( function ( d, j ) {
select.append( '<option value="'+d+'">'+d+'</option>' );
} );
} );
}
UPDATE:
In order to have the class added from the controller, changed also the table head definition to
<th ng-repeat="(i, th) in head" value="{{th.id}}" class="{{th.class}}"><span>{{th.name}}</span></th>
Live example (filter only for the "Payload" column, add filtersearch class to other columns to enable filtering)
I don't think there's a clean way to do this via the API. So this solution will be hacky.
So you'd wrap your logic around an IF block to filter out the columns dropdown filters you don't want to display.
api.columns().indexes().flatten().each(function (index) {
var column, select;
// You don't want to display the first and the fourth dropdown filter
if (index !== 0 || index !== 3) {
column = api.column(i);
select = $('<select><option value=""></option></select>')
.appendTo($(column.footer()).empty())
.on('change', function () {
var val = $.fn.dataTable.util.escapeRegex($(this).val());
column.search(val ? '^' + val + '$' : '', true, false).draw();
});
column.data().unique().sort().each(function (d, j) {
select.append('<option value="' + d + '">' + d + '</option>')
});
}
});