How can I apply Angular and UI-Sortable with to table cells without awkward spacing? - css

I want a table sortable by column using Angular UI-Sortable. When there are multiple rows in the table, the spacing gets confused. I think this is because the dragged cell and the placeholder are taking up space, even though the dragged cell is absolutely positioned.
My table looks like this:
<table>
<thead>
<tr ui-sortable="{'ui-floating': true, axis: 'x'}" ng-model="list">
<th ng-repeat="item in list">
{{item.text}}
</th>
</tr>
</thead>
<tbody>
<tr>
<td ng-repeat="item in list">
{{item.text}}
</td>
</tr>
</tbody>
</table>
and my controller looks like this:
var myapp = angular.module('sortableApp', ['ui.sortable']);
myapp.controller('sortableController', function($scope) {
var tmpList = [];
for (var i = 1; i <= 6; i++) {
tmpList.push({
text: 'Item ' + i,
value: i
});
}
$scope.list = tmpList;
});
I also have an example on codepen. Try dragging the first cell to see the rest of the row shift down past the end of the table.
I'm running Angular v1.4.9 and angular-ui-sortable v0.14.0.

I figured out a workaround. By adding an empty cell to each row, and adding ng-show to the first one, I get a cell to remove when the placeholder is added. This works pretty well, but the empty cell does take up a little space, and it makes the html a little less clear.
Updated codepen here: http://codepen.io/anon/pen/mPZBxq

Related

How to hide menu option of first table after right click on second table using p-contextMenu and p-table?

I have a p-table and p-contextMenu which gives me right click options on the table. When I right click on a row of first table I am able to view my right click options. When I right click on a row of second table I am able to view my right click options, but not able to hide the menu for first table.
As seen in the image when I right click on second table, first table right click option still remains.
https://i.stack.imgur.com/FtybH.jpg
Data-Table-Component.html
<p-contextMenu #cm [model]="items" appendTo="body"></p-contextMenu>
<p-table [columns]="columns" [value]="tradeList" [(contextMenuSelection)]="selectedProduct"
[contextMenu]="cm" dataKey="id" [rowHover]=true styleClass="p-datatable-striped p-
datatable-responsive-demo"
selectionMode="multiple" [(selection)]="selectedTrade">
<ng-template pTemplate="header" let-columns>
<tr>
<th pSortableColumn *ngFor="let col of getKeys(columns)" pReorderableColumn
pResizableColumn> {{col}}
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-block let-columns="columns" let-
rowIndex="rowIndex">
<tr [pContextMenuRow]="block" [pSelectableRow]="block"
[pSelectableRowIndex]="rowIndex">
<td *ngFor="let col of getKeys(columns)" (click)=fetchDataArray(block)>
{{block[col]}}
</td>
</tr>
</ng-template>
Data-Table-Component.ts
ngOnInit(): void{
this.items=[
{label: 'Option 1',icon:'pi pi-user-edit'},
{label: 'Option 2',icon:'pi pi-user-edit'},
{label: 'Option 3',icon:'pi pi-user-edit'},
{label: 'Option 4',icon:'pi pi-user-edit'},
{label: 'Option 5',icon:'pi pi-user-edit'},
];
}
On click of a row of first table fetchDataArray function is called by which second table data is being fetched.
In ComponentBox file, I am calling the p-table which has been declared and passing the values as required for the tables.
Component-Box.html
<ng-template #tabdata>
<p-scrollPanel [style]="{width: '100%', height: '100%'}"
<app-data-table [tradeList]="data" [selectedEntity]="entity"
[entityData]="entityData"
(selectedTradeEvent)="fetchData($event)"></app-data-table>
// This gives us first table data and on click event which is
//selectedTradeEvent is called click of a row to fetch data for second
//table.
</p-scrollPanel>
<p-scrollPanel [style]="{width: '100%', height: '100%'}"
<app-data-table [tradeList]="table.value" [selectedEntity]="table.key"
[entityData]="entityData"> </app-data-table>
// This gives us second table data
</p-scrollPanel>
</ng-template>
Component-Box.ts file-
fetchDataArray(selectedItem){
this.entityData[this.entity]["showTables"].forEach(val=>{
this.service.sendGetRequest('getData?id='+selectedItem).then(data=>
{
this.showTables.set("ABC",data);
});
});
}
I had similar problem where I had one contextmenu on p-table and second one on openlayer map (some div), and when opening first one then second one both are showed on screen. This is how I solved my problem... I already had functions to show context menu (because I had to position them where I wanted), so when opening one of contextmenu's I explicitly call hide on other one...
here is code:
<p-contextMenu #cmMap [ngStyle]="{'position':'absolute', 'z-index':'10000', 'top':mapContextMenuY+'px', 'left':mapContextMenuX+'px'}" [model]="mapContextMenuItems"></p-contextMenu>
<p-contextMenu #cmTab [ngStyle]="{'position':'absolute', 'z-index':'10000', 'top':tabContextMenuY+'px', 'left':tabContextMenuX+'px'}" [model]="tabContextMenuItems"></p-contextMenu>
...
#ViewChild('cmMap') cmMap: ContextMenu;
#ViewChild('cmTab') cmTab: ContextMenu;
...
openCmTableRow(event: PointerEvent, cm: ContextMenu, row: IClipboard) {
console.log(row);
this.clipboardGeometrija = row;
const tableHolderRect: DOMRect = this.leftSidebar.nativeElement.getBoundingClientRect();
this.tabContextMenuX = event.x - tableHolderRect.x;
this.tabContextMenuY = event.y - tableHolderRect.y;
cm.show();
this.cmMap.hide();
}
openCmMap(event: PointerEvent, cm: ContextMenu) {
const kartaRect: DOMRect = this.karta.nativeElement.getBoundingClientRect();
this.mapContextMenuX = event.x - kartaRect.x;
this.mapContextMenuY = event.y - kartaRect.y;
cm.show();
this.cmTab.hide();
}
i had the same issue when append the menu to body inside a table and have multiple menu what i did is:
previusMenu:any;
toggleMenu(menu, items, event, rowData) {
//hide previous menu
this.previusMenu?.hide();
this.selectedTaxActionsModel = //add your items;
this.previusMenu=menu;
menu.toggle(event);
}
<button type="button" pButton icon="pi pi-fw pi-cog" (click)="toggleMenu(menu, col.items, $event, rowData); $event.stopPropagation()"></button>
<p-menu #menu [popup]="true" appendTo="datatable" [model]="selectedTaxActionsModel"></p-menu>

Adjusting custom view in Fullcalendar by Adam Shaw

I've followed the outlines in FullCalendar Change Week View to Vertical List instead of Horizontal Table Columns to create a custom vertical week view in fullcalendar.
The implementation is taken from the original post shown in this fiddle: http://jsfiddle.net/nomatteus/dVGN2/3/
This lays out the view like this:
<table>
<thead>
.tr.td.headercontent....
</thead>
<tbody>
.tr.td.eventcontent....
</tbody>
</table>
However the vertWeek view is used on small screens (smartphones etc), so I would like to have the day header and content to be layed out horizontal to take up less space in height like in this screenshot:
http://i.imgur.com/F4AkoSw.png
The MAN 8. is styled manually as I like it, but TIR 9 is how it is rendered by the view.
I would like to achieve this:
<table>
<thead>
</thead>
<tbody>
<tr>
<td> headercontent
<td> eventcontent
</tr>
</tbody>
</table>
I have tried to understand the fullcalendar code to move the header into the same as the eventcontent - but it seems like the view is rendered in different places for thead and tbody for that container.
Could anyone point me in the right direction on how to modify the code to achieve this?
Post of implemented answer for sharing:
Seems like my understandig was a litte bit inaccurate. The header was placed in an overlapping table above the table containing the events. Tried to traverse the DOM and place the header during the dayRender function, but the corresponding tbody for the event was not yet created.
Simplified illustration:
table
thead
**header**
tbody
table
thead
tbody (not created at dayRender, but available at eventRender)
**event*
The solution was quite simple - hide the .fc-day-number:
dayRender: function( date, cell ) {
// Get the current view
var view = $('#meal_calendar').fullCalendar('getView');
// Check if the view is the new vertWeek -
// in case you want to use different views you don't want to mess with all of them
if (view.name == 'vertWeek') {
// Hide the widget header - looks wierd otherwise
$('.fc-widget-header').hide();
// Remove the default day number with an empty space. Keeps the right height according to your font.
//$('.fc-day-number').html('<div class="fc-vertweek-day"> </div>');
$('.fc-day-number').hide();
// Create a new date string to put in place
var this_date = date.format('ddd, MMM Do');
// Place the new date into the cell header.
cell.append('<div class="fc-vertweek-header"><div class="fc-vertweek-day">'+this_date+'</div></div>');
}
},
In addition I styled the td.fc-event-container in my CSS like this:
td.fc-event-container {
padding-left: 68px;
}
Quite possibly a hack - hours to research, two lines to correct. But works for me......

Table columns with relative size in HTML5

I have a table with four columns. The first column needs to be the minimum size to fit the content, and the other three columns need to be equal sizes and consume the rest of the space in the table. Neither my table nor my content is of a known size. (It's a pretty standard variable-sized-label-and-fixed-size-data layout.)
In the good old days of HTML4 I could do this by using the specifying the size of each column as a proportion of the whole, using the 'relative size' functionality:
<colgroup>
<col width="0*"/>
<col width="1*"/>
<col width="1*"/>
<col width="1*"/>
</colgroup>
However, the width attribute is now deprecated and we're supposed to use CSS instead.
But I haven't found any way to replicate this with CSS; CSS size specifiers only let me specify the width as either a fixed size or a fraction of the whole, where what I actually need is a fraction of what's left after the first column is taken away.
Is there any way to do this using modern techniques? (Note that I can't use CSS3, though.)
I would use a little javascript in order to solve your problem: http://jsfiddle.net/qR9g2/
var tableSize = 400; // example of size
var firstCol = document.getElementById('firstCol_01');
var sizeOfFirstCol = firstCol.offsetWidth;
var myOtherCols = document.getElementsByTagName('td');
var nbcols = myOtherCols.length;
var sizeOtherCols = (tableSize-sizeOfFirstCol)/(nbcols-1);
for(var i=0;i<nbcols; i++)
{
if(myOtherCols[i].className === 'otherCols')
{
myOtherCols[i].style.width = sizeOtherCols+'px';
}
}
first give the size of the overall table. Then go get the size of the first column, and distribute the rest of the width to the other columns.
EDIT: here is a CSS solution. It is not perfect, but better than nothing: http://jsfiddle.net/qR9g2/2/
In the css, the main idea is the following:
.col1{
display:table;
float:right;
}
Add for the first column the tag display:table. This will work like a fit-content for all browsers.
Adding a float:right will push the first column onto the right and "stick" it to the rest of the table.
The visual result is exactly what you want. On the negative side, the problem is that your table takes more place then it seems (on the left). (basically if you have a 400px table with 4 columns, it will automatically give 4*100px for each column. adding the upper CSS solution will simply shift the col1 on the right side of the 100px that are given to that column).
You could always try to play with negative left-margins (i don't recommend) in order to shift your table on the left.
var table = document.getElementById('table');
var first_col = document.getElementById('first-col');
var total_col = document.getElementsByClassName('col').length
var rem_width = table.offsetWidth - first_col.offsetWidth;
var col = document.getElementsByClassName('col')
for(let i=0;i<col.length;i++){
col[i].style.width=rem_width/total_col+'px'
}
<table id="table" width="100%" border="1">
<tr>
<th id="first-col">NO</th>
<th class="col">ISBN</th>
<th class="col">Title</th>
<th class="col">Price</th>
</tr>
<tr>
<td>12</td>
<td>3476896</td>
<td>My first HTML</td>
<td>$53</td>
</tr>
</table>
Instead of trying to do a table, you can try a grid layout as follows.
Apologies for the inline css - obviously you would use classes instead but I just tested it quickly and it actually appears to work! I had not actually ever used this before, but making the first column "auto" actually does work and the layout is I think what you are looking for.
<div style="display:grid; grid-template-columns: auto repeat(3, 1fr);">
<div style="width: fit-content">This should fit the content that you decide to insert here</div>
<div>This should fit the content too</div>
<div>This should fit the content .. more text</div>
<div>This should fit the content and some more text</div>
</div>
I checked & grid has been around since 2011 so it's not too modern hopefully. I almost always do my tables with either grid or flexbox now..

Breakable table row in HTML

Is there a way to make a table row breakable at a certain cell?
<table>
<tr>
<td>Some title descriptive text</td>
<td>nnumbers</td><td>Short text</td><td>datetime</td>
<tr>
... more rows
</table>
Now I would like this row to break after the first cell if the width of the viewport is too small (typically when used on mobile phones).
Is that achievable anyhow using html5 css3 and eventually some Javascript?
As of CSS2.1, it is possible by using appropriate display CSS attribute values. See this demo page:
http://dabblet.com/result/gist/1576044
...and the source:
http://dabblet.com/gist/1576044
Tested on a Galaxy Nexus phone, works, and should work for most Webkit-based mobile browsers. Also, it should work on Firefox Mobile and Opera, though I didn't test.
Long story short, use a media query to detect page width and set a max-width breakpoint and apply:
css
table, tbody, thead, tr, td, th { display: block }
No. Table rows cannot be broken onto multiple lines. That'd imply you want TWO rows of cells instead of a single.
I needed something just like this for a project of mine; i needed to support old browsers so it doesn't use HTML5, just javascript to check the overall width/amount of rows able to handle:
http://pastebin.com/raw.php?i=umFWx3mK (Just copy it inside an HTML file and open it with a browser)
$(window).resize(distribute)
$(document).ready(function(){
allboxes = $(".box");
$('#container').delegate(".box","mouseenter",function(){
$(this).addClass('current')
}).delegate(".box","mouseleave",function(){
$(this).removeClass('current')
});
table = $("#table");
distribute();
})
var lastfit, allboxes, table
function distribute(){
var fitAmount = Math.floor($("#container").width()/180);
if(lastfit!=fitAmount){
if(fitAmount<1){fitAmount=1}
lastfit = fitAmount;
var clones = allboxes.clone(),
emptycells = "", emptyrows = "",
trs = table.find("tr");
for(var i=0;i<fitAmount;i++){
emptycells += "<td> </td>";
}
trs.html(emptycells)
var count = trs.length*fitAmount
if(count < allboxes.length){
var newRows = Math.ceil((allboxes.length - count)/fitAmount);
for(var j=0;j<newRows;j++){
emptyrows += "<tr>"+emptycells+"</tr>";
}
}
table.append(emptyrows)
var tds = table.find("td"), trs = table.find("tr");
clones.each(function(index){
tds.eq(index).html("").append($(this))
})
allboxes = $(".box");
trs.filter(function(){ return !/box/gi.test(this.innerHTML) }).remove()
}
}
function boxmouseover(box){
$(box).css("background","red")
}
function boxmouseout(box){
$(box).css("background","#CCC")
}

Is it possible to change the position of generated <tr> by css?

Some asp.net controls generate , so to customize its appearance (e.g. childview in grid) i need to change the position of < tr> content. I don't know any ways to change position. The only idea is to generate div wrappers by javascript. Does anybody know a better way?
if you want to "move" the tr to another place, you can try:
<table>
<tr id="tr1"><td>test</td><td>test2</td></tr>
<tr id="tr2"><td>test3</td><td>test4</td></tr>
<tr id="tr3"><td>test4</td><td>test5</td></tr>
</body>
<script>
var tr = document.getElementById("tr2");
tr.style.display = 'block';
tr.style.position = 'absolute';
tr.style.top = "100px";
tr.style.left = "100px";
</script>
it definitely works in firefox (dont know about ie6-8). If you want to exchange the content with another tr, thats even easier (you just remove/add the tr nodes).

Resources