I too, was surprised by the lack of a template-based  component
inplementation by default in tapestry.  Here is my simple
implementation based on BaseComponent:

import java.util.LinkedList;
import java.util.List;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRender;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.ITemplateComponent;
import org.apache.tapestry.engine.IPageLoader;
import org.apache.tapestry.form.AbstractFormComponent;
import org.apache.tapestry.spec.IComponentSpecification;

public abstract class BaseFormComponent extends AbstractFormComponent implements
                ITemplateComponent {
        List<IRender> outerComponents;

        private List<IRender> getOuterComponents() {
                if (outerComponents == null) {
                        outerComponents = new LinkedList<IRender>();
                }
                return outerComponents;
        }

        protected void renderFormComponent(IMarkupWriter writer, IRequestCycle 
cycle) {
                renderEverything(writer, cycle);
        }

        private void renderEverything(IMarkupWriter writer, IRequestCycle 
cycle){
                for (IRender render : getOuterComponents()) {
                        render.render(writer, cycle);
                }
        }
        protected void rewindFormComponent(IMarkupWriter writer, IRequestCycle 
cycle) {
                renderEverything(writer, cycle);
        }

        public void addOuter(IRender element) {
                getOuterComponents().add(element);
        }

        public void finishLoad(IRequestCycle cycle, IPageLoader loader,
                        IComponentSpecification specification) {
                loader.loadTemplateForComponent(cycle, this);
                super.finishLoad(cycle, loader, specification);
        }
}




On 10/24/06, Matt Kerr <[EMAIL PROTECTED]> wrote:
I find Tapestry ok for generating html, but I'm struggling on the
request processing.  I don't think I'm alone .. I see many references
to this topic on the mailing list archive -- and it's not very well
described in the documentation :-?

Specifically, reusable components participating in request processing.

How can my component gather information in the request, and return an
object to its caller (eg. the page, or another component).  I'm
looking at the point in time *after* my component has received it's
request values, but *before* the page has invoked the listener action.

Also, I'd like to use an html template .. (What's the point in using
Tapestry if I'm writing my html *in the Java*??)
~~~
public void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
{
   writer.begin("a");
   writer.attribute("href", . . .);
   writer.attribute("title", getTitle());
~~



I'm imagining something like .. FooPage and DatePicker component --
where the DatePicker hands a Date object to the page.  A Date object
which the DatePicker creates from the FORM/request values sent to the
app.  eg. ..

        http://host:port/foo/blah?year=2006&month=10&day=24


What does DatePicker.java implementation look like ??

Can I use a template ?  (Or do I have to write the html *in* the java
with IMarkupWriter, etc??)

Is there a callback for the point in time I mention above?  .. where
the component is filled in by the framework, and it has an
opportunity to perform it's purpose, and then processing continues
elsewhere--like in the caller.

I believe "listener" callback isn't an option because you're not
guaranteed of the order.

The examples I'm reading online all break encapsulation and just have
the caller get the M/D/Y from the component so that the *caller*
creates the date.  That's completely wrong -- and defeats the purpose
of a "reusable component" .. since the caller is doing the work.

Any ideas greatly appreciated.

My sketch goes something like this (below).  I'm really wondering
what DatePicker.java does to push a value back to the caller *before*
the caller's action() method is called.

Thanks,
Matt

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

FooPage.html
~~~~~~~~~~~~
        ..
        Start- <span jwcid="@DatePicker" date="ognl:startDate" />
        End-   <span jwcid="@DatePicker" date="ognl:endDate" />
        ..
~~~~~~~~~~~~

FooPage.java
~~~~~~~~~~~~
        ..
        public abstract Date getStartDate();
        public abstract void setStartDate(Date value);
        public abstract Date getEndDate();
        public abstract void setEndDate(Date value);
        ..
        public void submitAction() {
                Date d = getStartDate();  // THIS SHOULD BE VALID HERE - no work
needed by caller FooPage
        }
        ..
~~~~~~~~~~~~


DatePicker.jwc
~~~~~~~~~~~~~~
        ..
        <parameter name="date" required="yes" />
        ..
~~~~~~~~~~~~~~

DatePicker.java
~~~~~~~~~~~~~~
        * don't want to use Listener -- it could be called out of order
        * don't want to use renderComponent() -- i'd rather just write the
html than bury the html *in* java
        * .. ???

        what's the trick ?
~~~~~~~~~~~~~~






Here's one example of an attempt to do this.

Is there a guarantee that setYear() is called last (after setMonth()
and setDay()) ??



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package ws.sundraw.tapestry.components;

import java.util.Calendar;

import org.apache.tapestry.BaseComponent;
import org.apache.tapestry.IBinding;
import org.apache.tapestry.form.IPropertySelectionModel;

/**
  *  Implements a component that accepts date input and is rendered
  *  as three HTML &lt;select&gt; elements, for day, month and year.
  *  Months are shown by their names (January, February etc.) and are
  *  automatically localized according to the preferred locale of the
page
  *  where the component is used
  *
  *  @author Alexander Kolesnikov (www.sundraw.ws)
  *  @version 1.0
  *
  **/

public abstract class DateInput extends BaseComponent {

        private int d, m, y;
        private Calendar c;

        protected void initialize() {
                d = m = 1;
                y = 2000;
                c = null;
        }

        public IPropertySelectionModel getDaysModel() {
                return new DayModel();
        }

        public IPropertySelectionModel getMonthsModel() {
                return new LocalizedMonthsModel(getPage().getLocale());
        }

        public IPropertySelectionModel getYearsModel() {
                return new YearModel();
        }

        public int getDay() {
                c = readDate();
                d = c.get(Calendar.DATE);
                return d;
        }

        public void setDay(int day) {
                d = day;
        }

        public int getMonth() {
                m = c.get(Calendar.MONTH) + 1;
                return m;
        }

        public void setMonth(int month) {
                m = month;
        }

        public int getYear() {
                y = c.get(Calendar.YEAR);
                return y;
        }

        public void setYear(int year) {
                y = year;
                c.set(y, m - 1, d);
                upDate(c);
        }

        public Calendar readDate() {
                return (Calendar)getDateBinding().getObject("date", 
Calendar.class);
        }

        public void upDate(Calendar c) {
                getDateBinding().setObject(c);
        }

        public abstract IBinding getDateBinding();

}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~






---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to