You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Luis Salas <lu...@mayasoft.com.co> on 2014/07/24 17:41:40 UTC

AjaxFormLoop with nested Ajax select onValueChange event

Hi everyone.

I'm developing a refine search component that need to add field's rows 
dynamically, this rows contains 2  select components and by default a 
textbox. When I change the value of the first select I have to update 
the list of the second select and change the textbox to a component that 
match with the data type of the first select eg. if I selected in the 
first list a "String" type, the second select have to change options to 
the ones that String types have and the textbox will remain, but if I 
select a date type, the sencond select will change the options to the 
ones that date type have and the textbox change to a dateField. I have 
done this, but I have a problem when I add a new row, and I change the 
older row data type, it will update the new's second list and textbox. 
When I debug it, the zone injected i the java is the last one added and 
not the one changed.

I really don't know if is right to mix this components. If someone need 
the source code, just let me know and I will send it.

Tnx.

Luis

Re: AjaxFormLoop with nested Ajax select onValueChange event

Posted by Lance Java <la...@googlemail.com>.
FYI, I just updated the demo to show the power of the mixin
http://tapestry-stitch.uklance.cloudbees.net/observedemo

NB. I changed the name of the mixin from onEvent to observe.


On 24 July 2014 18:52, Lance Java <la...@googlemail.com> wrote:

> Take a look at the onEvent mixin here
>
> https://github.com/uklance/tapestry-stitch/blob/master/src/main/java/org/lazan/t5/stitch/mixins/OnEvent.java
>
> It allows you to pass multiple field values to the serverside event. That
> way, each event can be passed all the relevant clientside field values.
> Keeping your code @Persist free.
>

Re: AjaxFormLoop with nested Ajax select onValueChange event

Posted by Lance Java <la...@googlemail.com>.
Take a look at the onEvent mixin here
https://github.com/uklance/tapestry-stitch/blob/master/src/main/java/org/lazan/t5/stitch/mixins/OnEvent.java

It allows you to pass multiple field values to the serverside event. That
way, each event can be passed all the relevant clientside field values.
Keeping your code @Persist free.

Re: AjaxFormLoop with nested Ajax select onValueChange event

Posted by Erich Gormann <e....@gormann.de>.
Hi Luis,

sometime ago I wrote exact such a component for a complex fully generic 
working search panel with any number of search criteria and data types.
I faced exactly the same problems like you, because without doing a HTTP 
post on the complete page there is no standrad way to keep the state 
information of the select boxes after let them firing their onChange 
events.

The solution I found was to write a dedicated value encoder for the 
selects enabling them to keep state information after each ajax request.

I have to search for my solution and will it provide to you tomorrow.

Greetings, Erich


Am 24.07.2014 17:41, schrieb Luis Salas:
>
> Hi everyone.
>
> I'm developing a refine search component that need to add field's rows 
> dynamically, this rows contains 2  select components and by default a 
> textbox. When I change the value of the first select I have to update 
> the list of the second select and change the textbox to a component 
> that match with the data type of the first select eg. if I selected in 
> the first list a "String" type, the second select have to change 
> options to the ones that String types have and the textbox will 
> remain, but if I select a date type, the sencond select will change 
> the options to the ones that date type have and the textbox change to 
> a dateField. I have done this, but I have a problem when I add a new 
> row, and I change the older row data type, it will update the new's 
> second list and textbox. When I debug it, the zone injected i the java 
> is the last one added and not the one changed.
>
> I really don't know if is right to mix this components. If someone 
> need the source code, just let me know and I will send it.
>
> Tnx.
>
> Luis
>


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


Re: AjaxFormLoop with nested Ajax select onValueChange event

Posted by Erich Gormann <e....@gormann.de>.
Hi Luis,

in my component there is an icon enabling the user to add a new input 
row on the fly.
Each rendered input row has got an id which is incremented for  each new 
row. Because my filter criteria object is a field in the row object it 
is instantiated together with it and so I'm able to write the id of the 
new input row into each criteria object.

Later when triggering events by the criteria object it is a big 
advantage that each of them owns the id of "its own" finder row as 
property.

You can believe that it took sweat and tears to develope this component 
and get it into production.

Currently I'am still facing the problem that I do ajax calls on each 
onChange event triggered by a filter criteria object, but that values 
entered in an input field belonging to a search criterion object are 
lost after the call. I think this depends on the fact that there is no 
state given for input components in such a context.

Greetings, Erich




Am 28.07.2014 20:40, schrieb Luis Salas:
>
> Hi Erich, I'm doing the same you have done, I'm creating a Filter 
> component that will have as many input rows as users needs. Each row 
> use a filterCriteria object in which I will store the users input. I 
> need to do something like you did but I'm having some troubles 
> defining the client ids to use with the encoder. I had created a 
> FilterRow component which contains all the inputs needed.
> Can you let me see how you find the input line id?
>
> Tnx for your help.
>
>> Hi Luis,
>>
>> as an alternative I want to show you my solution given in the below 
>> listed
>> encoder class.
>> Each search criterion in my solution is represented by a type called
>> "TapestryClientCriterion". My generic search component renders any 
>> number
>> of "finder input lines" each having a list of possible search criteria
>> which can be selected in a drop down.
>> My solution is based on the simple approach just to add a piece of
>> information identifying the input line a criterion belongs to in the 
>> client
>> id of each criterion. So a criterions client id consists of its own 
>> id and
>> a scond identifying the input line concatenated together with a certain
>> delimiter token. This all is done via an encoder (see below).
>>
>> /**
>>      * This encoder has the task to provide each client side element 
>> of the
>>      * component with id "<strong>criterionSelector</strong>" with a 
>> value
>>      * identifying this element by the id of the finder input line it is
>>      * rendered in and its own id. Both ids are concatenated using 
>> the "~"
>> token
>>      * as delimiter. The server side representation will be restored by
>> looking
>>      * up for the correct "<strong>{@linkplain TapestryClientCriterion}
>>      * </strong>" in the correct "<strong>{@linkplain
>> FinderInputLine}</strong>"
>>      * using the information coded in the above mentioned 
>> concatenated string.
>>      * The only sense of this encoder is to make each rendered finder
>> criterion
>>      * unique by the above id, because criteria are rendered multiple 
>> times in
>>      * the loop iterations.
>>      *
>>      */
>>     private class ClientCriterionEncoder implements
>>             ValueEncoder<TapestryClientCriterion> {
>>
>>         /**
>>          * @see 
>> org.apache.tapestry5.ValueEncoder#toClient(java.lang.Object)
>>          * @param value
>>          * @return The id of the looped finder input line.
>>          */
>>         @Override
>>         public String toClient(TapestryClientCriterion value) {
>>
>>             String finderInputLineId = String.valueOf(value
>>                     .getFinderInputLineId());
>>             String criterionId = String.valueOf(value.getId());
>>
>>             return finderInputLineId + "~" + criterionId;
>>         }
>>
>>         /**
>>          * @see 
>> org.apache.tapestry5.ValueEncoder#toValue(java.lang.String)
>>          * @param clientValue
>>          * @return The finder input line for the given client id.
>>          */
>>         @Override
>>         public TapestryClientCriterion toValue(String clientValue) {
>>
>>             TapestryClientCriterion clientCriterion = null;
>>
>>             try {
>>
>>                 String[] idParts = clientValue.split("~");
>>                 String finderInputLineIdStr = idParts[0];
>>                 String criterionIdStr = idParts[1];
>>                 int finderInputLineId = 
>> Integer.parseInt(finderInputLineIdStr);
>>                 long criterionId = Long.parseLong(criterionIdStr);
>>
>>                 // find the correct line
>>                 for (FinderInputLine finderInputLine : finderCallback
>>                         .getFinderInputLinesToRender()) {
>>
>>                     if (finderInputLine.getFinderInputLineId() == 
>> finderInputLineId) {
>>
>>                         // find the correct criterion
>>                         for (TapestryClientCriterion criterion : 
>> finderInputLine
>>                                 .getTapestryClientCriteria()) {
>>
>>                             if (criterion.getId() == criterionId) {
>>
>>                                 clientCriterion = criterion;
>>                                 break;
>>                             }
>>                         } // inner for
>>
>>                         break;
>>                     }
>>                 } // outer for
>>             } catch (Exception e) {
>>
>>                 LOG.info(e.getMessage(), e);
>>             }
>>
>>             return clientCriterion;
>>         }
>>     }
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
>> For additional commands, e-mail: users-help@tapestry.apache.org
>>
>>
>
>


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


Re: AjaxFormLoop with nested Ajax select onValueChange event

Posted by Luis Salas <lu...@mayasoft.com.co>.
Hi Erich, I'm doing the same you have done, I'm creating a Filter 
component that will have as many input rows as users needs. Each row use 
a filterCriteria object in which I will store the users input. I need to 
do something like you did but I'm having some troubles defining the 
client ids to use with the encoder. I had created a FilterRow component 
which contains all the inputs needed.
Can you let me see how you find the input line id?

Tnx for your help.

> Hi Luis,
>
> as an alternative I want to show you my solution given in the below listed
> encoder class.
> Each search criterion in my solution is represented by a type called
> "TapestryClientCriterion". My generic search component renders any number
> of "finder input lines" each having a list of possible search criteria
> which can be selected in a drop down.
> My solution is based on the simple approach just to add a piece of
> information identifying the input line a criterion belongs to in the client
> id of each criterion. So a criterions client id consists of its own id and
> a scond identifying the input line concatenated together with a certain
> delimiter token. This all is done via an encoder (see below).
>
> /**
> 	 * This encoder has the task to provide each client side element of the
> 	 * component with id "<strong>criterionSelector</strong>" with a value
> 	 * identifying this element by the id of the finder input line it is
> 	 * rendered in and its own id. Both ids are concatenated using the "~"
> token
> 	 * as delimiter. The server side representation will be restored by
> looking
> 	 * up for the correct "<strong>{@linkplain TapestryClientCriterion}
> 	 * </strong>" in the correct "<strong>{@linkplain
> FinderInputLine}</strong>"
> 	 * using the information coded in the above mentioned concatenated string.
> 	 * The only sense of this encoder is to make each rendered finder
> criterion
> 	 * unique by the above id, because criteria are rendered multiple times in
> 	 * the loop iterations.
> 	 *
> 	 */
> 	private class ClientCriterionEncoder implements
> 			ValueEncoder<TapestryClientCriterion> {
>
> 		/**
> 		 * @see org.apache.tapestry5.ValueEncoder#toClient(java.lang.Object)
> 		 * @param value
> 		 * @return The id of the looped finder input line.
> 		 */
> 		@Override
> 		public String toClient(TapestryClientCriterion value) {
>
> 			String finderInputLineId = String.valueOf(value
> 					.getFinderInputLineId());
> 			String criterionId = String.valueOf(value.getId());
>
> 			return finderInputLineId + "~" + criterionId;
> 		}
>
> 		/**
> 		 * @see org.apache.tapestry5.ValueEncoder#toValue(java.lang.String)
> 		 * @param clientValue
> 		 * @return The finder input line for the given client id.
> 		 */
> 		@Override
> 		public TapestryClientCriterion toValue(String clientValue) {
>
> 			TapestryClientCriterion clientCriterion = null;
>
> 			try {
>
> 				String[] idParts = clientValue.split("~");
> 				String finderInputLineIdStr = idParts[0];
> 				String criterionIdStr = idParts[1];
> 				int finderInputLineId = Integer.parseInt(finderInputLineIdStr);
> 				long criterionId = Long.parseLong(criterionIdStr);
>
> 				// find the correct line
> 				for (FinderInputLine finderInputLine : finderCallback
> 						.getFinderInputLinesToRender()) {
>
> 					if (finderInputLine.getFinderInputLineId() == finderInputLineId) {
>
> 						// find the correct criterion
> 						for (TapestryClientCriterion criterion : finderInputLine
> 								.getTapestryClientCriteria()) {
>
> 							if (criterion.getId() == criterionId) {
>
> 								clientCriterion = criterion;
> 								break;
> 							}
> 						} // inner for
>
> 						break;
> 					}
> 				} // outer for
> 			} catch (Exception e) {
>
> 				LOG.info(e.getMessage(), e);
> 			}
>
> 			return clientCriterion;
> 		}
> 	}
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>


Re: AjaxFormLoop with nested Ajax select onValueChange event

Posted by Erich Gormann <e....@gormann.de>.
Hi Luis,

as an alternative I want to show you my solution given in the below listed
encoder class.
Each search criterion in my solution is represented by a type called
"TapestryClientCriterion". My generic search component renders any number
of "finder input lines" each having a list of possible search criteria
which can be selected in a drop down. 
My solution is based on the simple approach just to add a piece of
information identifying the input line a criterion belongs to in the client
id of each criterion. So a criterions client id consists of its own id and
a scond identifying the input line concatenated together with a certain
delimiter token. This all is done via an encoder (see below). 

/**
	 * This encoder has the task to provide each client side element of the
	 * component with id "<strong>criterionSelector</strong>" with a value
	 * identifying this element by the id of the finder input line it is
	 * rendered in and its own id. Both ids are concatenated using the "~"
token
	 * as delimiter. The server side representation will be restored by
looking
	 * up for the correct "<strong>{@linkplain TapestryClientCriterion}
	 * </strong>" in the correct "<strong>{@linkplain
FinderInputLine}</strong>"
	 * using the information coded in the above mentioned concatenated string.
	 * The only sense of this encoder is to make each rendered finder
criterion
	 * unique by the above id, because criteria are rendered multiple times in
	 * the loop iterations.
	 * 
	 */
	private class ClientCriterionEncoder implements
			ValueEncoder<TapestryClientCriterion> {

		/**
		 * @see org.apache.tapestry5.ValueEncoder#toClient(java.lang.Object)
		 * @param value
		 * @return The id of the looped finder input line.
		 */
		@Override
		public String toClient(TapestryClientCriterion value) {

			String finderInputLineId = String.valueOf(value
					.getFinderInputLineId());
			String criterionId = String.valueOf(value.getId());

			return finderInputLineId + "~" + criterionId;
		}

		/**
		 * @see org.apache.tapestry5.ValueEncoder#toValue(java.lang.String)
		 * @param clientValue
		 * @return The finder input line for the given client id.
		 */
		@Override
		public TapestryClientCriterion toValue(String clientValue) {

			TapestryClientCriterion clientCriterion = null;

			try {

				String[] idParts = clientValue.split("~");
				String finderInputLineIdStr = idParts[0];
				String criterionIdStr = idParts[1];
				int finderInputLineId = Integer.parseInt(finderInputLineIdStr);
				long criterionId = Long.parseLong(criterionIdStr);

				// find the correct line
				for (FinderInputLine finderInputLine : finderCallback
						.getFinderInputLinesToRender()) {

					if (finderInputLine.getFinderInputLineId() == finderInputLineId) {

						// find the correct criterion
						for (TapestryClientCriterion criterion : finderInputLine
								.getTapestryClientCriteria()) {

							if (criterion.getId() == criterionId) {

								clientCriterion = criterion;
								break;
							}
						} // inner for

						break;
					}
				} // outer for
			} catch (Exception e) {

				LOG.info(e.getMessage(), e);
			}

			return clientCriterion;
		}
	}


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