How do i add a "custom" button in p:schedule? I tried doing it with the help of a header facet like in the p:dataTable component, but to no avail.
Sorry for being unclear initially, it also probably didnt help that someone butchered my question by editting it's title, here are more details with snippets of code.
I want to do somthing similar to this:
<p:tab title="#{bean.name}" value="bean" >
<f:facet name="title">
<h:outputText value="#{bean.name}"/>
<p:selectBooleanButton styleClass="...">
<p:ajax converter="... />
</p:selectBooleanButton>
</f:facet>
</p:tab>
The code is creating a tab (for an accordionpanel) with a text+button in it instead of the default text only.
I am looking for the same behaviour in a p:schedule component.
<p:schedule value="#{scheduleView.lazyEventModel}" leftHeaderTemplate="today" centerHeaderTemplate="prev, title, next" rightHeaderTemplate="month, agendaWeek" >
<f:facet name="header">
<h:outputText value="#{bean.name}"/>
<p:commandButton styleClass="..."/>
</f:facet>
</p:schedule>
The same add a button to the header principle, except this time on schedule. And of course since schedule does not have any facets available for overwriting this approach does not work.
Finally, my question is: How do I add a button in the p:schedule header like in the picture above?
P.S: Forgive me for confusing you people with datatable, used it because it supports multiple facets (header, footer).
Client side it is all html that can be manipulated with javascript (jquery if you like).
So if you create your schedule and button like this:
<h:panelGroup id="mySchedule">
<p:schedule value="#{scheduleView.lazyEventModel}" leftHeaderTemplate="today" centerHeaderTemplate="prev, title, next" rightHeaderTemplate="month, agendaWeek"/>
<h:outputText value="#{bean.name}" id="scheduleOutputText"/>
<p:commandButton styleClass="..." id="scheduleCommandButton"/>
</h:panelGroup>
You can move the h:outputText and p:commandButton into the schedule with jquery dom manipulation.
$("#scheduleCommandButton").insertBefore(".fc-left");
$("#scheduleOutputText").insertBefore("#scheduleCommandButton");
If you put this script inside the panelGroup and update the panelGroup each time you'd normally update the schedule via ajax, the button and text should be added moved again in an update.
<h:panelGroup id="mySchedule">
<p:schedule value="#{scheduleView.lazyEventModel}" leftHeaderTemplate="today" centerHeaderTemplate="prev, title, next" rightHeaderTemplate="month, agendaWeek"/>
<h:outputText value="#{bean.name}" id="scheduleOutputText"/>
<p:commandButton styleClass="..." id="scheduleCommandButton"/>
$("#scheduleCommandButton").insertBefore(".fc-left");
$("#scheduleOutputText").insertBefore("#scheduleCommandButton");
</h:panelGroup>
You could also put the text and button in a panelgroup and move that by dom manipulation. Just make sure you use the right selectors (I did not prepended the form id to the selectors above). You can also use class selectors instead of id's. That is up to you.
But make sure you use this with care. As #JasperDeVries mentioned in a comment, it is easy to break things. Use it just sparsely, carefully and only as a last resort
Related
I have a view like so:
<h:form id="productForm">
<p:messages
id="productFormMessages"
autoUpdate="true"
redisplay="true"
globalOnly="true" />
<p:panelGrid
id="detailsGrid">
<p:row>
...
<p:column>
...
<p:outputLabel
id="fieldToUpdateId"
value="XYZ" />
<p:commandButton
action="#{bean.prepareDialog}"
update="dialogFormId"
oncomplete="PF('dialogModal').show();" />
</p:column>
</p:row>
</p:panelGrid>
</h:form>
<ui:include src="/../.../dialog.xhtml" />
And this is what dialog.xhtml looks like:
<p:dialog
id="dialogId"
widgetvar="dialogModal"
appendTo="#(body)"
modal="true"
dynamic="true">
<h:form
id="dialogFormId">
...a selectOneMenu...
<p:commandButton
id="saveButtonId"
value="Save"
actionListener="#{bean.save}"
oncomplete="PF('dialogModal').hide();"
process="#form"
update=":productForm" />
</h:form>
But the save button just refuses to update the productForm. It does update productFormMessages (which I'm guessing is because of the autoUpdate) but the form just doesn't update. I need to do a page reload from the browser in order for it to reflect the latest data. I have tried many different ways of doing this.
1. Using p:component to directly refer to the outputLabel in the update attribute.
2. (1) also using the form ID and the panelGrid ID.
3. Using the full client ID (with and without the preceeding ':') in the update attribute. Similarly using the form ID and the panelGrid ID.
4. Adding the client ID to the render IDs in the bean and then calling the partialViewContext#update method on that.
4. Setting partialViewContext#setRenderAll to true.
4. And as a last ditch attempt, as demonstrated by the code, updating the entire productForm. Which isn't so bad, because fieldToUpdateId is just one of the fields that I need to update in the form. But either way, it's not working.
Clearly, the data is being saved on the back end, because a page reload gives me the latest data. But I just can't get the dialog to update the form where it's being called from. I'm out of ideas. What am I doing wrong?
Theoretically this should work, But please inspect the button in the Html source, to make sure which part of the html it refresh. it should have something like this.
onclick="PrimeFaces.ab({s:'dialogFormId:saveButtonId1',u:'productForm',onco:function(xhr,status,args){PF('dialogModal').hide();;}});return false;"
I am looking for solution that p:overlayPanel content should update it self while clicking commendButton or commendLink. But its showing blank white p:overlayPanel when i click the button. The updating with the p:overlayPanel id in that button or link. I have tried many ways nothing worked out. Is my code wrong?
Please suggest some solution.
Here is my code :
<ui:repeat id="profiles" value="#{items.lstProfiles}" var="profile">
<p:commandLink id="profileLink" value="show" update="moviePanel"
actionListener="#{dashBoardController.showProfileOverlay}"/>
<p:overlayPanel id="moviePanel" for="profileLink" hideEffect="fade"
dynamic="true" style="width:300px; height: 150px;">
<h:panelGrid columns="2">
<h:outputText value="Name : "/>
<h:outputText value="#{dashBoardController.selectedProfile.name}"/>
</h:panelGrid>
</p:overlayPanel>
</ui:repeat>
Usually dynamic="true" should do the job but some times it fails.So to update the contents inside the Overlay.
There are many ways to do this by tweaking Jquery.
Simplest one I can think of is:
Since ui:repeat generates dynamic ID for p:overlayPanels you can update by providing unique css class name from every iteration.
In Primefaces you can select a component using css class also using: #(.myclass).
And so you can update that component also:- update="#(.mystyle)"
Example:
<h:form>
<ui:repeat var="patient" value="#{dataCenter.patientList}">
<p:commandLink value="#{patient.firstName}" id="patientNameLnk" update="#(.overlay-class-#{patient.patientId})"/><br/>
<p:overlayPanel for="patientNameLnk">
<h:panelGroup styleClass="overlay-class-#{patient.patientId}">
#{patient.firstName}
#{patient.lastName}
#{patient.dob}
</h:panelGroup>
</p:overlayPanel>
</ui:repeat>
</h:form>
In the above example css class name for every h:panelGroup will be generated as overlay-class-<PATIENT_ID> so every h:panelGroup will have unique class name(if patientId is unique).
Note: Note that I'm updating h:panelGroup inside p:overlayPanel because if you update p:overlayPanel then it might start flickering(it happened to me while executing above example).
I'm having some trouble with primefaces datatables and dynamic overlay for each row.
Basically I have a main datatable containing a certain number of rows. For each row, I have a button and a linked overlay that, when clicked, shows a small datatable in the overlay (it lists the lasts changes concerning the row).
Here is the simplified code:
//the main datatable
<p:dataTable id="terminauxDataTable" var="terminalBean" widgetVar="dataTableWidgetVar" value="#{cc.attrs.listAllTerminals}"
filteredValue="#{cc.attrs.listFilteredTerminals}">
...
<p:columnGroup>
<p:row>
<p:commandButton id="changelogButton"
type="button"/>
<p:overlayPanel id="changelogPanel" for="changelogButton"
dynamic="true">
//the small datatable for each row
<p:dataTable var="changelog" value="#{terminalBean.lastChangelogs}">
<p:column headerText="#{msg['commun.changelog.table.label.date']}">
<h:outputText value="#{changelog.dateHr}">
<f:converter converterId="dateTimeConverter" />
</h:outputText>
</p:column>
... some other colums
</p:dataTable>
</p:overlayPanel>
</p:row></p:column></p:datatable>
everything works fine at first sight. When I click on any button i do get the content that I want to load. it's supposed to look like this :
http://i.stack.imgur.com/n9GrW.png
(sorry, cannot post image directly)
Problems start to arise as soon as I make any filtering od sorting on the main datatable.
If a specific button was never clicked since page load, the overlay and the contained datatable are load successfuly. It dosen't matter if I applied a filter or a sort.
If I already clicked a button at least once and then I apply a sort/filter, if I try to click again on the button the overlay is shown but is empty, there is no datatable inside.
here is an exemple of a click after a filter on a button that was clicked before :
http://i.stack.imgur.com/eLGLo.png
Do you have any lead on how to address this problem ?
Thank you
Using the overlay opitimally with a datatable, requires a little different approach as can be seen in the PrimeFaces showcase of the overlayPanel
You need to put the overlayPanel outside the datatable, put a updatable container in there, e.g. an outputPanel and on the button in your column, update the panel and call the show function of the overlay panel with a specific parameter. Something like this:
<p:dataTable>
....
<p:column style="width:32px;text-align: center">
<p:commandButton update=":form:terminalDetail" oncomplete="PF('myTerminalOP').show('#{component.clientId}')" icon="ui-icon-search" title="Details">
<f:setPropertyActionListener value="#{selectedTerminal}" target="#{mySelectionView.selectedTerminal}" />
</p:commandButton>
</p:column>
</p:dataTable>
<p:overlayPanel widgetVar="myOP" showEffect="fade" hideEffect="fade" dismissable="false" showCloseIcon="true">
<p:outputPanel id="terminalDetail" style="text-align:center;">
...
</p:outputPanel>
</p:overlayPanel>
(Disclaimer: done on my phone, so typos may be there)
On latest version of primeng we can do this.
Triggering the event based on element #id. By doing the toggle from typescript, I was able to pin point the element I need to attach the overlay panel to.
HTML:
<div>
<p-table>
<--loop the data-->
<button pButton (click)="showOP($event, rowwiseData, 'button'+rowIndex)" [id]="'button'+rowIndex"></button>
</p-table>
</div>
<--outside of the table add the overlay menu-->
<p-menu #menu [popup]="true" [model]="panelData"></p-menu>
TS File:
panelData: any;
#ViewChild('menu', {static: false}) op: OverlayPanel;
<!--Call and point the event to the correct element using unique #id-->
showOverlayPanel($event: MouseEvent, rowwiseData: any, id:string) {
this.panelData = rowwiseData;
this.op.toggle($event,document.getElementById(id));
}
I am developing a Seam-Jsfv1.2-EJB3 web app.
I have a datatable and checkboxes in each row. Moreover, I have a datascroller at the bottom of my table as well.
My problem is when I click the next page number from the scroller, the selected checkboxes at the first page of the datatable is gone. I mean, even if they were selected, clicking the next page make them deselected. I see it by going back to the first page again by clicking the scroller.
Do you have any idea about that problem?
In order to clearify my case, I attached my code below:
<rich:dataTable
id="apiV2ProductList" rows="10" var="_apiV2Product"
value="#{apiV2ProductList.resultList}"
rendered="#{not empty apiV2ProductList.resultList}" reRender="ds">
<rich:column>
<f:facet name="header">
<h:selectBooleanCheckbox id="selectionCheckAll" onclick="selectAll()" />
</f:facet>
<h:selectBooleanCheckbox id="selectionCheck" onclick="increase(this)" value="#{_apiV2Product.selectValue}" >
</h:selectBooleanCheckbox>
</rich:column>
...
<f:facet name="footer">
<rich:datascroller id="ds" renderIfSinglePage="false">
</rich:datascroller>
</f:facet>
Many thanks in advance.
Baris
You can extend the org.richfaces.renderkit.html.DatascrollerTemplate
write your own DataScroller for your own styling by adding a component with the below configuration in faces-config.xml
<component>
<component-type>exCustHtmlDatascroller</component-type>
<component-lass>org.jsf.common.ui.EXCustHtmlDatascroller</component-class>
</component>
<render-kit>
<renderer>
<component-family>org.richfaces.Datascroller</component-family>
<renderer-type>exCustDataScrollerTemplate</renderer-type>
<renderer- class>org.jsf.common.ui.EXCustDataScrollerTemplate</renderer-class>
</renderer>
</render-kit>
Adding an a4j support tag between scroller has solved my problem:
<f:facet name="footer">
<rich:datascroller id="ds" renderIfSinglePage="false">
<a4j:support event="onpagechange"/>
</rich:datascroller>
</f:facet>
However the other thing is, I am using JQuery to style my table (ex. on mouse over and out), and this time, when I click the next page of my table, the style is gone.
Any help would be great, many thanks in advance.
**
PS: BTW the wierest thing to my mind is it comes me impossible to find a solution by yourself for this kind of problems. Your creation may not always be enough to solve (at least here in my example, adding a4j:support thing) I am asking experts, how can we handle that kind of things by ourselves...
**
You don't need jQuery for styling the datatable
<rich:dataTable id="dataTable" var="x"
onRowMouseOver="this.style.backgroundColor='#F1F1F1'"
onRowMouseOut="this.style.backgroundColor='#{a4jSkin.tableBackgroundColor}'"
The problem you were seeing with the styles being removed is due to the nature of AJAX, and the way the table is reRendered.
Assuming you were firing the initial styling call based on some form of page onLoad, the first time the page is rendered, your styles will be applied. However, when you click the "next" button with the paginator, you are pulling a lot of new HTML down, and replacing the old HTML in the table with the newer, updated information. The proble you're seeing is that you saw styling because jQuery applied styles to the old nodes, upon reRender, those nodes are completely thrown away, along with their styling. You simply need to figure out the hook to call the "styling" method, and re-execute that call after the table is re-rendered.
Generally, I use an a4j:status tag, and set up the onstart or onstop to re-parse the table.
I specified this
<rich:panel>
<f:facet name="header">
Panel #1. Changing Style Synchronously
</f:facet>
Each component in the RichFaces has a pre-defined set of classes you can manipulate with. If defined, those
classes overwrite the ones come from the skin.
</rich:panel>
from the RichFaces demo, in my JSF page and no header appears, although I've nothing in my css which would interfere. What might be the reason for this?
Thanks
i dont see any problem with using f:facet
try
<f:facet name="header">
<div><h:graphicImage value="/images/search.png" />
<h:outputText value=" Action Logs Search" /></div>
</f:facet>
in order to regenerate the error you mentioned
Mine disappeared when I accidentally included the panel's facets in the panel form. The facets must be children of the modal panel:
<rich:panel>
<a4j:form> <!-- This is trouble! -->
<f:facet name="header">
Panel #1. Changing Style Synchronously
</f:facet>
Each component in the RichFaces has a pre-defined set of classes you can manipulate with. If defined, those
classes overwrite the ones come from the skin.
</a4j:form>
</rich:panel>
OK, do please feel free to comment on why the f:facet tag is not working, but I get my nice shiny headers when I change the code so it's like this instead:
<rich:panel header="header">
Each component in the RichFaces has a pre-defined set of classes you can manipulate with. If defined, those
classes overwrite the ones come from the skin.
</rich:panel>