Fixed header for UI5 Smart Table
In SAPUI5 application we often use sap.m.table
instance directly or via the sap.ui.comp.smarttable.SmartTable
.
One of the problems is how to keep the header toolbar and table’s header on top when we do scrolling.
In the following picture you can see what happen when we scrolling in the worklist table which has a smart table and a sap.m.table
as its including instance table.
But what we expect is to have the both custom toolbar and table’s header on top while scrolling.
Since version 1.54 of the SAPUI5 you can use the sticky attribute of the sap.m.table
and then keep the header of the table on top. At the moment this attribute only accept 2 values.
- sap.m.Sticky.ColumnHeaders which only keeps the column headers in a fixed position
- sap.m.Sticky.None
Thus if we define a sap.m.table
instance like the following:
<m:Table id="table" mode="MultiSelect" sticky="ColumnHeaders">
....
</m:Table>
Then we will have something like this when scrolling:
Fine, it is better than previous that we had no header on top. But still if user wants to use the buttons inside of the toolbar need to scroll down, then select the row(s) and then scroll up to use the buttons inside of the toolbar.
Let’s take a deeper look on what has been added to our html dom elements when we use this attribute:
Actually one css class which is called sapMListTblStickyColHdr
has been added to the header of the table. And in the css part we have these:
.sapMListTblStickyColHdr, html[data-sap-ui-browser^='cr']
.sapMListTblStickyColHdr>.sapMTableTH {
position: sticky;
position: -webkit-sticky;
top: 0;
z-index: 100;
}
So we can use the same idea to keep the custom toolbar of our smartTable
on top. Then let’s add some custom css and add a custom css class to our custom toolbar:
<smartTable:customToolbar>
<m:OverflowToolbar id="stickyToolbar" design="Solid" class="stickyToolbar">
<m:ToolbarSpacer/>
<m:SearchField id="searchField" tooltip="Search" width="auto" search="onSearch" liveChange="onSearchLiveChange"/>
<m:Button type="Transparent" press="onCreateBtnPress" icon="sap-icon://add" tooltip="Add"/>
<m:Button type="Transparent" press="onDeleteBtnPress" icon="sap-icon://delete" tooltip="Delete"/>
</m:OverflowToolbar>
</smartTable:customToolbar>
And the custom css which is normally placed inside of the style.css file must have:
.stickyToolbar {
position: sticky;
position: -webkit-sticky;
top: 0;
z-index: 101;
}
Please note that we assigned the z-index
to 101
(one value more than what we saw in sapMListTblStickyColHdr class).
But still it does not work, and the reason is that the class has been assigned to a deeper dom element. While if we assign it to its parent all would work.
So we will use the onAfterRendering
event of the smart table to assign the css class to toolbar’s parent. If you noticed, we assigned one id to our custom toolbar then we will use that id to retrieve it.
// This function must be bound to the view's afterRendering event
onAfterRendering: function() {
// Stick the toolbar and header of the smart table to top.
var oSmartTable = this.byId("__smartTableWorklist");
oSmartTable.onAfterRendering = function() {
var oToolbar = this.byId("stickyToolbar"),
oParent = oToolbar.$().parent();
if (oParent) {
oParent.addClass("stickyToolbar");
}
}.bind(this);
},
As you can see in the above code we found the parent dom element of our custom toolbar. (In the previous figure it is a div with “__data28” as its id). Here is the result:
OK, not bad. But now we have another problem. We could keep the custom toolbar on top but as it is seen the header is going to be hide under the custom toolbar as soon as we scroll (The yellow highlight in the above picture). The reason is because of top
property of the table’s header. Actually it will also stay on top but under the custom toolbar as it has smaller z-index
. If you want to see it, just change the z-index
of the stickyToolbar
to some value smaller than 100. You can see the result of this change here:
Yeah, you can see now the table’s header move to places on top to 0 point in Y-axel.
Let’s return the z-index
to 101 again. We have to actually set the top
property of the table’s header to a value equal to the outer height of the custom toolbar in runtime.
For this, we simply remove the sticky property of the sap.m.table
instance and then will generate a custom css in runtime and assign it in the afterRendering
event of the table. Here are the steps:
- Remove the sticky property from table instance:
<m:Table id="table" mode="MultiSelect">
- Change the
afterRendering
method of the view like this:onAfterRendering: function() { // Stick the toolbar and header of the smart table to top. var oSmartTable = this.byId("__smartTableWorklist"); oSmartTable.onAfterRendering = function() { var oToolbar = this.byId("stickyToolbar"), oParent = oToolbar.$().parent(); if (oParent) { oParent.addClass("cimtStickyToolbar"); } }.bind(this); // This is new code to make the table's header also sticky var oTable = this.byId("table"); oTable.onAfterRendering = function() { oTable.addStyleClass("cimtStickyTableMSW"); var oToolbar = this.byId("stickyToolbar"), iTop = oToolbar.$().outerHeight(); if ($("head").find("style#cimtStickyTableMSW").length !== 0) { $("head").find("style#cimtStickyTableMSW").remove(); } var style = $("<style id='cimtStickyTableMSW'></style>"); $(style).html(" .cimtStickyTableMSW > table > thead > tr," + ".cimtStickyTableMSW > table > thead > tr > th {" + " position: sticky;" + " position: -webkit-sticky;" + " top: " + iTop + "px;" + " z-index: 100;" + "}"); $("head").prepend(style); //eslint-disable-line }.bind(this); }, // end of afterRendering handler of the view.
As you have seen, here we added a new style
element on runtime to the head
tag of the page. I know it is not recommended but it is the best place to add the style
tag, to be able to remove it for the next times that we need to change the top
attribute based on another rendering situation (the height of the custom toolbar can be vary).
And here is the final result:
I hope you find this post useful.
Mahdi, that’s a nice one. Thanks! I hope to meet you in June…
Thanks Nabi. I hope to.
Hi
This is method work in Chrome, but not in IE.
How fixed head in IE ?
Hi Ivan. Thanks for the comment. You can find your answer here.
Shortly the answer is:
But please take care the suggested solution cannot work because top:0 is assumed the top of the browser and not the container div.
I understand, Thanks for the answer.
Hi,
I am using a custom toolbar. It is getting fixed along with the table header until scrolling for 6-7 rows but is toolbar is not sticking at the top after that. Header remains fixed at the height = top + toolbar height.
PFA screenshot.
Hello,
Please ignore my previous issue. I found the solution. I am using sap.m.page and the overflow property was causing the issue. Putting smart table in VBox solved the issue.
Hi Arush,
How did you overcome this? I am also facing same issue.
Can you please share code?
Hi,
Now sticky has multiple options like InfoToolbar, ColumnHeaders and HeaderToolbar. So if we want to header and toolbar fixed, we can simply achieve it by:
<Table sticky="ColumnHeaders,HeaderToolbar" />
Thanks,
Arpit
custom toolbar can't be made sticky with HeaderToolbar
Hi,
Can we also have Fixed footer as well. If there is Use Case, where the Customer wants to print products, if the no products exceeds come to next page- this next page should also have same fixed header and footer. Can we achieve this?
Thanks and Regards,
RR
Since ui5 version 1.56 there is property placeToolbarInTable at SmartTable which helps to achieve sticky custom toolbar while responsive table scrolling
In case if someone has declared table inside a smartTable with a customToolBar,then use placeToolbarInTable=”true” property at smartTable and sticky=”ColumnHeaders,HeaderToolbar” at inside table to make the both header and customToolBar sticky.
it worked !! Thanks
Among all, your solution is the best. Thanks. Exactly what i needed