简体   繁体   中英

generate dates label dynamically in JSF primefaces

in a page I have an InputText box for the duration of a priod (months as int) and ap:calendar input for picking a intial date. I need to generate labels (month-year) for all months from the intial date. for example, if duration is 3 and intial date is 10-dec-2014, three following labels should be generated: Dec-2014 Jan-2015 Feb-2015 I tried to do it without backing bean:

<c:forEach var="i" begin="1" end="${myBean.duration}">
                        <p:outputLabel value=" ${i+myVar} ${year+1900} " />
                        <h:panelGrid columnClasses="input, slider" columns="2">
                            <p:inputText id="inputTxt_${i}" style="width:70px;" />
                            <p:slider for="inputTxt_${i}"
                                style="padding-left: 100px; margin-left:5px">
                                <p:ajax event="slideEnd" />
                            </p:slider>
                        </h:panelGrid>

but in this way I can not correctly generates the labels. Anyone knows how to do this by using JSF or Backing bean with or without a submit button(for example using events such as event="keyup" or event="dateSelect") ??

Whenever I do dynamic jsf-stuff like you are trying to do, I tend to create the components in java via a backing bean. This is mainly due to the reason that I feel more comfortable writing conditional statements or loops in an established programming language and the results become more understandable in my opinion. To do so, you would need to define a component with a binding to a backing bean. JSF will insert that element to your bean on creation using a setter method and retrieve it via the corresponding getter on every update. In between, you can basically do whatever you want to the component. That includes removing and adding children, changing attributes, etc. So in your case, you could define your html-markup as follows:

<h:form id="dateform">
    <!-- calendar for setting the date -->
    <p:calendar value="#{backingbean.date}">
        <p:ajax event="change" update=":#{p:component('dateform')}" />
    </p:calendar>
    <!-- input for setting the duration -->
    <p:inputText value="#{backingbean.duration}">
        <p:ajax event="change" update=":#{p:component('dateform')}" />
    </p:inputText>
    <!-- panel for printing the labels, bound to a backingbean -->
    <p:outputPanel binding="#{backingbean.labelPanel}" />
</h:form>

The important part here is the outputPanel provided by the primefaces library. It's content will be bound to a backing-bean and updated whenever the values for the calendar or the duration changes. For the backing bean, apart from setters and getters for Date and duration, you would also need a getter and setter for labelPanel, so that JSF is able to populate the component to the bean:

private Date date;
private int duration;
private OutputPanel panel;

public Date getDate() {
    return this.date;
}

public void setDate(Date date) {
    this.date = date;
    this.updatePanel();
}

public int getDuration() {
    return this.duration;
}

public void setDuration(int duration) {
    this.duration = duration;
    this.updatePanel();
}

public OutputPanel getLabelPanel() {
    return this.panel;
}

public void setLabelPanel(OutputPanel panel) {
    this.panel = panel;
}

private void updatePanel() {
    if (this.panel != null) {
        this.panel.getChildren().clear();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(this.date);
        for (int i = 0; i < this.duration; i++) {
            calendar.add(Calendar.MONTH, 1);
            OutputLabel label = new OutputLabel();
            label.setValue(calendar.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault()));
            this.panel.getChildren().add(label);
        }
    }
}

As you can see, every time the setter for date or duration is called, the code will dynamically build OutputLabel elements and add them to the OutputPanel managed by your bean.

I'm sure there are loads of other solutions for your problem, but this is the way I personally would implement this and it usually works fine.

I think your xhtml-Structure is not correct.

  • You are missing the closing </c:forEach>
  • If closed at the end of the code-snippet you would get {i} Sliders

Assuming you want one slider and {i} outputs of the dates

  • Establish a BackingBean to hold your values
  • values are: "monthCount" holding the integer, "dateList" holding the (calculated) dates
  • listener-Method to calculate the dates, according to integer-input by the slider public void listenerMonthCount(SlideEndEvent ae)

     <h:form id="form"> <h:panelGrid columns="2"> <p:inputText id="monthCount" style="width:70px;" value="#{backingBean.monthCount}" /> <p:slider for="monthCount" style="padding-left: 100px; margin-left:5px" maxValue="12"> <p:ajax event="slideEnd" process="@form" listener="#{backingBean.listenerMonthCount}" update="form" /> </p:slider> </h:panelGrid> <ui:repeat var="month" value="#{backingBean.dateList}"> <h:outputText value="#{month}"> <f:convertDateTime pattern="MMM-yyyy" /> </h:outputText> <br /> </ui:repeat> </h:form> 

Explanation in more detail: The p:ajax -Tag not only needs the event -Attribute, but also needs to be told what to do. So define the listener listener="#{backingBean.listenerMonthCount}" . For the listener to know the newly chosen monthValue, it must be transferred to the server process="@form" is used to transfer all values in this form from the client to server. update="form" instructs to update all values after the listener is processed.

The <ui:repeat> -Block contains rendering of your output. It iterates over the List<Date> and assignes every item to the variable month . This is printed and formatted with f:convertDataTime wich takes a Java-DateFormatPattern as pattern -Attribute.

In your Backing-Bean you essentially need this

private int monthCount = 0; // +getter/setter

private List<Date> dateList = new ArrayList<Date>(); // +getter/setter

public void listenerMonthCount(SlideEndEvent ae) {
    dateList.clear(); // clear the list to remove entries from possible old runs
    if (monthCount > 0) {
        Date now = new Date();
        dateList.add(now); // add first date
        Calendar cal = Calendar.getInstance();
        for (int i = 1; i < monthCount; i++) {
            cal.setTime(dateList.get(dateList.size() - 1)); // get last date from list and set calendar
            cal.add(Calendar.MONTH, 1);// add one month
            dateList.add(cal.getTime()); // add calculated date
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM