You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Franz Amador <fg...@gmail.com> on 2008/05/01 01:02:40 UTC

T5: Ajax update of one form field based on change to another form field?

Hi, all.  I asked about this a while ago, and there was no good answer
then, but I'm hoping that there are new options now.  I have a bean
that holds information about a database connection.  I'm editing it
with BeanEditForm.  One of the fields is the database type, an enum
that renders as a dropdown.  Another field is the database-server
port.  When the user picks a database type from the dropdown, I want
to update the database port to the default value for that database
type (e.g. 1521 for Oracle), while leaving the other fields alone.  Is
there a good way to do this?

I see there's now a zone parameter to BeanEditForm that causes the
specified zone to be updated when the form is submitted.  This sounds
promising, but I don't see how to make it work for my case.

1) I would need to make the form auto-submit when the user picks a
value from the dropdown.  I don't know how to do that, but there must
be a way.

2) I would need a way to prevent validation from complaining about
missing or errant fields during the form auto-submit, but to have
validation work normally during a regular form submit (via the submit
button).

3) I would need the form to do an Ajax zone update on an auto-submit
(for a zone containing the form itself), but not on a regular form
submit.

On the whole, I prefer Tapestry 5 to Wicket, but for Ajax, I think
Wicket's approach has some advantages.  In Wicket, you can register an
event listener on a component (e.g. an on-change listener on a
dropdown).  When the event happens, the listener method gets passed a
list to which it appends components that should be re-rendered.  In my
case, I'd append the database-port-field component to the list when
the database-type enum changes value.  This approach allows me to
update multiple components anywhere on the page in response to any
event, with no need for a special update-target-wrapper component like
Zone.  (You do have to call "setOutputMarkupId(true)" when creating a
component that can be rendered via Ajax.)

I hope this doesn't come across as a "Wicket is better than Tapestry"
taunt.  I've experimented with both at some length, and I find
Tapestry 5 tighter and leaner and faster.  However, I really need
richer Ajax tools, and I think the Wicket approach is worth looking
at.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: T5: Ajax update of one form field based on change to another form field?

Posted by Franz Amador <fg...@gmail.com>.
Thank you VERY much.  That works like a champ... except I keep getting
an exception in the log, though it doesn't affect the UI.  Here's the
way I ran with your suggestions.  First, the tml:

    <t:beaneditform t:id="beanEditForm" object="propertiesBean"
submitlabel="message:save-label">
      <t:parameter name="type">
        <t:label for="type"/>
        <t:select t:id="type" value="propertiesBean.type"
                  t:mixins="t5components/OnEvent" event="change"
onCompleteCallback="typeChanged"/>
      </t:parameter>
      <t:parameter name="port">
        <t:label for="port"/>
        <t:textfield t:id="port" value="propertiesBean.port"/>
      </t:parameter>
    </t:beaneditform>

    <script type="text/javascript">
      function typeChanged(response) {
        $('port').value = response;
      }
    </script>

Next, the page java:

    StreamResponse onChangeFromType(String typeName) {
        DatabaseType type = DatabaseType.valueOf(typeName);
        return new TextStreamResponse("text/plain",
String.valueOf(type.getDefaultPort()));
    }

And lastly, the exception:

java.io.IOException: The filename, directory name, or volume label
syntax is incorrect
	at java.io.WinNTFileSystem.canonicalize0(Native Method)
	at java.io.Win32FileSystem.canonicalize(Win32FileSystem.java:395)
	at java.io.File.getCanonicalPath(File.java:531)
	at org.mortbay.util.FileResource.getAlias(FileResource.java:176)
	at org.mortbay.http.ResourceCache.getResource(ResourceCache.java:251)
	at org.mortbay.http.HttpContext.getResource(HttpContext.java:2118)
	at org.mortbay.jetty.servlet.WebApplicationContext.getResource(WebApplicationContext.java:785)
	at org.mortbay.jetty.servlet.ServletHandler.getResource(ServletHandler.java:735)
	at org.mortbay.jetty.servlet.ServletHandler$Context.getResource(ServletHandler.java:1082)
	at org.apache.tapestry.internal.services.ContextImpl.getResource(ContextImpl.java:43)
	at $Context_119abd0bad3.getResource($Context_119abd0bad3.java)
	at $Context_119abd0ba6e.getResource($Context_119abd0ba6e.java)
	at org.apache.tapestry.internal.services.StaticFilesFilter.service(StaticFilesFilter.java:56)
	at $RequestHandler_119abd0ba72.service($RequestHandler_119abd0ba72.java)
	at nu.localhost.tapestry.acegi.services.internal.RequestFilterWrapper$1.doFilter(RequestFilterWrapper.java:60)
	at nu.localhost.tapestry.acegi.services.internal.AcegiExceptionTranslationFilter.doFilter(AcegiExceptionTranslationFilter.java:67)
	at nu.localhost.tapestry.acegi.services.internal.RequestFilterWrapper.service(RequestFilterWrapper.java:54)

with lots more frames below.  Using the debugger, I find that Jetty is
getting a request for a URL that looks like this:

/myapp/admin/database.type:change/MYSQL_5

which it's passing to File.getCanonicalPath as this:

C:\ResearchWorkspace\myapp-tapestry5\src\main\webapp\admin\database.type:change\MYSQL_5

which it doesn't like.  Any ideas?  MYSQL_5 is, of course, a value for
my database-type enum.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: T5: Ajax update of one form field based on change to another form field?

Posted by Chris Lewis <ch...@bellsouth.net>.
Sorry I was vague on that, and I was referring to the t5components
OnEvent mixin
(http://87.193.218.134:8080/t5components/t5c-commons/ref/org/apache/tapestry/commons/mixins/OnEvent.html).
Here's a quick example of ajax-based data retrieval. Note that where I
use hard-coded strings, you'd be using your database information bean
(or whatever). First you need your template:

        <form t:type="form">
            <t:select t:id="mySelect" model="selectOptions"
value="selected" t:mixins="t5components/OnEvent"
                event="change" onCompleteCallback="selectionChanged"/>
            <t:textfield value="port" t:id="dbPort"/>
            <br/><input t:type="submit"/>
        </form>
       
        <script type="text/javascript">
            function selectionChanged(response) {
                $('dbPort').value = response;
            }
        </script>

The first thing to notice is the use of the onevent mixin, and notice
the subsequent parameters (event="change" and
onCompleteCallback="selectionChanged"). The 'event' parameter notifies
the mixin of which client side event it should bind to, while the
'onCompleteCallback' parameter is the name of an in-scope javascript
function that will receive the ajax response from the server. Also
notice our hard-coded script block in which we declare the named handler
'selectionChanged' - in which we set the value of the field by id
'dbPort' (which if you look at the form, you'll see that we created a
textfield with that id). Now the event handler in the page class:

    public StreamResponse onChangeFromMySelect(String value) {
        logger.info(" changed: " + value);
        return new TextStreamResponse("text/plain",
value.equals("Oracle") ? "1521" : "3306");
    }

This is obviously a stupid implementation in that it tests for the
string "Oracle" and returns "1521", other wise "3306" as a plain-text
response, but it shows how to check for what was selected and how to
return something. Now if you fill in the simple missing parts of this,
you'll see that it works by retrieving values from the server based on
the selection in an asynchronous manner. The OnEvent mixin really opens
the door to a much wider potential of data binding, but by itself it
gives you some raw tools to do what you want.

> As for Ajax support being still in the oven, I'm really hoping it's
> coming out soon.
>   
I imagine it will stop baking when web development methodologies stop
changing. I said 'in the oven' because there are still and handful unmet
goals outstanding in the ajax area. There are a few useful things now,
and I'd say you can bet on the fact that the innovative strides in the
ajax part will be as innovative as those in the rest of the framework.

-- 
http://thegodcode.net


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: T5: Ajax update of one form field based on change to another form field?

Posted by Franz Amador <fg...@gmail.com>.
On Thu, May 1, 2008 at 4:25 AM, Chris Lewis <ch...@bellsouth.net> wrote:
>  Why would you need to submit the form when a value is selected from the
>  list? If you know the available DBs before hand, then you know the
>  default ports. Store those as a client-side JSON object and use the
>  select's onchange event.

> ...

>  While tapestry's Ajax support is still in the oven, it has @OnEvent
>  which does something similar [to Wicket].

I don't want to submit the form.  It just appeared that that was the
only way to use the zone parameter on BeanEditForm to get what I want.
 It looks like you're proposing two alternatives:

1) Do it all client-side using JavaScript:  That would work for this
case, since I do know the mapping from DB types to DB ports in
advance.  I see two flaws, however.  The main one is that I have
other, similar cases in mind in which I'd need server-side computation
to update the form in response to field-change events.  Second, I
don't know JavaScript well and don't like it, so I'd really rather
keep it neatly encapsulated in components that somebody else writes.

2) Use @OnEvent:  Do form fields issue events, or is that planned for
the future?  If they do so now, could you tell me the event name for a
drop-down selection-made event, or tell me how to find it for myself?
I don't see any mention of events in the code for Select,
AbstractField, or Field.  Or do I need to use a mix-in?

As for Ajax support being still in the oven, I'm really hoping it's
coming out soon.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: T5: Ajax update of one form field based on change to another form field?

Posted by Chris Lewis <ch...@bellsouth.net>.

Franz Amador wrote:
> Hi, all.  I asked about this a while ago, and there was no good answer
> then, but I'm hoping that there are new options now.  I have a bean
> that holds information about a database connection.  I'm editing it
> with BeanEditForm.  One of the fields is the database type, an enum
> that renders as a dropdown.  Another field is the database-server
> port.  When the user picks a database type from the dropdown, I want
> to update the database port to the default value for that database
> type (e.g. 1521 for Oracle), while leaving the other fields alone.  Is
> there a good way to do this?
>
> I see there's now a zone parameter to BeanEditForm that causes the
> specified zone to be updated when the form is submitted.  This sounds
> promising, but I don't see how to make it work for my case.
>
> 1) I would need to make the form auto-submit when the user picks a
> value from the dropdown.  I don't know how to do that, but there must
> be a way.
>
>   
Why would you need to submit the form when a value is selected from the
list? If you know the available DBs before hand, then you know the
default ports. Store those as a client-side JSON object and use the
select's onchange event.
> 2) I would need a way to prevent validation from complaining about
> missing or errant fields during the form auto-submit, but to have
> validation work normally during a regular form submit (via the submit
> button).
>
> 3) I would need the form to do an Ajax zone update on an auto-submit
> (for a zone containing the form itself), but not on a regular form
> submit.
>
> On the whole, I prefer Tapestry 5 to Wicket, but for Ajax, I think
> Wicket's approach has some advantages.  In Wicket, you can register an
> event listener on a component (e.g. an on-change listener on a
> dropdown).  When the event happens, the listener method gets passed a
> list to which it appends components that should be re-rendered. 
While tapestry's Ajax support is still in the oven, it has @OnEvent
which does something similar.
>  In my
> case, I'd append the database-port-field component to the list when
> the database-type enum changes value.  This approach allows me to
> update multiple components anywhere on the page in response to any
> event, with no need for a special update-target-wrapper component like
> Zone.  (You do have to call "setOutputMarkupId(true)" when creating a
> component that can be rendered via Ajax.)
>
> I hope this doesn't come across as a "Wicket is better than Tapestry"
> taunt.  I've experimented with both at some length, and I find
> Tapestry 5 tighter and leaner and faster.  However, I really need
> richer Ajax tools, and I think the Wicket approach is worth looking
> at.
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>
>   

-- 
http://thegodcode.net


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org