I have an application that's built on primefaces 12 to generate dynamic pages based on backend database, and I create InputMask as follows :
Application application = FacesContext.getCurrentInstance().getApplication();
InputMask inputNumber = (InputMask) application.createComponent(InputMask.COMPONENT_TYPE);
inputNumber.setMask("999999999999999");
inputNumber.setSlotChar("");
inputNumber.setAutoClear(false);
inputNumber.setValidateMask(false);
inputNumber.setId(property.getSymbolicName());
inputNumber.setMaxlength(15);
myPanelGrid().getChildren().add(inputNumber);
Issue : the mask doesn't work in my xhtml page and I get error in console :
Widget class 'InputMask' not found!
So I tried manually to import the inputMask script as follows :
<h:outputScript library="primefaces" name="inputmask/inputmask.js" target="head" />
<h:outputScript library="primefaces" name="validation/validation.js" target="head" />
But it didn't work also
The only working workaround was to manually add in page a hidden inputMask component as follows :
<p:inputMask style="display:none"/>
Question : How to make the inputMask works fine without this workaround ?
Related
I have a big form that I need to reuse in multiple pages. So, I decided to create a
<ui:composition> that contains the form and include it in some pages (page1.xhtml and page2.xhtml).
form.xhtml:
<ui:composition ...>
<!-- The form goes here -->
</ui:composition>
This form has a controller called FormController.
In page1.xhtml and page2.xhtml I just include the form using a <ui:include> tag:
<ui:include src="/WEB-INF/.../form.xhtml"/>
I need to initialize a property in the FormController bean, so, in page1.xhtml I decided to set an attribute with the Id that I need (for example 5):
<c:set var="id" scope="request" value ="5"/>
And in the controller I just get the value of this attribute:
#PostConstruct
public init() {
Long id = ((HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest()).getAttribute("id");
//Do some queries to the database
}
Until know, everything works fine. But in page2.xhtml the "initialization" of the bean property has to be done after an ajax request, so I used the following code:
<h:selectOneMenu ...>
<f:selectItems ...>
<f:ajax listener="#{otherBean.doSomething}" render="panel"/>
</h:selectOneMenu>
<h:panelGroup id="panel">
<c:set var="id" scope="request" value ="#{otherBean.id}"/>
<ui:include src="/WEB-INF/.../form.xhtml"/>
</h:panelGroup>
What is weird is that this works just the first time I select an element in the <h:selectOneMenu>. The second time, the doSomething() method is called but the panel is not rendered (I don't know why, you know why?), so I decided to explore the following alternative that works well in both pages, but I feel that it isn't a good solution:
#{bean.init(otherBean.id)}
<ui:include src="/WEB-INF/modules/company/company.xhtml"/>
As you see, I am just calling an init method (before the <ui:include>) with the argument I need. In the controller I just set the property and do the corresponding queries:
public init(Long id) {
this.id = id;
//Do some queries
}
What do you thing about this solution?
If the form has to be initialized at start, you can use
<f:metadata>
<f:viewAction action="#{otherBean.initSomething('MYID2')}"/>
</f:metadata>
If the form has to be initialized by an action
<h:commandButton action='#{otherBean.doSomething('MYID1')}'...>
or
<f:ajax listener="#{otherBean.doSomething('MYID')}" .../>
I have a big problem with my Primefaces Interface. I want to do a loop over a list and display some information + a hidden editfield.
XHTML Primefaces codesnippet:
<p:dataList value="#{datas}" var="data">
<div class="ui-g">
<div class="ui-g-3">
<h2>#{data.desc}</h2>
</div>
<div class="ui-g-3">
<p:commandButton operation="edit" disabled="#{data.isLocked()}" actionListener="#{view.edit(data)}"
style="width:120px;" update="edit_#{data.id}" />
<p:commandButton operation="delete" actionListener="#{view.delete(data.getId())}" disabled="#{data.isLocked()}"/>
</div>
</div>
<!-- works perfectly to set the id -->
<span id="edit_#{data.id}">#{data.desc} #{index}</span>
<!-- doesnt work - maybe of the rendering moment to set the id? -->
<p:panelGrid id="edit_#{data.id}" rendered="#{view.edit}">
<p:outputLabel for="desc" value="#{msg.text}" />
<p:inputText id="desc" value="#{view.selectedValue.desc}" />
</p:panelGrid>
How can I set a dynamic ID to the panelGrid to update it by commandButton click if I want to edit that div? + How can I make the div toggled while editing it? or are there other Solutions? I am not allowed to use JavaScript/jQuery.
Thank you very much!
cheers,
JohnRamb0r
I would say you are nearly working against JSF and the way it works in your code example. Before showing you a working example, there are a few things I would like to say here related to good practice:
Do not call methods directly, use the built in translation of property references. A reference to data.locked will be translated to a call to data.isLocked() automatically. A call to data.locked is preferred, as it will cause the framework to evaluate it instead of you sending in the already evaluated value.
Work with JSF - not against it. There are a lot of unnecessary ids and use of unneeded tags and indexes in your example code. Keep it simple and work with the framework. Instead of referencing an id, referencing the object directly - it simplifies the code and makes it easier to use on the page itself.
Use action as the main executor of business logic and outcome. Action listeners are executed beforehand and can be used to intercept or stop the execution of the main action. They are are therefore suitable to be used as a validatory step before executing business logic.
Mark your events. It's good practice to use the naming convention on<Something> when naming methods that receive user events. This allows you to clearly identify them.
I made a small working example of your code (this uses Lombok and Apache Commons);
#Data
#Named
#ViewScoped
public class DataListViewBackingBean implements Serializable {
private Entity entity;
private Entity selectedEntity;
private List<Entity> dataEntities;
#PostConstruct
private void init() {
dataEntities = new ArrayList<>();
for (int i = 0; i < 10; i++) {
dataEntities.add(new Entity(i, RandomUtils.nextBoolean(),
RandomStringUtils.randomAlphabetic(30)));
}
}
#Data
#AllArgsConstructor
#EqualsAndHashCode(exclude = {"locked","description"})
public class Entity {
private int id;
private boolean locked;
private String description;
}
public void onEdit(Entity entity) {
selectedEntity = entity;
}
public void onDelete(Entity entity) {
dataEntities.remove(entity);
selectedEntity = null;
}
}
The code above initializes a data list of ten entities and fills this with random data. I took the privilege to change data to entity. When it comes to your HTML code, I felt it needed some cleaning. The definition of the JSF would look something like this;
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Data list test</title>
</h:head>
<h:body>
<h:form id="items">
<p:dataList type="definition" value="#{dataListViewBackingBean.dataEntities}" var="entity">
<div class="ui-g">
<div class="ui-g-8">
#{entity.description}
</div>
<div class="ui-g-4" style="text-align: right">
<p:commandButton value="Edit" disabled="#{entity.locked}" action="#{dataListViewBackingBean.onEdit(entity)}" update=":edit" />
<p:commandButton value="Delete" disabled="#{entity.locked}" action="#{dataListViewBackingBean.onDelete(entity)}" update="#form :edit" />
</div>
</div>
</p:dataList>
</h:form>
<h:form id="edit">
<p:outputPanel rendered="#{dataListViewBackingBean.selectedEntity != null}">
<h1>Editing...</h1>
<p:inputText placeholder="Description" value="#{dataListViewBackingBean.selectedEntity.description}" />
<p:commandButton value="Save" update=":items" />
</p:outputPanel>
</h:form>
</h:body>
</html>
Note how the editing div/outputPanel is wrapped in another container (a form). If we skipped the wrapping and instead pushed an update on the wrapped container directly, the rendered tag of the container would never be updated during a refresh and the div would therefore never show up. In this particular case, this is why the form is defined outside the container instead of inside.
This example uses a #ViewScoped bean, so as long as you stay on the page, the backing data should stay the same. If you reload the page you will get a new data set with new entities, as this will reinitialize a backing bean and call #PostConstruct again.
See also
How can I set id of a component/tag inside ui:repeat
I have 2 views (a.xhtml and b.xhtml) one of which contains a link to the other. The first view:
uses the current view map by setting some value to it;
points to b.xhtml with h:link using includeViewParams="true" in order to automatically include view parameters in the link's query string.
a.xhtml:
<f:view >
<f:metadata>
<f:viewAction>
<!-- just set any value to force view map creation... -->
<f:setPropertyActionListener target="#{viewScope.username}" value="John" />
</f:viewAction>
</f:metadata>
<h:link id="alink" value="Go to B" outcome="b" includeViewParams="true" />
<h:form>
<h:commandButton id="away" action="b" value="Navigate away" immediate="false" />
</h:form>
</f:view>
</html>
and b.xhtml:
<!DOCTYPE html>
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:view >
<f:metadata>
<f:viewParam id="id" name="userid" value="1" />
</f:metadata>
</f:view>
</html>
Also I am creating here a ViewMapListener in order to demonstrate 'spurious' view map destruction event calls that happen once a.xhtml gets visited. In my faces-config.xml I'm having this entry:
<system-event-listener>
<system-event-listener-class>org.my.TestViewMapListener</system-event-listener-class>
<system-event-class>javax.faces.event.PreDestroyViewMapEvent</system-event-class>
<source-class>javax.faces.component.UIViewRoot</source-class>
</system-event-listener>
where TestViewMapListener is like this:
public class TestViewMapListener implements ViewMapListener {
#Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
if (event instanceof PreDestroyViewMapEvent) {
PreDestroyViewMapEvent viewMapEvent = (PreDestroyViewMapEvent)event;
UIViewRoot viewRoot = (UIViewRoot)viewMapEvent.getComponent();
System.out.println("PreDestroyViewMapEvent: "+viewRoot.getViewId());
}
}
...
Once the page a.xhtml is rendered, the listener prints out the following line:
PreDestroyViewMapEvent: /b.xhtml
which is strange because b.xhtml has never been visited. When I navigate away with "Navigate away" button a correct event is printed as expected:
PreDestroyViewMapEvent: /a.xhtml
The incorrect event is fired only if I am using includeViewParams="true" on the link. By debugging, I can see that it happens because com.sun.faces.application.view.ViewMetadataImpl.createMetadataView(FacesContext) is temporarily setting to FacesContext a UIViewRoot for b.xhtml where a shallow copy of the original view map is created and set to temporary view root. This is probably done in order to correctly detect values of query string parameters for the link; it also temporarily turns off events for the time of the manipulations however it turns them back on too early (see 'finally' block), so view map destruction event is 'incorrectly' fired for a temporary copy of the view map, while no events for the original view map itself are expected at this time. It's a headache because I need to take some additional actions in order to detect whether it is the original map is destroyed or it is a spurious event for its 'ghost'.
Is this a bug or a desired behavior? I am using Mojarra 2.2.12.
i would like to add a composite component programmatically and add a action listener for a primefaces commandbutton over a interface attribute.
Problem: The listener method will never be executed.
My composite component with the delcard listener attribute:
<composite:interface>
<composite:attribute name="bean"/>
<composite:attribute name="listener" required="false" method-signature="void reportClickedAction(javax.faces.event.ActionEvent)"/>
</composite:interface>
<composite:implementation>
<h:outputScript library="js/composite" name="KpiPast.js"/>
<h:panelGroup rendered="#{cc.attrs.bean.showButtons}">
<p>
<h:form>
<!-- Primefaces button using the listener -->
<p:commandButton id="testbutton" value="prime" ajax="true" actionListener="#{cc.attrs.listener}"/>
</h:form>
</p>
</h:panelGroup>
</div>
</composite:implementation>
If i use this component in a .xhtml file, like the following example, it works.
<qc:kpi-past bean="#{dynamicPageController.kpipast}" listener="#{statisticController.reportClickedAction}" />
Buf if i render it programmatically like in this post the listener method does not get called if i click the button. I use omnifaces for rendering. Here is the render code:
UIComponent composite = Components.includeCompositeComponent(parent, Content.CONTENT_LIBRARYNAME, KpiPast.RESOURCENAME, this.getId());
Map<String, Object> attributes = composite.getAttributes();
// create MethodExpression
MethodExpression listener = Components.createMethodExpression("#{statisticController.reportClickedAction}", Void.class, javax.faces.event.ActionEvent.class);
// add MethodExpression as attribute
attributes.put("listener", listener);
attributes.put("bean", this);
parent.getChildren().add(composite);
And here is my listener Method:
public void reportClickedAction(ActionEvent actionEvent) {
logger.info("reportClickedAction");
}
What am i doing wrong? And why do the listener in my programmatically generated composite elements only work if the page gets submitted? For testing purposes i also tried a with ajax event instead of , same result, it is not working.
But while testing i saw that once a form gets submitted (with no specific action value) the page gets reloaded and my listeners are working as the should on first page call. For example if i submit the following form in the .xhtml which includes my generated composite elements, the page reloads and my listeners are working:
<h:form>
<h:commandButton type="submit" value="submit"/>
</h:form>
I have dashboard with panels:
<p:dashboard id="board" model="#{dashboardOptionsMB.model}">
<c:forEach var="item" items="#{dashboardOptionsMB.emsWidgets}">
<ui:include src="/pages/dashboard/panel.xhtml">
<ui:param name="widget" value="#{item.webDashboardDbBean}" />
<ui:param name="emsValue" value="#{item.emsValue}" />
</ui:include>
</c:forEach>
</p:dashboard>
I load a list dashboardOptionsMB.emsWidgets with content before rendering page, and this works fine with panel component:
panel.xhtml:
<p:panel id="#{widget.widgetid}" header="#{widget.widgetheader}" closable="true" >
<h:outputText value="#{emsValue.value}" />
...
</panel>
So, before each rendering I initialize the list with all elements and content with this method:
DashboardOptionsMB:
private void initWidgets(WebDashboardsDbBean dashboard) {
//dashboard is JPA entity from database
emsWidgets = dashboard.getWidgets();
...
}
What I want to achieve is to load each panel content dynamically after page load. For example each panel should call:
initWidget(String widgetId)
after page load, and when this method is completed to update its content.
Use p:remoteCommand to create some Ajaxified Javascript which will be executed when body is loaded:
<h:body onload="loadWidgets()">
<!-- content -->
<p:remoteCommand name="loadWidgets"
update="#{widget.widgetid}"
actionListener="#{dashboardOptionsMB.initWidgets}"/>
</h:body>
Alternatively, you might use the autoRun="true" argument to have it executed when document is ready:
<p:remoteCommand name="loadWidgets"
update="#{widget.widgetid}"
actionListener="#{dashboardOptionsMB.initWidgets}"
autoRun="true"/>
See also:
JSF lazy loading component value
Make your Primefaces app load faster with lazy loading