简体   繁体   中英

<s:iterator not working properly for a list, i am using struts2

I have as:iterator which is iterating a property list, For each item in the list has the properties key,value and category.On the basis of category,I need to populate the values to divs defined inside the iterator. I am using jquery tabs. Here the iterator not iterating properly.Please look the code it is easy to understand

<div id="tabs">
    <ul>
        <li><a href="#channel">Channel</a></li>
        <li><a href="#connection">Connection</a></li>                                        
    </ul>

    <s:iterator value="property" status="rowstatus">

        <div id="channel">
            <s:if test="(property[#rowstatus.index].category=='Channel')">
                <table>
                    <tr><s:hidden name="property[%{#rowstatus.index}].key" />
                        <td><s:label value="%{property[#rowstatus.index].key}">    </s:label></td>
                        <td> <s:textfield name="property[%{#rowstatus.index}].value">
                            </s:textfield>
                        </td>                                                      
                    </tr>
                </table>
            </s:if>

        </div>

        <div id="connection">

            <s:if test="(property[#rowstatus.index].category=='Connection')">
                <table>
                    <tr><s:hidden name="property[%{#rowstatus.index}].key" />
                        <td><s:label value="%{property[#rowstatus.index].key}"></s:label></td>
                        <td> <s:textfield name="property[%{#rowstatus.index}].value">
                            </s:textfield>
                        </td>                                                      
                    </tr>
                </table>
            </s:if>

        </div>

    </s:iterator>
</div>

Change JSP

<div id="tabs">
    <ul>
     <li><a href="#channel">Channel</a></li>
     <li><a href="#connection">Connection</a></li>                                        
    </ul>
    <div id="channel">
       <table>
              <s:subset source="property" decider="channelDecider">
                <s:iterator var="channel">
                  <tr><s:hidden name="property[%{property.indexOf(#channel)}].key" />
                    <td><s:label value="%{#channel.key}">    </s:label></td>
                    <td> <s:textfield name="property[%{property.indexOf(#channel)}].value" value="%{#channel.value}">
                        </s:textfield>
                    </td>                                                      
                  </tr>
                </s:iterator>
              </s:subset>
        </table>           
    </div>

    <div id="connection">

       <table>
              <s:subset source="property" decider="connectionDecider">
                <s:iterator var="connection">
                  <tr><s:hidden name="property[%{property.indexOf(#connection)}].key" />
                    <td><s:label value="%{#connection.key}">    </s:label></td>
                    <td> <s:textfield name="property[%{property.indexOf(#connection)}].value" value="%{#connection.value}">
                        </s:textfield>
                    </td>                                                      
                  </tr>
                </s:iterator>
              </s:subset>
        </table>           
    </div>
</div>

Create deciders

 public Decider getChannelDecider() {
 return new Decider() {
     public boolean decide(Object element) throws Exception {
         return ((MyElement)element).category.equals("Channel");
     }
 };
 }

 public Decider getConnectionDecider() {
 return new Decider() {
     public boolean decide(Object element) throws Exception {
         return ((MyElement)element).category.equals("Connection");
     }
 };
 }

Note, MyElement is a list element type that has corresponding properties.

The iterator works fine.

You're creating a div for each item in the collection, not each group of like items.

While <s:subset> will work, as an alternative, I'd propose a simpler, less-S2-centric solution.

Additional MyElement code:

public class MyElement {
    public boolean isChannel()    { return category.equals("Channel");    }
    public boolean isConnection() { return category.equals("Connection"); }
}

I'm not a fan of using strings to indicate types.

There are a number of ways the list could be broken apart; manually in the action, which is easy and quick; via a utility class, nice if you need this functionality in several places; etc.

A possible utility class:

public class MyElementSplitter {
    // Also getters for both of these; possibly wrapped with an immutable collection.
    private List<MyElement> channels    = new ArrayList<>();
    private List<MyElement> connections = new ArrayList<>();

    public MyElementSplitter(List<MyElement> elements) {
        for (MyElement element: elements) {
            if (element.isChannel()) {
                channels.add(element);
            } else if (element.isConnection()) {
                connections.add(element);
            }
        }
    }
}

Notes: this could be enhanced significantly, especially if you have additional types. If the types aren't determined by strings, you can play a lot of nice games with making the code general-purpose to expose other types as well.

In the action you categorize the elements and expose the splitter to the view:

private MyElementSplitter elements; // And getter.

public String execute() {
    // And any additional processing, list retrieval, etc.
    elements = new MyElementSplitter(allElements);
    return SUCCESS;
}

Then in the view:

<div id="channel">
    <s:iterator value="elements.channels" status="stat">
        <table>
            <tr>
                <s:hidden name="property[%{#stat.index}].key" />
                <td><s:label value="%{property[#stat.index].key}" /></td>
                <td><s:textfield name="property[%{#stat.index}].value" /></td>
            </tr>
        </table>
    </s:iterator>
</div>

<div id="connection">
    <s:iterator value="elements.connections" status="stat">
        <table>
            <tr>
                <s:hidden name="property[%{#stat.index}].key" />
                <td><s:label value="%{property[#stat.index].key}" /></td>
                <td><s:textfield name="property[%{#stat.index}].value" /></td>
            </tr>
        </table>
    </s:iterator>
</div>

If these sections will always be identical then I'd wrap them up in a JSP-based custom tag.

That would leave us with the following:

<div id="tabs">
    <ul>
        <li><a href="#channel">Channel</a></li>
        <li><a href="#connection">Connection</a></li>
    </ul>

    <app:elementTab id="channel"    values="elements.channels"    />
    <app:elementTab id="connection" values="elements.connections" />
</div>

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