Details
-
Improvement
-
Status: Open
-
Minor
-
Resolution: Unresolved
-
Future
-
None
-
Operating System: All
Platform: All
-
17473
Description
2 problems have been identified for this type of inclusion :
Let's start with a sample code :
Here is a sample main jsp (main.jsp) :
<%@taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<html:form method="post" action="/submit">
<html:iterate name="myForm" property="tab" id="tab" indexId ="index"
scope="request">
<jsp:include page="/included.jsp" flush="true" />
</html:iterate>
</html:form>
Here is a sample included jsp (included.jsp) :
<%@taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
Personne <bean:write name="index"><br>
Nom <html:text name="tab" property="firstName" indexed="true" /><br>
Prenom <html:text name="tab" property="lastName" indexed="true" /><br>
The first problem is that in the included jsp, it is impossible to access to
the differents properties given by each iteration : The error message
is "cannot find bean index in any scope"
One proposed solution is to use <bean:define> into the <logic:iterate> tag and
to add the index bean and the tab bean in scope session instead of scope page.
This solution doesn't seams to work : the error message is the same.
Another solution could be to modify the doStartTag() and doAfterBody() method
of the o.a.s.taglib.logic.IterateTag class to store the two bean in request
instead of page context.
My tested solution is to redefine the <logic:iterate> tag. I have created a
<perso:iterate> tag with the class PersoIterateTag wich extends IterateTag,
redefining his doStartTag() and doAfterBody() method :
public doStartTag() throws JspException {
int result = super.doStartTag();
if (result == EVAL_BODY_TAG) {
Object o = pageContext.getAttribute(id);
if (o == null)
else
{ pageContext.getRequest().setAttribute(id,o); }o = pageContext.getAttribute(indexId);
if (o != null) { pageContext.getRequest().setAttribute(indexId,o); }
}
return result;
}
public doAfterBody() throws JspException {
int result = super.doAfterBody();
if (result == EVAL_BODY_TAG) {
Object o = pageContext.getAttribute(id);
if (o == null) { pageContext.getRequest().removeAttribute(id); } else { pageContext.getRequest().setAttribute(id,o); }
o = pageContext.getAttribute(indexId);
if (o != null)
}
return result;
}
Modifying the first jsp (main.jsp) to use this tag, there is no problem for
finding the bean anymore.
But, here comes the second problem : the indexed property of tag <html:text>
provides a way to generate a <html input="text"> type tag with a name property
like "tab[0].firstName".
To do this, when the indexed property is true into the <html:text> tag, the
method prepareIndex() from o.a.s.taglib.html.BaseHanderTag class is called.
But into this method the first operation consists in calling the
findAncestorWithClass() method to get the instance of the IterateTag wich
correspond to the <logic:iterate>.
In this case the <logic:iterate> tag isn't in the same page than the
<html:text> tag, and so an error message comes: "indexed="true" is only valid
within an enclosing iterate tag"
This problem seems to be a scope problem : the corresponding instance for
<logic:iterate> is into the page scope, that's why the included jsp cannot
recover his instance.
One solution to fixe this problem can be to add two property to the <html:text>
(and to similar tag) :
- indexName : The name of the bean containing the current value of the index
(in this exemple "index") - indexScope : The scope where this bean can be found.
This properties could be added to the o.a.s.taglib.html.BaseHandlerTag class
with the corresponding getter and setter method.
On begining of the prepareIndex() method of this class, the following code
could be added :
protected void prepareIndex(StringBuffer handlers, String name) throws
JspException {
if (indexName != null) {
Integer index = (Integer)RequestUtils.lookup
(pageContext,indexName,indexScope);
if (index == null)
if (name != null)
handlers.append(name);
handlers.append("[");
handlers.append(index);
handlers.append("]");
if (name != null)
handlers.append(".");
return;
}
...
}
On the end of the release() method of this class, the following code could be
added :
indexName = null;
indexScope = null;
Finally, the struts-html.tld file has to be modified, addding the following
line to each tag wich can use it :
<attribute>
<name>indexName</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>indexScope</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
With this modification the folowing jsp code will now work :
Here is the new main jsp (main.jsp) :
<%@taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@taglib uri="/WEB-INF/struts-perso.tld" prefix="logic" %>
<html:form method="post" action="/submit">
<logic:iterate name="myForm" property="tab" id="tab" indexId ="index"
scope="request">
<jsp:include page="/included.jsp" flush="true" />
</logic:iterate>
</html:form>
Here is the new included jsp (included.jsp) :
<%@taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
Personne <bean:write name="index"><br>
Nom <html:text name="tab" property="firstName" indexName="index"
indexScope="request" indexed="true" /><br>
Prenom <html:text name="tab" property="lastName" indexName="index"
indexScope="request" indexed="true" /><br>