Display footer in PrimeFaces template, when fullPage of p:layout is set to false

12,496

Solution 1

To easily visualize what you ultimately need (and to confirm your needs for myself), here's in SSCCE flavor a pure HTML/CSS solution of what you're (apparently) asking for. The sticky footer solution is largely based on Ryan Fait's approach (a min-height:100% and a negative margin on the container element which covers everything but footer), it only doesn't support IE6/7 anymore (due to :after pseudoselector), hereby simplifying the HTML markup (no non-semantic clutter like <div id="pushfooter"> needed). Note: background colors are purely for visualization.

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Stack Overflow Question 22584920</title>
        <style>
            html, body {
                height: 100%;
                min-width: 800px;
                margin: 0;
            }
            #container {
                min-height: 100%;
                margin: 0 auto -90px; /* Negative of #footer.height */
            }
            #header {
                height: 135px;
                background: pink;
            }
            #menu {
                float: left;
                width: 225px;
                background: khaki;
            }
            #content {
                margin-left: 225px; /* Same as #menu.width */
                margin-right: 175px; /* Same as #side.width */
                background: lemonchiffon;
                padding: 1px 1em; /* Fixes collapsing margin of p's on div, feel free to remove it */
            }
            #side {
                float: right;
                width: 175px;
                background: palegreen;
            }
            #footer, #container:after {
                height: 90px;
            }
            #footer {
                background: orange;
            }
            .clearfix:after {
                display: block;
                content: " ";
                clear: both;
            }
        </style>
    </head>
    <body>
        <div id="container" class="clearfix">
            <div id="header">Header</div>
            <div id="menu">Menu</div>
            <div id="side">Side</div>
            <div id="content">
                <p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>
            </div>
        </div>
        <div id="footer">Footer</div>
    </body>
</html>

Note: due to the way how floats work, the <div id="side"> (the "east unit") has in the HTML markup to be placed before all non-floating elements at the same "row", such as the <div id="content"> (the "center unit"), otherwise it will be aligned relative to the bottom of the last non-floating element.

Now, in order to achieve exactly the same with the <p:layout> thing, which basically renders almost the same HTML structure, only with the footer still inside the container and the east unit after the center unit, you need to make sure that no one of the layout units are collapsible/closable/resizable (those attributes all already default to false and can thus be omitted for brevity) and that you apply the PrimeFaces-builtin clearfix style class ui-helper-clearfix on the container unit to clear the floats (otherwise the menu, content and side would overlap the footer when the screen is shrunk vertically):

<p:layout styleClass="ui-helper-clearfix">
    <p:layoutUnit position="north" size="135">
        <p>Header</p>
    </p:layoutUnit>
    <p:layoutUnit position="west" size="225" header="Menu Item">
        <p>Menu</p>
    </p:layoutUnit>
    <p:layoutUnit position="center">
        <p>Content</p>
        <p>Content</p>
        <p>Content</p>
        <p>Content</p>
        <p>Content</p>
    </p:layoutUnit>
    <p:layoutUnit position="east" size="175">
        <p>Side</p>
    </p:layoutUnit>
    <p:layoutUnit position="south" size="90">
        <p>Footer</p>
    </p:layoutUnit>
</p:layout>

Then you can apply the following CSS in your PrimeFaces-override stylesheet to remove/override all "irrelevant" PrimeFaces-generated CSS properties on those layout units by setting the absolute positioning with fixed offsets/dimensions back to initial/default values (note: the exact purpose of !important is being able to override hardcoded/inline style properties from a true stylesheet on, there's in this particular case simply no other option as long as you don't want to rewrite PrimeFaces components and renderers). Key point is that you should end up with exactly the same HTML/CSS (defaults) as the SSCCE:

html, body {
    height: 100%;
    min-width: 800px;
    margin: 0;
}
.ui-layout-container {
    min-height: 100%;
    height: auto !important;
    margin: 5px;
    margin-bottom: -90px; /* Negative of footer height. */
}
.ui-layout-unit {
    position: static !important;
    top: auto !important;
    bottom: auto !important;
    left: auto !important;
    right: auto !important;
    height: auto !important;
}
.ui-layout-unit-content {
    display: block !important;
    height: auto !important;
}
.ui-layout-west {
    float: left;
    margin: 5px 0 !important;
}
.ui-layout-center {
    margin: 5px 0 !important;
    margin-left: 230px !important; /* Menu width plus margin between panels. */
    margin-right: 180px !important; /* Side width plus margin between panels. */
}
.ui-layout-east {
    float: right;
    margin: 5px 0 !important;
}
.ui-layout-container:after {
    height: 85px; /* Footer height minus margin between panels. */
}
.ui-layout-south {
    margin: 5px !important;
    visibility: visible !important;
}

And finally add the following script in order to move the side (east unit) before the content (center unit), so that the floats go as intented, and to move the footer to end of body, so that it's outside the container element:

$(function() { 
    $(".ui-layout-east").insertBefore(".ui-layout-center");
    $(".ui-layout-south").appendTo("body");
});

Make sure that this script is re-executed when you do an ajax update with @all on the same view for some reason (which is at its own a bad idea though).

With this "solution" (I'd rather call it a hack and just throw it all away and go for a sane and clean HTML/CSS solution, if necessary with <p:panel>s instead of <div>s), it's still somewhat brittle; the auto-included layout.js script auto-adjusts the layout units on every window resize. But so far they don't seem to break anything in all modern browsers I tried (IE>8).

Solution 2

This may or may not be a bug in PrimeFaces - you're best off asking there. The layout is actually on your page if you check the source, however its positioning is above the header, likely because it has no idea where it's to be. In a full page it knows its location generated by the page, but otherwise it could be anywhere you want it to be. Try using CSS to move it etc, refer to. and use styleClass etc to attach classes, my hack was just to use !important which you shouldn't really do.

.ui-layout-pane-south {
    top: 200px !important;
}

etc..

Although I am more inclined to think this is a bug as none of the CSS is applied properly to it.

I've created an issue report on PF and hopefully someone can give some more information on the problem.

Solution 3

To ensure that the layout DIV has a relative height :

1_ Every components between the BODY and the layout must have a relative height, witch should be 100%.

2_ Always use DIV instead of SPAN between the BODY and your layout (no inline elements).

exemple :

<body>
<h:panelGroup layout="block***important***" style="height:100%" >
    <pe:layout widgetVar="pageLayoutWV" fullPage="false" style="height:100%" > 
    </pe:layout>
</h:panelGroup>
</body>

In case, it dosent work add this code to your page, (i fixed a long time ago but its probably has a relationship with your problem) :

function BaseWidgetInit(cpn, cfg) {
    cpn.cfg = cfg;
    cpn.id = cfg.id;
    cpn.jqId = PrimeFaces.escapeClientId(cpn.id),
    cpn.jq = $(cpn.jqId);           
    //remove script tag
    $(cpn.jqId + '_s').remove();
}   
if (PrimeFaces.widget.Layout)
PrimeFaces.widget.Layout = PrimeFaces.widget.Layout.extend({
    init: function(cfg) {
        BaseWidgetInit(this, cfg);        
        this.cfg = cfg;
        this.id = this.cfg.id;
        this.jqId = PrimeFaces.escapeClientId(this.id);
        if(this.cfg.full) {                                                 //full
            this.jq = $('body');
        } else if(this.cfg.parent) {                                        //nested
            this.jq = $(PrimeFaces.escapeClientId(this.cfg.parent));
        } else {                                                            //element
            this.jq = $(this.jqId);
            this.jq.css('height', $(window).height()-10);
        }        
        var _self = this;
        $(this.jq).data("layoutContainer", null);
        $(this.jq).data("layout", null);
        if(this.jq.is(':visible')) {
            this.render();
        } 
        else {
            var hiddenParent = this.jq.parents('.ui-hidden-container:first'),
            hiddenParentWidget = hiddenParent.data('widget');

            if(hiddenParentWidget && hiddenParentWidget.addOnshowHandler) {
                hiddenParentWidget.addOnshowHandler(function() {  
                    return _self.render();
                });
            }
        }
    }
});

i also suggest you, to use the layout of PF Extention library, its more stable, a working template can be found here erp.agitech.net admin/pass

Solution 4

Apparently <p:layout> requires an appropriate height, when fullPage is set to false. The height is required to display the footer at appropriate position (it should position at the bottom of the browser window) like,

<p:layout fullPage="false" style="height: 2000px;">

Learnt from PrimeFaces Extensions <pe:layout> which fails to work with the following error in JavaScript alert box on page load,

/ UI Layout Initialization Warning The layout-container "DIV#mainForm:fullPage" has no height. Therefore the layout is 0-height and hence 'invisible'!

if fullPage of <pe:layout> is set to false and height is not defined. For it to work appropriately, it needs an appropriate height like as follows.

<pe:layout id="fullPage" 
           fullPage="false" 
           style="height: 2000px;" 
           stateCookie="true">

It is difficult to tell whether it is deliberate or intentional.


It would be delightful, if someone could expose how to adjust the footer according to the page contents, a sticky footer.

Share:
12,496
Tiny
Author by

Tiny

Just an orphan kid and have no more to say. Three things in general, cannot be avoided (at least I can never) Mother Mother-tongue Mother-land. They are always unique. I'm a family-less boy. My family was hunted leaving me all alone when my house targeted and deliberately set on a fire by a mob during a nonsense communal riot but I was survived by a rescue team with the help of firemen. As a survival, I didn't know whether it was my fortune or misfortune but when I recovered, the rescue team came to my home, one day. One of the members gave me a piece of paper in my hand in which the following text was written. lifeisnowhere. He asked me to read it carefully and I could hardly interpret the text as Life is now here, instead of Life is nowhere. All of them gave me a cute smile and went away and I decided to live peacefully and hopefully on their saying from then onwards and very soon. Because of this tragedy, I'm alone couldn't join a school but a curiosity to learn something made me a self-learner. I'm indeed a self-learner, so I'm likely not able to answer any questions on this site right now. In the field of computer science, my self-study mainly includes, QBASIC, C, C++, C#, VB, Java, JavaScript, PHP and a little about ASP.NET. Oracle, MySQL and MSSQL-Server with DBMS. and other theoretical subjects. I'm currently dealing with - Android and Java EE including Servlet, JSP-JSTL/EL (with Spring and Struts with ORM models JPA/Hibernate) and JSF.

Updated on June 27, 2022

Comments

  • Tiny
    Tiny almost 2 years

    Footer is not displayed (actually, it is incorrectly displayed on top of the page), when fullPage is set to false in PrimeFaces template.

    <p:layout fullPage="false">
        <p:layoutUnit position="north" size="135">
            <!--Put north content here, if any-->
        </p:layoutUnit>
    
        <p:layoutUnit position="west" size="225" header="Menu Item" collapsible="true">
            <!--Put west content here, if any-->
        </p:layoutUnit>
    
        <p:layoutUnit position="center" size="2500" maxSize="2500">
            <!--Put center content here, if any-->
        </p:layoutUnit>
    
        <p:layoutUnit position="east" size="175">
            <!--Put east content here, if any-->
        </p:layoutUnit>
    
        <p:layoutUnit position="south" size="90">
            <!--Put south/footer content here, if any-->
        </p:layoutUnit>
    </p:layout>
    

    How to display footer, when fullpage is set to false?


    EDIT :

    if <p:layout> is given a height like as follows,

    <p:layout fullPage="false" style="height: 2000px;">
    

    then the footer is displayed at the bottom of the page based on the value of the height CSS attribute but it is still not a sticky footer - it does not adjust according to the page contents.

    So, Is there a way to make it sticky?


    Update :

    The behaviour remains stationary on PrimeFaces 5.3 final (community release), when fullPage is set to false as said previously throughout the question.

  • Tiny
    Tiny about 10 years
    What CSS can we apply so that the footer positions automatically according to the contents (it should position immediately below the contents no matter how much contents we display/load on the page)?
  • VeenarM
    VeenarM about 10 years
    I don't know, I know enough CSS to get me by, that's someone elses job :) As I mentioned it seems like an oversight and likely you may prefer to use use fullPage="true" for now. I will reponsd back with what ever I get from the IssueTracker on Primefaces website.
  • Tiny
    Tiny about 10 years
    Just to clarify : This is not an actual answer that can suit the real requirements. It lacks the sticky footer concept.
  • VeenarM
    VeenarM about 10 years
    obviously didn't read the whole comment saying ' which you shouldn't really do'...
  • BalusC
    BalusC about 10 years
    But the question didn't state that.
  • Tiny
    Tiny about 10 years
    Appended to the question body.
  • BalusC
    BalusC almost 10 years
    1) is wrong (it should go up to with <html>) and 2) isn't required at all (thus it's perfectly fine to have none) yet your answer implies that. That JavaScript snippet would be more helpful if you elaborate in detail what exactly you changed and why, instead of making it a seek&find game.
  • Nassim MOUALEK
    Nassim MOUALEK almost 10 years
    1) No its working to me without going until HTML, as i said all components between BODY and Layout, 2) i dont understand you my english is limited
  • BalusC
    BalusC almost 10 years
    Uh, it's working for you because you used that script. That div/span around the layout is completely unnecessary. With that script you don't need to declare the heights at all.
  • Nassim MOUALEK
    Nassim MOUALEK almost 10 years
    OK, now i understand u, as i said i modify it a long time ago, and now i am using the PF extension Layout not the default PF layout, but i think that i add this line this.jq.css('height', $(window).height()-10);
  • Nassim MOUALEK
    Nassim MOUALEK almost 10 years
    The exemple show that no SPAN must be between the BODY and the Layout otherwise the Layout initialization will fail
  • BalusC
    BalusC almost 10 years
    Of course there should be no inline elements in between block elements in order to achieve a full height. But the OP didn't have any and the div is also not required at all. Yet your answer implies that. You should just have nothing between body and layout. In any way, I just tried your script, it'll behave exactly like fullPage="true". This isn't what the OP intented.
  • Nassim MOUALEK
    Nassim MOUALEK almost 10 years
    We dont know, may be if BalusC respect the both rules (1 and 2) its should work fine
  • Nassim MOUALEK
    Nassim MOUALEK almost 10 years
    In case it fail, he probably should give a try to the PF extention Layout, (last advice)
  • BalusC
    BalusC almost 10 years
    The OP want a fullPage="false" with a sticky footer. Thus, when the content (center layout unit) is smaller than the screen height, then the footer should stay all at the bottom. But when the content is bigger than the screen height, then the footer should be pushed lower along with the content. The center layout unit should NEVER have a vertical scroll bar (otherwise you end up with exactly the same as fullPage="true"). Your answer definitely doesn't achieve that and I start to have the impression that you have genuinely no idea how HTML inline/block/layout elements work (as to 1 and 2).
  • Nassim MOUALEK
    Nassim MOUALEK almost 10 years
    maybe i didnt understand your need, sorry
  • Tiny
    Tiny almost 10 years
    To my experiments, PrimeFaces Extensions <pe:layout> only works (when fullPage is set to false), when it is explicitly given a height. Otherwise, it fails with an error in an alert box like - / UI Layout Initialization Warning The layout-container "DIV#mainForm:fullPage" has no height. Therefore the layout is 0-height and hence 'invisible'! I cannot see any concept of sticky footer in PrimeFaces Extensions <pe:layout> too. Does it have a sticky footer? If yes then, I instantly avoid using PrimeFaces <p:layout>.
  • Tiny
    Tiny almost 10 years
    Thank you very much for taking much time. Will give it a try!
  • Tiny
    Tiny almost 10 years
    I have some components on the west and east units like <p:slider> displayed inside <p:panel> and a colour list displayed using <p:dataGrid> inside <p:panel>. They all are messed up, their positions, appearance, height, width... considerably changed. It requires enhanced CSS/JS to display them properly. I lack that much knowledge of HTML/CSS/JS (someone with sufficient knowledge of HTML/CSS/JS can of course do this but certainly not me) I left with some of choices now are, exclude the footer from the template forever, use fullPage="true" or use plain vanilla HTML/CSS template ha ha :)
  • BalusC
    BalusC almost 10 years
    I just quickly tried a <p:panel><p:inputText id="i"/><p:slider for="i"/></p:panel> in center unit, looks okay.
  • Tiny
    Tiny almost 10 years
    Components on the center unit look fine but components on the west and east units shuffle.
  • BalusC
    BalusC almost 10 years
    There's no east unit in the question/answer? If you keep it out, the answer should work, otherwise the question and answer has to be altered.
  • Tiny
    Tiny almost 10 years
    The east unit was added long after this post. Therefore, it is not available in this question.
  • Tiny
    Tiny almost 10 years
    OK, I will have to look carefully, if I'm doing something wrong somewhere.
  • BalusC
    BalusC almost 10 years
    You can't use this CSS when you add the east unit. The CSS has to be altered for that. The answer is targeted on the question in its current form, nothing else.
  • Tiny
    Tiny almost 10 years
    Sorry then, I should have changed the question to reflect that but I myself forgot it. I could not remember there was no east unit in the question.
  • Tiny
    Tiny almost 10 years
    My application uses the east unit and there is no east unit in this question. Honestly, I could know only after you commented here. Apologize to this big mistake.
  • BalusC
    BalusC almost 10 years
    Have you in first place checked the SSCCE of the layout? There's already no "east unit" in there. If the SSCCE already doesn't match your wish, the remainder of the answer would be unsuitable as well. In any way, I updated the answer to include the east unit. Please try to work with SSCCE's before applying on the existing codebase. This should give a much better understanding of the problem and solution as they are really minimalistic and don't contain "code noise" (except of background colors)
  • Tiny
    Tiny over 8 years
    The issue status on the tracker is NotMovedToGitHub : "Marking as NotMovedToGitHub, if you'd like to provide further feedback please create a new issue ticket at GitHub with details to continue discussion over there."