0

I have created a composite component, based on PrimeFaces components that works as a multi-line text component. Text is added to an input, an "Add" button is clicked, and that text is added to a menu. The items in the menu are the submitted value. This works fine, until I set it up as a Composite Component. Then, the initial "Add" click does not add a value. Subsequent clicks work fine. From what I can tell the ViewState is not created until the second click. I assume this is the issue. Am I doing something wrong? Is it a bug? Here is the code:

Composite Component:

    <cc:interface>
        <cc:attribute name="value" type="java.util.Collection" />
    </cc:interface>
    <cc:implementation>
        <p:inputText value="#{multiTextBean.text}" id="txtInput" />
        <p:commandButton value="Add" action="#{multiTextBean.add}"
            update="menu txtInput" />
        <p:commandButton value="Clear"
            action="#{multiTextBean.clear}" update="menu txtInput" />
        <p:selectManyMenu id="menu"
            value="#{multiTextBean.removes}">
            <f:selectItems id="items"
                value="#{multiTextBean.items}" />
        </p:selectManyMenu>
        <p:commandButton value="Remove"
            action="#{multiTextBean.remove}" update="menu" />
    </cc:implementation>

Backing Class for component:

package util;
import java.io.IOException;
import java.util.Set;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIInput;
import javax.faces.component.UISelectItems;
import javax.faces.context.FacesContext;
import javax.faces.convert.ConverterException;

import org.primefaces.component.selectmanymenu.SelectManyMenu;


public class multitext extends UIInput implements NamingContainer {

public String getFamily(){
    return "javax.faces.NamingContainer";
}

@SuppressWarnings("unchecked")
@Override
protected Object getConvertedValue(FacesContext context, Object newSubmittedValue)
        throws ConverterException {
    SelectManyMenu menu = (SelectManyMenu) findComponent("menu");
    UISelectItems items = (UISelectItems) menu.findComponent("items");
    Set<String> localItems = (Set<String>) items.getValue();
    return localItems;
}

@Override
public Object getSubmittedValue() {
    return this;
}

@Override
public void encodeBegin(FacesContext context) throws IOException {
    super.encodeBegin(context);
}       
 }

Bean referenced by Composite Component

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ManagedBean
@ViewScoped
public class MultiTextBean {
private String text;
private Set<String> items;
private List<String> removes;

@PostConstruct
public void init(){
    items = new HashSet<String>();
    removes = new ArrayList<String>();
}

public String getText() {
    return text;
}

public void setText(String text) {
    this.text = text;
}

public Set<String> getItems() {
    return items;
}

public List<String> getRemoves() {
    return removes;
}

public void setRemoves(List<String> removes) {
    this.removes = removes;
}

public void add(){
    if(!text.isEmpty())
    {items.add(text);}
    text = null;
}

public void clear(){
    items.removeAll(items);
    text = null;
}

public void remove(){
    items.removeAll(removes);
}
 }

The component looks like: enter image description here

Using the component on this test page:

 <!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"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:mt="http://java.sun.com/jsf/composite/util"
xmlns:p="http://primefaces.org/ui">
<h:head>
    <title>Insert title here</title>
</h:head>
<h:body>
    <ui:debug hotkey="x"/>
    <form>
    <mt:multitext value="#{backingBean.submittedValues}"/>
    <p:commandButton value="Submit" action="Submit" update="@all"     process="@all"/>
    #{backingBean.submittedValues}
    </form>
</h:body>
 </html>
bricks
  • 153
  • 1
  • 3
  • 14
  • Are you rendering the form containing the composite from another form using `` beforehand? Then it can namely happen that the form will lose its view state. See also http://stackoverflow.com/questions/7807334/rendering-other-form-by-ajax-causes-its-view-state-to-be-lost-how-do-i-add-this/7807401#7807401 – BalusC Sep 20 '12 at 11:54
  • @BalusC No. I have updated the question with the xhtml page that I am using to run the test. Does this look ok? – bricks Sep 20 '12 at 14:53
  • Also, @BalusC per your blog, I thought that bug was not relevant when using PrimeFaces components. True? – bricks Sep 20 '12 at 17:12
  • That applies to the way how the form is been opened/updated. Not to what components the opened/updated form itself is containing. – BalusC Sep 20 '12 at 17:17
  • @BalusC Ok, well I only have one form, so I think this is a different issue. – bricks Sep 20 '12 at 17:25
  • Your test page contains a `
    `, not a ``. Does this really reflect your real code?
    – BalusC Sep 20 '12 at 17:52
  • @BalusC Wow, I feel stupid. I've been debugging this for hours, and did not catch that. That fixes the issue. I apologize for wasting your time. Thank you so much for all of the help that you provide. It is invaluable. – bricks Sep 20 '12 at 18:05

1 Answers1

1

In order to invoke (ajax) actions in JSF, you need a <h:form> instead of <form>.

Fix it accordingly:

<h:form>
    ...
</h:form>

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555