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 }
