Search code examples
javatilesapache-tiles

Dynamically composing pages using tiles


I'm a new tiles user and love it so far. But I face a problem now and I'm not sure that tiles is the right tool in my hand to achieve my aims.

What I would like to do is to create a general registration form, shared between several sites. This registration form will be slightly different on each sites. So clearly they could use the same jsp files and java codes. My aim is to have a .properties files in which I can configure which input form fragments should be included in the form and which should not (for each sites).

Is there any way to dynamically insert attributes?

I have created a view preparer class. This way I can add/override existing attributes.

public class TestViewPreparer extends ViewPreparerSupport {
    public void execute(TilesRequestContext tilesContext, AttributeContext attributeContext) throws PreparerException {
        Attribute attribute = new Attribute("/WEB-INF/views/search-panel/holiday-type.jsp");
        attributeContext.putAttribute("rfFragment", attribute);
    }
}

But this only add/override one attribute at time. Besides in the template file I have to add the following line for each of them.

<tiles:insertAttribute name="rfFragment1" />
<tiles:insertAttribute name="rfFragment2" />
    //... etc

What I'm looking for is more like adding a list of Attributes and include them in the template line with a loop. Somehow like this:

    <tiles:useAttribute id="fragments" name="rfFragments" classname="java.util.List" />
    <c:forEach var="fragment" items="${fragments}">
        <tiles:insertAttribute value="${fragment}" flush="true" /></c:forEach>

My problem is that AttributeContext can take only one Attribute and cannot a List of Attributes. Or Did I miss something?

I hope I described my problem enough , given the details.


Solution

  • I'm currently working on a similar issue trying to create a dynamic navigation menu within a tile using ViewPreparer. According to the post linked below, you can pass ArrayLists via TilesRequestContext instead of using AttributeContext. I haven't completely gotten it to work myself, but maybe these links will help whoever is looking for this in the future (took me forever to find good examples)

    ViewPreparer example

    Injecting the controller with Spring

    My implementation:

    public class HeaderController extends ViewPreparerSupport{
    private EvalTypesService evalTypesService;
    
    @Autowired
    public HeaderController(EvalTypesService evalTypesService){
        this.evalTypesService = evalTypesService;
    }
    
    @Override
    public void execute(TilesRequestContext tilesContext, AttributeContext attributeContext) throws PreparerException{
        List<EvalMasterEvaluationType> evalTypes = evalTypesService.getAllActiveEvalTypes();
        tilesContext.getRequestScope().put("evalTypes", evalTypes);
    }
    

    }

    Definition in view.xml:

    <definition name=".mainTemplate" template="/WEB-INF/views/main_template.jsp" preparer="myPathToController.HeaderController">
        <put-attribute name="header" value="/WEB-INF/views/tiles/header.jsp" />
        <put-attribute name="content" value="" />
        <put-attribute name="footer" value="/WEB-INF/views/tiles/footer.jsp" />
    </definition>
    

    Tiles Beans in dispatch servlet xml:

    <bean class="org.springframework.web.servlet.view.tiles2.TilesViewResolver"/>
    
    <bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
        <property name="definitions">
            <list>
                <value>/WEB-INF/views/**/views.xml</value>
            </list>
        </property>
        <property name="preparerFactoryClass" value="org.springframework.web.servlet.view.tiles2.SimpleSpringPreparerFactory" /></bean>
    

    In the header.jsp tile:

    <div id="nav">
    <c:out value="${msg}"></c:out>
    <ul>
        <c:forEach var="type" items="${evalTypes}">
        <li><a href="<s:url value="/evalTypes/${type.id}" />"><c:out value="${type.name}" /></a></li>
    
        </c:forEach>
    </ul>