Pergunta

I currently have a listbox (part of a search criteria) that represents a list of strings that are retrieved one at a time via a pop-up window. However when the pop-up window closes the selected String is never added to the listbox. (I have confirmed that the hidden variable is updated and if you navigate away from the page after a search is performed and navigate back, the list box correctly shows Strings I had selected from the pop up previously). Any help would be greatly appreciated!

    <script type="text/javascript">
        function selectBook(bookId, extendedBookName) {
            var idInput = jQuery("#myForm\\:bookNames");
            if (idInput.val() == "") {
                idInput.val(extendedBookName);
            } else {
                idInput.val(idInput.val() + '@@@' + extendedBookName);
            }  
        }
    </script>
...
 <h:form id="myForm">
    ...
      <ui:define name="form-fields">
         <h:selectOneListbox id="booksListBox" size="3" style="width:470px">  
            <s:selectItems var="_var" value="#{bean.searchCriteria.bookNames}" label="#{_var}" noSelectionLabel="" />
         </h:selectOneListbox>
         <h:outputLink onclick="return openNewWindow('#{bean.booksLookupUrl}?#{bean.bookLookupParameters}', 'book');" 
                       target="_blank">
                     <h:inputHidden id="bookNames" value="#{bean.searchCriteria.bookNames}" converter="StringListConverter"/>
                     <h:outputText value="Add"/>
         </h:outputLink>

      </ui:define>
    ...
 </h:form>

This is javaScript that belongs to the lookup window. This calls the selectBook function

function selectBook(bookId, extendedBookName) {
        var extendedName = unescape(extendedBookName);
        window.opener.selectBook(bookId, extendedName);
        window.close();
    }

And for my Java code...

public class BookSearchCriteria implements Serializable {
...
private List<String> bookNames = new ArrayList<String>();

    public List<String> getBookNames() {
    return bookNames;
}
public void setBookNames(List<String> bookNames) {
    this.bookNames = bookNames;
}

The StringListConverter code...

@FacesConverter("myStringListConverter")
public class StringListConverter implements Converter {

    // this is used as a regex, so choose other separator carefully
    private static final String MY_SEPARATOR = "@@@";

    @Override
    public Object getAsObject(FacesContext context, UIComponent component,
            String value) {
        if (value == null) {
            return new ArrayList<String>();
        }
        return new ArrayList<String>(Arrays.asList(value.split(MY_SEPARATOR)));
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component,
            Object value) {
        if (value == null) {
            return "";
        }
        return join((List<String>) value, MY_SEPARATOR);
    }

    /**
     * Joins a String list, src: http://stackoverflow.com/q/1751844/149872
     * 
     * @param list
     * @param conjunction
     * @return
     */
    public static String join(List<String> list, String conjunction) {
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        for (String item : list) {
            if (first) {
                first = false;
            } else {
                sb.append(conjunction);
            }
            sb.append(item);
        }
        return sb.toString();
    }

}
Foi útil?

Solução

I don't really understand why you want to populate your listBox using a popup.

But if you modify the underlying bean values, you need to rerender the <h:selectOneListbox/> to reflect these changes. If you are using (or can use) the richfaces framework it can be done quite easily through an ajax call.

The ajax4jsf component called <a4j:jsFunction/> can do the job. For example in your parent page add :

<a4j:jsFunction name="refreshListbox" reRender="booksListBox" limitToList="true"/>

and in your popup just call this js function when a new book value is selected :

<script type="text/javascript">
    window.opener.refreshListbox();
</script>

You could also use a <rich:modalPanel> instead of a popup to stay in the same page and interact more easily with your jsf components.

Outras dicas

The page in the popup window is running some server-side Java code that creates new options for the dropdown menu. This has no absolutely no effect on the parent page until the parent page is reloaded and regenerated by the server. To avoid reloading the page, you need to create and select the new option using client-side JavaScript/jQuery code.

Assuming that the HTML code for the resulting option should look something like <option value="bookId">extendedBookName</option>, you can use this:

<script>
function addBook(bookId, extendedBookName) {
    var newOption = jQuery('<option>').val(bookId).text(extendedBookName);
    var idInput = jQuery('#myForm\\:bookNames');
    idInput.append(newOption).val(bookId);
}
</script>

Demo: http://jsfiddle.net/5Cwjk/

Or, if the selection from the popup window is not guaranteed to be new, then you'll want to dynamically determine whether creating an option is necessary before doing so to avoid duplicates:

<script>
function addBook(bookId, extendedBookName) {
    var idInput = jQuery('#myForm\\:bookNames');
    if (idInput.val(bookId).val() != bookId) {
        var newOption = jQuery('<option>').val(bookId).text(extendedBookName);        
        idInput.append(newOption).val(bookId);
    }
}
</script>

Demo: http://jsfiddle.net/nTtY9/1/

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top