Angular html table borders get ruined - angularjs

I dynamically generate angular html table. Actually, I generate several tables on page with different column numbers and sizes, and expandable editable cells is a must. Here is a simplified template I use:
<table>
<colgroup ng-repeat="col in field.cols track by $index">
<col width="{{col}}%" />
</colgroup>
<thead ng-hide="true"></thead>
<tbody>
<tr ng-repeat="row in field.rows track by $index" >
<td ng-repeat="cell in row track by $index">
<span class="text-container" ng-show="!cell.isEditing" >{{cell.text}}</span>
<input type="text" ng-show="cell.isEditing" ng-model="cell.text" ng-blur="cell.isEditing = false" />
</td>
</tr>
</tbody>
</table>
and the very simplified directive is:
app.directive('tableField', function() {
return {
templateUrl: 'views/table.html',
replace: true,
restrict: 'A',
scope: {
field: '='
},
link: function($scope, $element, $attr){
var init = function() {
$scope.appendRow = function addRow() {
var newRow = [];
$scope.field.rows[0].forEach(function(col) {
newRow.push({'text': 'new'});
});
$scope.field.rows.push(newRow);
};
};
};
init();
}
};
}]);
this is how it looks before edits or page orientation change:
When I append a new row or edit cells and they expand, or rotate the device, the borders ruin - see the images:
Ideally I need to generate several tables on page with different column numbers and widths, with editable expandable cells. What shall I do to achieve proper result? I somehow need the table rows to update the row height upon any changes. Please help. I also could not find a library to do all I need.
Some part of the stylesheet:
table {
width: 100%;
border: 1px solid #000000;
}
table > tbody > tr > td {
line-height: 1.42857143;
border: 1px solid #000000;
}
table .text-container {
word-wrap: break-word;
word-break: break-all;
}
the rest regards colors and other stuff not influencing the table layout.

Finally I ended up rewriting the table on flexboxes. Thus now it is not a <table> but a set of <div>s with flexbox styles. Though it looks nice and which is more works fine on all devices.

Related

AngularJS uiSortable - highlighting table cell moving over with item and mouse

I use uiSortable (uiSortable) in my application and it works fine.
The only thing I was not able to do is to highlighting the drop cell before leave the item into the cell.
This is my html- code:
<td ui-sortable="vm.moveableItems" data-ng-model="myModelItems">
....
and this is my javascript code:
vm.moveableItems= {
start: function(e, ui) {
},
update: function(e, ui) {
},
stop: function(e, ui) {
// code to place the item into the cell -> works fine
Is there a possibility to highlight the cell I move over with the item and the mouse?
uiSortable is by default already applying the ui-sortable-placeholder class to the element you are currently hovering.
By default, it's invisible, but you can easily change it using only css:
.ui-sortable-placeholder {
visibility: visible !important;
background: red;
}
If the element you want to stylize is the td instead, just change the background of .ui-sortable-placeholder td, but keep the visibility override on the placeholder class.
You're looking for placeholder: <classname>.
This gets set in your ui-sortable=<parms>, alongside the start, update and stop methods you're already using.
Demo http://plnkr.co/edit/s3LNeq4SzrBxj4bhFu4q?p=preview
Controller
app.controller('mainController', function ($scope) {
$scope.list = ['Alabama','Alaska','Arizona','Arkansas'];
$scope.sortableOptions = {
placeholder: 'ui-state-highlight'
start: function(e, ui) {},
update: function(e, ui) {},
stop: function(e, ui) {},
};
});
Markup
<div ng-controller="mainController">
<table class="table">
<tbody ui-sortable="sortableOptions" ng-model="list">
<tr ng-repeat="item in list" style="cursor: move;">
<td>
{{item}}
</td>
</tr>
</tbody>
</table>
</div>
CSS
.ui-state-highlight {
height: 50px;
background: green;
display: block;
}
Update:Horizontal
This is also possible to do with horizontal movement. Pass 'ui-floating': true, and tweak your css to support it. Plnkr of this implantation here: http://plnkr.co/edit/YwBpL0LmSvVaa4t2HNsO?p=preview

angular-datatables - ng-repeat does not update datatable with new rows when $onChanges event called in component controller

I have made an angular-datatable component to be used in my project (using angular 1.5) and have bound the data it is populated with (the angular way) to an array of objects that gets updated in the parent scope. Upon changing the parent scope value, the $onChanges event is called and the bound data is updated, but the rows in the table do not change via ng-repeat to reflect the update -- after the table is initially drawn, no changes can be seen with subsequent data changes. Here is my code:
JS:
angular.module('datatable').
component('datatable', {
bindings: {
graphData: '<',
tableId: '=',
divId: '='
},
templateUrl: 'components/graphs/datatable.template.html',
controller: function datatableController (DTOptionsBuilder, DTColumnBuilder) {
let self = this;
self.tableKeys = Object.keys(self.graphData[0])
self.$onChanges = function () {
self.dtOptions = {
paginationType: 'full_numbers',
displayLength: 30,
dom: 'Bfrtip',
buttons: [
{extend: 'excelHtml5'},
'copy'
],
scrollY: 450,
scrollX: '100%',
scrollCollapse: true,
};
};
}
})
HTML (Component):
<datatable graph-data="$ctrl.submittedResults" table-id="'allDataTableResults'" div-id="'allDataTable'"></datatable>
HTML (Template):
<div class="col-md-10 col-md-offset-1">
<div class="well well-lg" style="background: white">
<div id="{{$ctrl.divId}}" style="width: 100%; height: 700px; display: block; margin: 0 auto">
<table datatable="ng" dt-options="$ctrl.dtOptions"
class="table table-striped table-bordered" cellspacing="0">
<thead>
<tr>
<th ng-repeat="key in $ctrl.tableKeys">{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in $ctrl.graphData">
<td ng-repeat="val in row">{{val}}</td>
</tr>
</tbody>
</table>
</div>
</div>
I have tried just about everything I have seen in related questions on Stack Overflow to no avail, and I had no luck with rerendering the table completely with dtInstance. Any help would be greatly appreciated.
v0.5.5 doesn't allow '$' char in controller variable name which unfortunately is the default value in Angular Component. Override it as a workaround e.g. controllerAs: ctrl
https://github.com/l-lin/angular-datatables/blob/v0.5.5/dist/angular-datatables.js#L892
Reported this issue: https://github.com/l-lin/angular-datatables/issues/916

Setting a table onclick using AngularJS ng-repeat

My static html table has a row click event which hightlights a div.
The static table is working fine, but my ng-repeat table has some issues.
I can now highlight my div with a red border, but how do I remove the border when something else is clicked ?
Here's the static table example :
<script type="text/javascript">
$('.image-clicked').click(function () {
debugger;
$(this).css("border", "2px solid red");
});
$('.clickable_row td div').click(function (e) {
// clear all borders first, highlight clicked image
var imageclicked = $(this).data('url');
$('.propertyTable td div').css("border", "none");
$(this).css("border", "2px solid red");
});
</script>
<table id="gadgets" class="propertyTable clickable_row">
<tr>
<th>Type</th>
</tr>
<tr>
<td data-url="chart_treelist">
<div><img data-draggable id="chart_treelist" src="images2/table.png" title="Tree Grid" alt="Hierarchy Grid" width="64" height="64">Grid</div>
</td>
<td data-url="{chart_pivot}">
<div><img data-draggable id="chart_pivot" src="images2/pivottable.png" title="Pivot Table" alt="Pivot Table" width="64" height="64">Pivot</div>
</td>
</tr>
<tr>
<td>
<div><img data-draggable id="chart_bar" src="images2/bar.png" title="Bar" width="64" height="64">Bar</div>
</td>
<td>
<div><img data-draggable id="chart_line" src="images2/line.fast.png" title="Line" >Line</div>
</td>
</tr>
<tr>
<td>
<img data-draggable id="chart_pie" src="images2/pie.png" title="Pie" alt="Pie" width="64" height="64">Pie
</td>
<td><img data-draggable id="chart_area" src="images2/area.png" title="Area" alt="Area" width="64" height="64">Area</td>
</tr>
<tr>
<td>
<img data-draggable id="chart_scatter" src="images2/point.png" title="Scatter" width="64" height="64">Scatter
</td>
<td>
<img data-draggable id="chart_bubble" src="images2/bubble.png" title="Bubble" width="64" height="64">Bubble
</td>
</tr>
</table>
And here is the AngularJS ng-repeat generated table.
FYI: ng-class assigns the image-border class if the initImage values are equal. ng-click goes into the controller and reassigns the chart based on what was just selected.
PROBLEM: I cannot figure out how to select a NEW chart icon with red border, and simultaneously REMOVE the image-border class on the others.
(function () {
'use strict';
angular.module('rage')
.controller('GadgetIconsCtrl', ['$rootScope', '$scope', icons]);
function icons($rootScope, $scope) {
var gadgets = this;
gadgets.subset = null;
gadgets.chartSelected = null;
gadgets.selectChart = function (chart) {
// the assumption is that user selected a different chart icon from the formatting tab
gadgets.chartSelected = chart;
};
if ($scope.widget.gadgetType == 'chart' && $scope.widget.chartType == 'bar') {
// user is configuring a bar chart type, so we also include 'column' in our subset of icons to display
gadgets.subset = _.filter($scope.widgetDefs, function (item) {
return item.chartType == 'bar' || item.chartType == 'column';
});
}
}; // end of gridSettings()
})();
<style scoped>
.image-clicked {
border: 2px solid red;
}
.image-unclicked {
border: 2px solid red;
}
</style>
<table ng-controller="GadgetIconsCtrl as gadgets" >
<tr ng-repeat="gadget in gadgets.subset" >
<td>
<!-- the image icon for this widget should have a css border, otherwise none -->
<div ng-class="{'image-border': gadget.initImage===widget.initImage}">
<img ng-click="gadgets.selectChart(gadget.name)" ng-src="{{gadget.initImage}}" title="{{gadget.title}}"
width="64" height="64">{{gadget.title}}
</div>
</td>
</tr>
</table>
I'm sure there's a better Angular approach to this, but I'm still trying to figure out the best use of ng-click and ng-class in this use-case.
Help is appreciated.
thanks,
Bob
I started a new plnkr http://plnkr.co/edit/w3Ojy5Eo40QHDtUxJfft
for your question.
You can use ng-clik and inject click event (and affected element) into the handler:
$scope.widgetClick = function($event) {
$event.srcElement.style.border = "2px black solid";
}
Corresponding html:
<div class="image-clicked" ng-click="widgetClick($event)"> ... </div>
For simple dom manipulation, like adding or removing a css class, its better to use angular only instead of mixing things up with jQuery.
Dealing with dom/css changes by yourself is more "jQuery way".
With Angular on the other hand, you will change the data for your model and
let the framework do the dom/css work.
For your example (using my plunkr code):
Define widget for ng-repeat as something like:
{
title : "Foobar ",
initImage : "http://lorempixel.com/10/10/",
clicked: false
}
and change clicked in the handler:
$scope.widgetClick = function(widget) {
widget.clicked = true;
};
Corresponding html:
<div ng-click="widgetClick(widget)" ng-class="{clicked: widget.clicked}">
The css class .clicked will be added by angular if widget.clicked changes to true.
Why this is better? No Css/Dom manipulation in your code. Everything clean and nice.
EDIT:
How to remove the .clicked class from previously selected widget?
We will need to keep a reference to the selected widget in the controller:
var selectedWidget = null;
$scope.widgetClick = function(w) {
if(selectedWidget) selectedWidget.clicked = false;
selectedWidget = w;
w.clicked = true;
};
Now, when another widget is selected (clicked), we only need to update the model data: Set the clicked property on the previously selected widget to false and change it to true on the selected one. And update the reference to the selectedWidget. Angular will take care about the css.
Updated plnkr http://plnkr.co/edit/IqWc1W9N12SH8K72jAun?p=preview
Try this !! cannot run angular now, but I think it should work!
< script type = "text/javascript" >
var lastobj = "";
function clickImage(obj, $event) {
debugger;
if (lastobj != obj) {
$(lastobj).css("border", "0px");
} else {
$($event.target).css("border", "2px solid red");
}
};
function clickRow(obj, $event) {
//obj should be the widget
//There you should do similar..
var imageclicked = $($event.target).data('url');
$('.propertyTable td div').css("border", "none");
$($event.target).css("border", "2px solid red");
}); < /script>
<table ng-controller="GadgetIconsCtrl as gadicons">
<tr ng-repeat="widget in gadicons.widgetSubset">
<td>
<div ng-click="clickRow(widget)" class="image-clicked">
<img data-draggable ng-click="clickImage(widget)" ng-src="{{widget.initImage}}" title="{{widget.title}}" width="64" height="64">{{widget.title}}
</div>
</td>
</tr>
</table>
EDIT
I added the unset border functionality u told, and corrected some spelling and grammar mistakes for angularjs.
Hope it works!!

Having trouble with ellipsis with angularjs

I am having issue with ellipsis and angularjs. I want to update max-width dynamically from parent as TD element width. I tried for 2 approach. One is updating dom after printing the table structure. Another is to provide directive. But nothing works.
HTML:
<table class="table data-table cvcTable sort display">
<thead>
<tr>
<th ng-repeat="column in tableOptions.columnDefs"
ng-style="{'width': column.width}"><a href
ng-click="tableEvents.sort('{{column.field}}',$event)">{{column.label}}
<i class="pull-left" ng-class="column.orderType"></i>
</a></th>
</tr>
</thead>
<tbody>
<tr ng-class-odd="'row-odd'" ng-class-even="'row-even'" ng-repeat="item in tableOptions.data">
<td>{{item.key}}</td>
<td><span title="{{item.value}}" ellipsisSpan
class="ellipsis">{{item.value}}</span></td>
<td><span title="{{item.comments}}" ellipsisSpan
class="ellipsis">{{item.comments}}</span></td>
<td>{{item.updated}}</td>
<td>{{item.updatedBy}}</td>
</tr>
</tbody>
Directive: I am not getting alert message.
app.directive('ellipsisSpan', function () {
return {
restrict: 'A',
link: function ($scope, element, attrs, ctrl) {
alert("Im inside call");
// Do calculation
}
};
});
Dynamic Call: I can see following line working perfectly but don't see updated in DOM.
"a.css('max-width', width + 'px');"
angular.element(document).ready(function () {
var element = angular.element(document.querySelector('.ellipsis'));
angular.forEach(element, function(value, key){
var a = angular.element(value);
var width = a.parent()[0].clientWidth;
a.css('max-width', width + 'px');
});
scope.$apply();
});
CSS:
.ellipsis {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
max-width: inherit;
}
Directive names get converted into dash separated case in the HTML so you need to reference your directive like this in the HTML:
<span title="{{item.value}}" ellipsis-span class="ellipsis">

Dragging a table column using HTML5 and AngularJS

http://jsfiddle.net/asutosh/82qum/
<div ng-app='myApp'>
<div ng-controller="myCtrl">
<table border="4">
<thead>
<th ng-repeat="hd in heads">
<div draganddrop drag="handleDrag()">{{hd}}</div>
</th>
</thead>
<tr ng-repeat="row in myData">
<td ng-repeat="hd in heads">
{{row[hd]}}
</td>
</tr>
</table>
</div>
Here is the JS:
var myApp=angular.module('myApp',[]);
myApp.controller('myCtrl',function($scope){
$scope.handleDrag=function()
{
}
$scope.heads=['name','age','company','tech'];
$scope.myData=[{name:'Jay',age:27,company:'XYZ',tech:'Js'},
{ name:'Rayn',age:30,company:'XYZ',tech:'.net'}]
});
myApp.directive('draganddrop',function(){
return{
scope:{
drag:'&'
},
link: function(scope, element) {
// this gives us the native JS object
var el = element[0];
el.draggable=true;
el.addEventListener(
'dragstart',
function(e) {
e.dataTransfer.effectAllowed = 'move';
// this.classList.add('drag');
return false;
},
false
);
el.addEventListener(
'dragend',
function(e) {
this.classList.remove('drag');
return false;
},
false
);
}
};
});
In the above fiddle I want to create a table having column reordering, I am able to set the column header to draggable however while dragging only the header's image is getting dragged, I want the the image of the whole column should come as the dragging image, any suggestion on that will be helpful.
The following solution works with Chrome's latest version, and this solution is implemented using AngularJS 1.4 version:
The change in the code is:
var headerElem=e.target.closest('th');
var textOfHeader=angular.element(headerElem).find("a");
scope.$apply(function() {
scope[dropfn](data, textOfHeader[0]);
});
http://plnkr.co/VDygHR
If you want to use a plugin instead of implementing it yourself you can choose from:
http://ng-table.com/
http://ui-grid.info/
http://lorenzofox3.github.io/smart-table-website/
http://ekokotov.github.io/object-table/
They all support column reorder and a lot of other features, I believe there are a lot of other solutions around.
http://jsfiddle.net/asutosh/82qum/142/
Following is HTML Code:
<div ng-app='myApp'>
<div ng-controller="myCtrl">
<table ng-hide={{dragStart}} id="hidtable" border="4" >
<thead>
<th>{{dragHead}}</th>
</thead>
<tr ng-repeat="row in myData">
<td>{{row[dragHead]}}</td>
</tr>
</table>
<div class='dragstyle' id="coverup"></div>
<table border="4">
<thead>
<th ng-repeat="hd in heads">
<div draganddrop drag="handleDrag">{{hd}}</div>
</th>
</thead>
<tr ng-repeat="row in myData">
<td ng-repeat="hd in heads">
{{row[hd]}}
</td>
</tr>
</table>
</div>
</div>
Following is the CSS:
.dragstyle{
background: white;
width:200px;
color:white;
height: 100px;
position: absolute;
top: 0;
right: 0;
z-index: 2;
}
#hidtable{
height: 100px;
position: absolute;
top: 0;
right: 0;
z-index: 2;
}
Following is the JS:
var myApp=angular.module('myApp',[]);
myApp.controller('myCtrl',function($scope){
$scope.handleDrag=function(columnName)
{
$scope.dragHead=columnName;
};
$scope.dragHead='name';
$scope.heads=['name','age','company','tech'];
$scope.myData=[{name:'Jay',age:27,company:'XYZ',tech:'Js'},
{name:'Rayn',age:30,company:'XYZ',tech:'.net'}]
});
myApp.directive('draganddrop',function(){
return{
scope:{
drag:'='
},
link: function(scope, element,attrs) {
var el = element[0];
el.draggable=true;
el.addEventListener(
'dragstart',
function(e) {
e.dataTransfer.effectAllowed = 'move';
var columnName=e.target.innerHTML;
scope.$apply(function(self){
console.log(self);
scope.drag(columnName);
});
e.dataTransfer.setDragImage(document.getElementById('hidtable'), 0, 0);
;
return false;
},
false
);
el.addEventListener(
'dragend',
function(e) {
this.classList.remove('drag');
return false;
},
false
);
}
};
});
So this way I have created a box with width of 200px and having background color as white, under that the 'hidetable' element is present, so it's visible to the browser but not to the user.
When the drag event occurs at any column head element, the 'hidetable' element is set as the drag image.
This drag'n'drop library will do it for you:
https://github.com/lorenzofox3/lrDragNDrop
Just include it in your app, and make your <th> say this:
<th lr-drag-src="headers" lr-drop-target="headers" ng-repeat="hd in heads" >

Resources