tags:

views:

427

answers:

2

I have this form:

<h:form>
    <h:outputText value="Tag:" />   
    <h:inputText value="#{entryRecorder.tag}">
        <f:ajax render="category" />
    </h:inputText>
    <h:outputText value="Category:" />
    <h:inputText value="#{entryRecorder.category}" id="category" />
</h:form>

What I'm trying to achieve: When you type in the "tag" field, the entryRecorder.tag field is updated with what was typed. By some logic upon this action the bean also updates its category field. This change should be reflected in the form.

Questions:

  1. What scope shall I use for EntryRecorder? Request may not be satisfactory for multiple AJAX requests, while session will not work with multiple browser windows per one session.
  2. How can I register my updateCategory() action in EntryRecorder so that it is triggered when the bean is updated?
A: 

Answering point 2:

<h:inputText styleClass="id_tag" value="#{entryRecorder.tag}"
    valueChangeListener="#{entryRecorder.tagUpdated}">
    <f:ajax render="category" event="blur" />
</h:inputText>

Bean:

@ManagedBean
@ViewScoped
public class EntryRecorder {
    private String tag;
    private String category;
    @EJB
    private ExpenseService expenseService;

    public void tagUpdated(ValueChangeEvent e) {
        String value = (String) e.getNewValue();
        setCategory(expenseService.getCategory(value));
    }
}

Number 1, anybody?

Konrad Garus
A: 

To point 1, I'll use Request since there is no need to use View and Session is, as you well pointed, completely unnecessary.

For point 2, since you are using <f:ajax/> I suggest making full use of it. Here is my proposal:

xhtml:

<h:form>
    <h:outputText value="Tag:" />
    <h:inputText value="#{entryRecorder.tag}">
        <f:ajax render="category" event="valueChange"/>
    </h:inputText>
    <h:outputText value="Category:" />
    <h:inputText value="#{entryRecorder.category}" id="category" />
</h:form>

Note the use of valueChange event instead of blur (not that blur doesn't work but I find valueChange more 'proper' for a value holder component).

bean:

@ManagedBean
@RequestScoped
public class EntryRecorder {
    private String tag;
    private String category;

    public String getCategory() {
        return category;
    }

    public String getTag() {
        return tag;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public void setTag(String tag) {
        this.tag = tag;
        tagUpdated();
    }

    private void tagUpdated() {
        category = tag;
    }
}

Unless you really want the tagUpdated method executed only when tag is updated through the view, my proposal looks more clear. You don't have to deal with the events (nor casting) and the tagUpdated method can be private hiding it's functionality from possible misuses.

Toni Penya
If this bean for some reason is heavy, the request scope approach does not seem to be optimal.
Konrad Garus
"If this bean for some reason is heavy, the request scope approach does not seem to be optimal." -- Granted.If you have a VERY heavy bean you should think about splitting it or even encapsulating the tag-category inputs into a custom component rather than changing de scope of the bean just because it makes your application run smoother (Did you run some performance tests?) instead of because it makes sense.
Toni Penya