You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Jakob Praher <jp...@yahoo.de> on 2002/12/20 15:38:03 UTC

[Proposal] XForm with linking and model item properties WAS:Re: [Proposal] XMLForm: Data Provider

hi konstantin,
hi all,

first, thanks for your pointers. 
I looked at the various "advanced" xforms constructs and have come to
following solution for realising it in "standard" xforms:

I will first introduce the solution and then put some questions, which
should be settled before implementation starts ...

the solution I found:
============================================================

<!--
  somehow, we have to get a handle to the JXPath model, which
  is not "really" present in the xml form definition

  <instance id="xf:builtin-instance" />
  -->

<!--
	the instance( ) method is used to get the first 
	child of the instance element.
	so instance( 'x' ) means
		<instance id="my-instance" >
			<x>
			</x>
		</instance>
	
	the instance/x == instance('my-instance')
  -->
<xf:model name="data">

  <instance id="countries" src="cocoon:/data/states.xml" />

  <instance id="calc-data" >
	<data>
		<states /> <!-- this will be calculated -->
	</data>
  </instance>

  <bind nodeset="instance('calc-data')/states" 
	calculate="instance('countries')/country[@id=instance('xf:builtin-instance')/country]/states"
	/>

</xf:model>


<xf:form id="my-form">
	<!-- instance('xf:built-in' ) is the default instance? -->
	<xf:selectOne ref="/country" >
		<xf:caption>select a country ...</xf:caption>
		<!-- bind the elments using the itemset element -->
		<xf:itemset model="data" nodeset="instance('countries')/country" >
			<xf:caption ref="name" /> <!-- the name of the country -->
			<xf:value   ref="@id"  /> <!-- the id of the country -->
		</xf:itemset>
	<xf:selectOne>

	<xf:selectOne>
		<xf:caption>select a state ... </xf:state>
		<xf:itemset model="data" nodeset="instance('calc-data')/states" >
			<xf:caption ref="name" /> <!-- the name of the state -->
			<xf:value   ref="@id"  /> <!-- the id of the state -->
		</xf:itemset>
	</xf:selectOne>
</xf:form>



+======================================================================+
| questions/problems and orthogonalities:                              |
+======================================================================+


* how to refer to the model which is kept in the Form.getFormModel( )
  and is accessed via JXPath?
----------------------------------------------------------------------------
I propose here a kind of well-known identifier. In my example, I have
used 'xf:builtin-instance' as the name of the instance that resides in
the Form object, and is accessed via JXPath.

We could also use a kind of form( ) method or something like that. but
that is not standard conform.


* there is a instance( ) method to access different instances, but there
is
  no method to change the model via XPath.
-----------------------------------------------------------------------------
so we have to suppose that the well known instance 'xf:builtin-instance'
is a member of very model. Otherwise we can't write the binding, as
there is no xpath expression for chaging the model. [ or does the
instance( 'id' ) method work accross models ? ]


* first version will be as simple as possible:
------------------------------------------------------------------------------
the tricky part of the implementation is part of translating the
calculate property to DHTML Javascript Form.

surely it would be interesting to get only the "required" data from the
server. Such a mechanic could be implemented by using data request line,
with which the client can request the data on an as needed basis - this
could probably be implemented using a generic Action Component that,
looks up the data description from the form defnition and serves the
data to the client. 

a very "cheap" idea would be to give the client all the data and let him
choose the appropriate data.
the logic can be deduced from the calculate model properties like :

<bind nodeset="instance('calc-data')/states" 
	calculate="instance('countries')/country[@id=instance('xf:built-in')/country]/states"
	/>

javascript:

<script>
  /* ------- global data ----------------------- */
  instances = { };
  
  /* ------- set up instances ------------------ */
  /* static data ... */
  instances[ 'countries' ] = [
	{ _att_id: 'at', name: 'Austria', 
		states : [
			{ _add_id: 'ua', name: 'UpperAustria' },
			{ _add_id: 'la', name: 'LowerAustria' },
			/* ... */
		]
	}, /* next one ... */ 
	];

  

  /* calculated data */
  instances[ 'calc-data' ] = { states: null };
  
  
  function recalculate_data( ctx, src_selector, dest_selector, data ) {

     src_selector = dest_selector( data );
  }

  /* ------- a recalculation global event handler */
  function xform_recalculate( ) {
      var value = this.value;
      if ( this.name == 'country' ) {
         /* primitive that sould get generated somehow */

	 src_selector = function( ) {
	 	return instances['calc-data'].states;
	 }
	 dest_selector = function( value ) {
		for ( i in instances[ 'countries' ] )
		{
			if ( instance[ 'countries' ][ i ]._att_id = value )
				return instance['countries'][i].states;
		}
	 }

	 recalculate_data( {}, src_selector, dest_selector, data );
      }
  }   
  

  /* register all handlers for recalculation */
  document.forms[ 'my-form' ].country.onChange = xform_recalculate;
</script>


for the sake of simplicity one could write a huge recalculate function
and trigger it based on the dependencies in the calculate xpath.

the transformer also has to track which form elements depend on
calcluated data.
these form elements must be recalculated if the data they depend on is
recalculated too.

for instance:
for every instance data element refered to by a "ref", make function for
refreshing the view

for every bind nodeset with a calculate property make a recalculation
function.

in the recalculate function call those refresh functions that refer to
the recalculated instance data.

 

the xpath calculate expression to javascript converter could get quite
tricky.
I will experiment with them a bit.

any ideas on this are appreciated.


thanks

-- Jakob





Am Don, 2002-12-19 um 11.04 schrieb Konstantin Piroumian:
> From: "Konstantin Piroumian" <kp...@apache.org>
> > From: "Jakob Praher" <jp...@yahoo.de>
> >
> >
> > Also see how the input controls are bound to the instance data using
> binding
> > expressions:
> >
> http://www.w3.org/TR/2002/CR-xforms-20021112/slice3.html#structure-bind-elem
> > ent
> 
> Minor addition to this point. Usually, an XForms form contain a defaul
> 'instance' data which is referenced by simple expressions like
> '/customer/name', but you are allowed to use multiple 'instance' data
> objects and you can reference particular 'instance' using instance()
> function, e.g.:
> 
> The instance:<xforms:instance xmlns="" id="orderform">
>   <orderForm>
>     <shipTo>
>       <firstName>John</firstName>
>     </shipTo>
>   </orderForm>
> </xforms:instance>
> and the reference:ref="instance('orderform')/shipTo/firstName"
> The default instance in case of XMLForms is the underlying Form object, so
> this will require support for multiple instances.As for the function in
> referencing expression: it should not be much difficult as XMLForms uses
> JXPath to retrieve values and it's quite easy to add extension functions to
> it.
> 
> Konstantin
> 
> <snip/>
> 
> >
> > Regards,
> >   Konstantin
> >
> > >
> > > thanks in advance
> > >
> > > -- Jakob
> > >
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: cocoon-dev-unsubscribe@xml.apache.org
> For additional commands, email: cocoon-dev-help@xml.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: cocoon-dev-unsubscribe@xml.apache.org
For additional commands, email: cocoon-dev-help@xml.apache.org