Primefaces Custom Positioning for a Specific P:Growl

Primefaces custom positioning for a specific p:growl

As you can see from the generated HTML the growl component isn't holding your actual growl data. The message which is appearing in the corner is hold by a div element:

<div id="your_growl_id + _container">

so the correct css selector for growl would be:

div[id="growlForm1:growlCenter_container"] {}

(I assume your growl components are placed into the same form). Finally as you noted in your post if you have two growl components on your page:

<h:form id="growlForm1">
<p:growl id="growlCenter" showDetail="true" sticky="true" />
<p:growl id="growlRight" showDetail="true" sticky="true" />
</h:form>

just assign the desired css properties for the centered and not-centered growl containers:

div[id="growlForm1:growlRight_container"] {
position:absolute;
top:20px;
}
div[id="growlForm1:growlCenter_container"] {
position:absolute;
top:20px;
left:40%;
}

Note that you can use the prependId="false" attribute of the <h:form/>. That would simplify the css selectors. But it is advised not to use this, see UIForm with prependId="false" breaks <f:ajax render>

How to use Growl with 'position: sticky' in Primefaces?

Disclamer: I tried this with the PF 7.0 showcase, but I think the basics also work with the 5.1 version.

You effectively have 4 options. The latter three all need you to inspect the javascript source of the component (which is open, so you can ALWAYS inspect it before asking questions, the java source is irrelevant here) and for the first solution it helps to see how the component works, but inspecting with a browser developer tool is sufficient (that is how I did it).

Basic analysis with or without looking at the source

This is a variant on your "Or some way to get the component to render where it is declared?". Since on the client side, it is all plain html, css and javascript, you can manipulate with al tools available on the client-side.

You can see that the main part of the grow is html technically rendered where it is declared. Check the PrimeFaces showcase and you'll see

<span id="j_idt700:growl" class="ui-growl-pl" data-widget="widget_j_idt700_growl" data-summary="data-summary" data-detail="data-detail" data-severity="all,error" data-redisplay="true"></span>

right inside the form where it also is in the xhtml. The javascript of the component creates the client side dom things, amongst which is the container that you see right before the end of the body (from the showcase)

<div id="j_idt700:growl_container" class="ui-growl ui-widget" style="z-index: 1002;"></div>

This last piece is html is where the individual growls are added to when they need to be rendered and hence the part that makes the component in most normal cases behave correctly but needs to be done differently in your case.

Solution 1, pure client-side component agnostic solution

Effectively this is as simple as moving this piece of html in the dom, see How to move an element into another element?.

In the online showcase I put the following jquery code in the browser developer tool console

$("#j_idt700\\:growl_container").prependTo(".layout-content");

And added the following css

position: sticky;
top: 10px;
float: right; // this is needed in the showcase, might not always be needed

And it worked.

The jquery should be put somewhere in your page where it runs after the component javascript is executed, so best is to do it right before the end of the body.
Keep in mind that the j_idt700 prefix is the dynamic id of the form in the showcase (it does not have a fixed id here), but you can also use different selectors based on the classes or whatever)

Solution 2, changing the source 'locally'

In the javascript source, you can see where the container is technically rendered

render: function() {
//create container
this.jq = $('<div id="' + this.id + '_container" class="ui-growl ui-widget"></div>');
this.jq.appendTo($(document.body));

//render messages
this.show(this.cfg.msgs);
},

Changing the this.jq.appendTo($(document.body)); in some way to have it appended to the current html node ('this'?) will make it work too. Regarding the overriding, you have two options

  • How do I find and/or override JavaScript in Primefaces component based on widgetVar?
  • Override a method from a Primefaces specific widget

Solution 3 Changing the source server side

Effectively you do the first part of #2 but patch the source and create a new custom PrimeFaces version

Solution 4 Make this feature avaiable for others too

What can be done here is to create a new attribute on the component and patch the source in some places so it is configurable to have the component behave as it is now or as sticky (they changed the existing 'sticky' attribute to 'keepAlive' in 7.0.x so sticky is avalable again ;-)). Of course this should be submitted as a patch then...

PrimeNG - How to change p-growl style

You must likely add one of the following before the selector:

/deep/

>>>

before the selector. If you're using the CLI then use /deep/, if not. Use the other.

/deep/ .ui-growl-message {
color: red;
}

UPDATE:

Use ::ng-deep instead.

Primefaces p:growl css. How to extend div message background color width

Thanks, yeah upon inspection it was clear the css was not applied.

The following CSS solved the position and width issues

.ui-growl {
position: fixed;
top: 60px;
right: 100px;
width: 800px;
}

.ui-growl-message {
padding: 0 0 5px 0;
width: 95%;
float: left;
}

Mainly though the issue was a resource ordering problem which was solved by putting the stylesheet within the facet named last within the body

<h:body>
<f:facet name="last">
<h:outputStylesheet library="theme1" name="css/styles/demo.css" />
</f:facet>

As described in Resource Ordering

how to use p:growl only for confirmation not validation jsf2 primefaces

If you set the message with a null client ID, then it becomes a "global message". Now, if you set globalOnly="true" attribute in <p:growl>, then it will display only that kind of messages.

Thus, so

context.addMessage(null, message);

with

<p:growl ... globalOnly="true" />

should do it for you.



Related Topics



Leave a reply



Submit