Very simple dialog. I want a method to be called when it is closed by clicking on the x. However the listener is not called. It's not in the generated source code either. I'm using Primefaces 2.1 with Glassfish4.
xhtml:
<h:body>
<p:dialog visible="true" closeListener="#{variances.closeDetail}" >
Hi there!
</p:dialog>
</h:body>
java:
#Named("variances")
#SessionScoped
public class Variances implements Serializable {
public void closeDetail(CloseEvent event) {
Log.trace("Variances", "closeDetail called");
}
}
generated source:
<script type="text/javascript">
jQuery(function() {
widget_j_idt6 = new PrimeFaces.widget.Dialog(
'j_idt6',
{autoOpen:true,minHeight:0,ajaxClose:true,url:'/MetricsMonitor/binh.jsf'});});
</script>
Any idea ? I can't use p:ajax because I then get the "Parent not an instance of ClientBehaviorHolder" error.
TIA.
Binh
Related
<h:form prependId="false" id="vt_sel_form">
<p:panelGrid styleClass="center" columns="2">
<p:commandButton value="GO" oncomplete="alert(#{test.i})" actionListener="#{test.testfxn()}" update="#this"/>
</p:panelGrid>
</h:form>
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ViewScoped
#ManagedBean(name = "test")
public class TestClass implements Serializable {
int i ;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
public void testfxn() {
setI(i++);
//i=i+10;
System.out.println("i" + i);
}
}
Here, alert(#{test.i}) is always displaying 0. How do i get backing bean value that changes when I click the commandButton. It works when I click button twice. It used to work fine when I used a4j:commandButton.
That's just because alert(#{test.i}); is evaluated when the commandButton is rendered. You can see the changed value by telling JSF to render the script again:
<h:commandButton value="click me" action="#{testClass.testfxn()}">
<f:ajax render="out" />
</h:commandButton>
<h:panelGroup id="out">
<h:outputScript>
alert(#{testClass.i});
</h:outputScript>
</h:panelGroup>
Unlike Richfaces where you can directly call javascript function, primefaces you need to have javascript function as:
function_name(xhr, status, args)
Using listed CommandButton as Example:
<p:commandButton value="GO" oncomplete="alert(#{test.i})" actionListener="#{test.testfxn()}" update="#this"/>
In function test.testfxn() we have:
public void testfxn(){
RequestContext reqCtx = RequestContext.getCurrentInstance();
i = i++;
reqCtx.addCallbackParam("i", i);
}
Here,In function call to backing bean from actionlistener the variables are added to RequestContext.
Now In javascript function:
function draw(xhr, status, args) {
console.log("We are into draw function");
jsonString = JSON.parse(args.i); //json variable is taken out from args variable.
console.log("The value of i "+ i);
}
I am trying to implement infinite scrolling by using Primefaces with the assistance of jQuery Waypoint and Masonry API.
Here is what I have so far:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:pe="http://primefaces.org/ui/extensions">
<f:view>
<h:head>
<h:outputScript library="primefaces" name="jquery/jquery.js" />
<h:outputScript name="js/global.js"/>
<h:outputScript name="js/masonry.pkgd.js"/>
<h:outputScript name="js/imagesloaded.pkgd.js"/>
<h:outputStylesheet name="css/global.css" />
<title>Gallery</title>
</h:head>
<h:body>
<h:form prependId="false">
<h:panelGroup id="galleryPanel" layout="block">
<p:outputPanel autoUpdate="true">
<h:panelGroup layout="block" styleClass="galleryContainer">
<ui:repeat id="gallery" value="#{galleryController.images}" var="image">
<h:panelGroup layout="block" styleClass="item">
<h:graphicImage library="images" name="demo/#{image}.jpg" />
</h:panelGroup>
</ui:repeat>
</h:panelGroup>
</p:outputPanel>
<pe:waypoint id="waypoint" widgetVar="waypointWidget" offset="function(){return $.waypoints('viewportHeight') - $(this).outerHeight()}">
<pe:javascript event="reached" execute="handleLoadStart(ext);"/>
</pe:waypoint>
<h:outputScript target="body">
var layout = function(){
var container = $('.galleryContainer');
$(container).imagesLoaded(function(){
$(container).masonry({
itemSelector : '.item',
columnWidth : 240
});
});
};
var handleLoadStart = function(ext) {
if (ext.direction == "down") {
PF('waypointWidget').remove();
moreMedia();
}
};
var handleLoadStop = function(){
layout();
PF('waypointWidget').register();
};
$(document).ready(function(){
layout();
});
</h:outputScript>
<p:remoteCommand name="moreMedia" update="gallery" actionListener="#{galleryController.loadMore}" oncomplete="handleLoadStop()"/>
</h:panelGroup>
</h:form>
</h:body>
</f:view>
</html>
The Managed Bean is:
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;
#ManagedBean(name="galleryController")
#ViewScoped
public class GalleryController implements Serializable {
private static final long serialVersionUID = 563439107531288284L;
private List<String> images;
#PostConstruct
public void initialize() {
images = new ArrayList<>();
IntStream.range(1, 16).forEach(i->images.add(new String("image" + i)));
}
public void loadMore(ActionEvent event){
IntStream.range(1, 16).forEach(i->images.add(new String("image" + i)));
}
public List<String> getImages() {
return images;
}
public void setImages(List<String> images) {
this.images = images;
}
}
It is partially working, as it has issues.
The major issue is, as I am adding new images to the existing image list, the ui:repeat is rendering completely. I don't want to do this. Because by this way the existing images also get loaded. Modern browser like FF or Chome caches images, so it would not be a problem for them, but in the browser like IE I can see in Network console that it is sending GET to fetch those images. From the performance perspective the images which has already been loaded should not get fetched, only the newly added images.
But I don't know how can I make it in JSF!
Also as a side effect, the Masonry is not working as desired. Every time when the onComplete of p:remoteCommand is triggering the layout() method, the scrollbar is getting set to the top. From the functional perspective it should stay at that location from where the Waypoint triggered the next load.
Any suggestion would be very helpful.
PrimeFaces Extensions has pe:fluidGrid based on Masonry by the way. Check the showcase http://primeext.mooo.com:8080/primeext-showcase/views/fluidGrid.jsf
You do not update the ui:repeat anymore after initial load. Use a temporary data storage such as h:inputHidden to hold data returned and formatted by the the managed and then use JavaScript to move data from h:inputHidden to Masonry. In Masonry use the following to append data:
$container.masonry( "appended", html, true );
where html is the data of h:inputHidden
If you want you can visit this the blog below for details. It does not use PrimeFaces nor WayPoints but how Masonry is updated is similar to what wanted to do.
http://kahimyang.info/kauswagan/code-blogs/1699/how-to-use-and-append-data-to-masonry-in-responsive-jquerymobile-with-jsf-2-and-ajax
Let's say that you need an infinite list using
<ul>
<li>item 1</li>
<li>item 2</li>
<li>...</li>
</ul>
The idea is to create a composite component called list.xhml for instance with an attribute index.
That component could load a page of 10 elements for example.
When you scroll, load that component with JQuery ajax and add it to the dom.
I'm trying to capture old/new value for some business validation. For that, the ValueChangeListener seemed like a good choice. It worked great on h:selectOneMenu, however it does not get called when used with a home grown Composite Component with a Backing Component. Any idea what I'm doing wrong?
One thing to add is, when removing the componentType attribute from state.xhtml, the valueChangeListener works as expected...
The component:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface displayName="state" componentType="com.company.dept.system.ui.address.State" shortDescription="State Information Display/Input Component">
<composite:attribute name="value" type="java.lang.String" required="true" shortDescription="The value of the component" />
<composite:editableValueHolder name="state" />
</composite:interface>
<composite:implementation>
<div id="#{cc.clientId}">
<h:selectOneMenu id="state" value="#{cc.attrs.value}">
<f:selectItem itemLabel="(select)" noSelectionOption="true"/>
<f:selectItems var="item" itemLabel="#{item.displayValue}" value="#{cc.states}" />
</h:selectOneMenu>
</div>
</composite:implementation>
</html>
The backing component
#FacesComponent("com.company.dept.system.ui.address.State")
public class State extends UIInput implements NamingContainer {
private List<com.company.dept.policy.enums.State> states;
#Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
/**
* Prepare the list of states to display
*/
public List<com.company.dept.policy.enums.State> getStates(){
if (states != null) {
return states;
}
states = new ArrayList<com.company.dept.policy.enums.State>();
for (com.company.dept.policy.enums.State st : com.company.dept.policy.enums.State.values()) {
if(!st.equals(com.company.dept.policy.enums.State.NWNORWAY) && !st.equals(com.company.dept.policy.enums.State.UNKNOWN) && !st.equals(com.company.dept.policy.enums.State.TTTRUST_TERRITORY_AND_GUAM)) {
states.add(st);
}
}
Collections.sort(states,new StateNameComparator());
return states;
}
}
The value change listener
public class ClientValueChangeListener implements ValueChangeListener {
#Override
public void processValueChange(ValueChangeEvent event)
throws AbortProcessingException {
System.out.println("*****************************");
System.out.println("VALUE CHANGE LISTENER. OLD=" + event.getOldValue() + " - NEW=" + event.getNewValue());
System.out.println("*****************************");
}
}
consuming page:
<h:form>
<address:state value="#{testPage.state}">
<f:valueChangeListener type="com.company.dept.system.ui.clientinformation.ClientValueChangeListener" for="state"/>
</address:state>
<h:commandButton id="submitButton" value="Test" action="#{testPage.act}"/>
</h:form>
It's because your backing component extends from UIInput. The value change listener is applied to the backing component itself instead of to a child of the composite implementation.
Your concrete functional requirement isn't exactly clear, but based on the information provided so far, you can safely replace extends UIInput implements NamingContainer by extends UINamingContainer (and get rid of getFamily() override).
If you really intend to keep your backing component to extend from UIInput, then you should be delegating the submitted value, local value and value of the backing component all to the child dropdown component, but this makes design technically little to no sense.
Here is the situation:
I have a component, whose value is a property of my ViewScoped bean, which gets a FacesMessage generated for it do to some error when the form is first submitted
On a subsequent user action, a h:commandlink is clicked, which uses f:ajax, and its actionlistener sets the component to no longer be rendered
Upon receiving the reponse, the component is no longer rendered (as expected), but the FacesMessage for it still remains and is displayed
I am using Mojarra JSF 2.1, and IceFaces 3.0 - although this example and the problematic behavior are seen using only standard JSF components. Here is a small example that demonstrates the behavior:
test.xhtml
<h:form id="testform">
<h:message for="tv"/>
<h:inputText id="tv" value="#{testBean.testVal}" rendered="#{testBean.testValRendered}" required="true" />
<h:commandButton value="Submit"/>
<h:commandLink actionListener="#{testBean.toggleTestVal}" value="Toggle input">
<f:ajax execute="#this" render="#form"/>
</h:commandLink>
</h:form>
Bean code
#ViewScoped
#ManagedBean(name = "testBean")
public class TestBean {
private String testVal;
private boolean testValRendered;
public TestBean() {
testValRendered = true;
}
public String getTestVal() {
return testVal;
}
public void setTestVal(String testVal) {
this.testVal = testVal;
}
public boolean isTestValRendered() {
return testValRendered;
}
public void setTestValRendered(boolean testValRendered) {
this.testValRendered = testValRendered;
}
public void toggleTestVal(ActionEvent ae) {
testValRendered = !testValRendered;
}
}
If I change the h:commandLink so that it does not use f:ajax, and set immediate='true' on it instead, then the message is removed properly. While this may work in some cases, I would like to understand why using f:ajax to render things as I have in my example does not work. Thanks.
The input component is submitted, processed and validated before its rendering condition has been toggled. The <h:message> isn't aware that the associated input component is not rendered. You'd like to check the very same rendering condition on the <h:message> as well:
<h:message for="tv" rendered="#{testBean.testValRendered}" />
<h:inputText id="tv" ... rendered="#{testBean.testValRendered}" />
I have a <ui:repeat> that iterates over a List<String> and creates a <p:commandButton> with the value of the current String in a <p:lightBox>.
But when I add widgetVar to my <p:lightBox>'s attributes the value of the <p:commandButton> is always the String from the last iteration.
Can someone explain what happens and (as I need widgetVar) maybe point out a solution?
This is my html:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head />
<h:body>
<ui:repeat var="thing" value="#{bugBean.things}">
<p:lightBox widgetVar="whatever">
<h:outputLink>
<h:outputText value="#{thing}" />
</h:outputLink>
<f:facet name="inline">
<h:form>
<p:commandButton action="#{bugBean.writeThing(thing)}"
value="#{thing}" />
</h:form>
</f:facet>
</p:lightBox>
</ui:repeat>
</h:body>
</html>
This is the backing bean:
package huhu.main.managebean;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
#Named
#SessionScoped
public class BugBean implements Serializable {
private static final long serialVersionUID = 1L;
List<String> things = new ArrayList<String>();
public BugBean(){
things.add("First");
things.add("Second");
things.add("Third");
}
public void writeThing(String thing){
System.out.println(thing);
}
public List<String> getThings() {
return things;
}
public void setThings(List<String> things) {
this.things = things;
}
}
The widgetVar basically generates a window scoped JavaScript variable. What you're effectively doing now in JavaScript context is:
window['whatever'] = new Widget(lightboxElement1);
window['whatever'] = new Widget(lightboxElement2);
window['whatever'] = new Widget(lightboxElement3);
// ...
This way the whatever variable in JS would only refer the last one.
You should basically be giving them each an unique name, for example by adding the iteration index:
<ui:repeat var="thing" value="#{bugBean.things}" varStatus="iteration">
<p:lightBox widgetVar="whatever#{iteration.index}">
This way it becomes effectively:
window['whatever0'] = new Widget(lightboxElement1);
window['whatever1'] = new Widget(lightboxElement2);
window['whatever2'] = new Widget(lightboxElement3);
// ...
This way you can refer the individual lightboxes by whatever0, whatever1, whatever2, etc.
Unrelated to the concrete problem: isn't it easier to use a single lightbox and update its content on every click instead?
recently i had a similar problem when upgrading to primefaces 4.0 -> 5.1
I had to use syntax:
PF('whatever0')
Due to changes in how primefaces names the widgetvar.