Ben Pope wrote:

Hi,

First of, sorry for the post here, but I've asked a few times on users and
not had this solved, so I'm gonna cross my fingers and post here:

This is something I've been struggling with, on and off, for some time now.

Assume I have some data as follows:

<project>
  <people>
     <person id="0">
        <name>Me</name>
     </person>
     <person id="1">
        <name>You</name>
     </person>
     <person id="2">
        <name>Him</name>
     </person>
  </people>
  <rooms>
     <room id="0">
        <name>Lounge</name>
        <person idref="0"/>
        <person idref="1"/>
     </room>
     <room id="1">
        <name>Kitchen</name>
        <person idref="2"/>
     </room>
  </rooms>
</project>

That describes a list of people which are in a particular room, so Me and
You are in the Lounge and Him is in the Kitchen.

I want to have a form that displays, for a given room, a list of the people
in it.

A repeater is obviously the first choice, but there are a few
counter-intuitive thingsd going on:

I need to be able to modify the name of the person.  Simply running the
repeater over the rooms is not enough.

Adding a row needs to add an rooms/room/person with an idref - I'll then use
client side javascript and XMLHTTP to allow the user to select a person (by
id) to fit in the space, as all the people are predefined.  I do not want to
have the repeater add /people/persons.

I've toyed with a few ideas:

id is passed in as a parameter, and this code is actually in a stylesheet -
but ignore that for now.

<fb:repeater id="people" parent-path="/project/rooms/[EMAIL PROTECTED]"
row-path="/project/people/[EMAIL PROTECTED]/project/rooms/[EMAIL 
PROTECTED]/person/@
idref]">

This "solution" has the result of being perfect for load.  However, when I
save it, it breaks, because I can't have an xpath predicate.  So what do I
set the row-path-insert to?

If I set row-path-insert="/project/people/person" and bind the id (which is
fb:identity) in both directions, /project/people/ ends up correct, but
/project/rooms/room/ doesn't get updated.

I've tried
     <fb:on-insert-row>
        <fb:context path="/project/rooms/[EMAIL PROTECTED]'0']">
           <fb:insert-node>   <person idref="5"/>
     </fb:insert-node>

But then I get a new node in both /rooms/[EMAIL PROTECTED]'0']/ which is 
correct,
and another node created in /project/people/ which is the usual binding for
person and is a copy of the existing one.  This doesn't seem correct to me.

Hmm, I've had a little play with fb:javascript but I don't know what I'm
doing... Ideally I would remove all the /rooms/[EMAIL PROTECTED]'x']/person 
fields
and repopulate with the list of ids in the repeater.  I can't seem to work
out the correct APIs, it always says that such and such method doesn't exist
- can anybody point me in the right direction?

I've toyed with the idea of having two repeaters, and updating one from the
other but it sounds like a recipe for disaster.

Another idea was to have a play around with it in flow, but I suspect I'd
end up with exactly the same problems I have using fb:javascript, with the
disadvantage of distributing the binding code.

Any help is much appreciated, I'm confused by the number of options and
multitude of interfaces.

I can't be the only person working with cross-referenced data! I'm either
missing something or the repeater just doesn't understand this construct - I
wonder if Sylvain has any ideas on this.



Hmm... I hope I'm not the only one to do fancy CForms stuff :-/

Your room repeater links to existing people through their ID but should display their name. This is typically a selection-list with IDs as labels and names as values.

About the ability to add new names at any level, this looks like a combo-box (editable dropdown). We've hacked such a thing for one of our projects, and basically the idea is to have a single widget be rendered as two inputs.

Say you have
<fd:field id="personref">
 <fd:selection-list src="cocoon:/person-selection-list"/>
</fd:field>

The editable combobox renders this as :
- a dropdown list of name "personref" with the contents of the selection-list
- an input of name "personref.label".


When the user chooses in the dropdown, the selected value is copied to personref.label.

When the user types in the personref.label input, a new option is added to the dropdown, having "new" as a value, and the typed text as label.

On form submit, the flowscript checks if "personref" equals "new" and if true creates a new person with the name in the "personref.label" request parameter and replaces the "new" value with the newly created id.

Binding can then go on as usual.

This is a bit hacky, but it works :-)

Hope this helps,
Sylvain

--
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }



Reply via email to