my situation is the following:
I have a nodeset, through which I iterate and populate a table with some of the data
One of the fields, I do want to sum up
The problem:
Unfortunately I cannot use the sum method for the calculation as the nodeset is custom function that accesses data from other forms. And that seems to mess up things.
My idea of a solution:
I thought, I could create an instance and in each iteration add the value to it. Then I simply could access that data and do whatever calculation required. But I cannot get the xforms:insert to work.
A simplified version looks like this:
<xforms:repeat nodeset="(xxforms:si-source-forms('other_form'))">
<!-- table here -->
<xforms:insert
nodeset="instance('fr-form-instance')//positionen/position"
origin="instance('neue-position')"/>
</xforms:repeat>
The 'neue-position' instance contains bindings to the values in the source form:
<xforms:bind id="neue-position-binds" nodeset="instance('neue-position')">
<xforms:bind id="neue-position-bind" nodeset="position">
<xforms:bind id="neue-position-summe-bind" nodeset="summe" name="summe" type="xforms:string" required="true" xxforms:default="xxforms:si-source-forms('other_form')//gesamtbetrag_ausgabe" />
</xforms:bind>
</xforms:bind>
It does not work as expected though, so obviously something is wrong. I'd appreciate any hints.
About your first code snippet:
Your <xforms:insert> won't have any effet. You're in the view, and an action only runs if it is attached to an event listener. Without an ev:listener on the <xforms:insert> (or on an action around that insert), it just won't run.
About doing a sum over nodes not in an instance:
Assuming there is just one "sum" over the data returns by your custom function, you could write code along those lines:
Store the sequence of nodes returned by the function in an variable <xf:var name="others" ref="xxforms:si-source-forms('other_form')"/>
Use that variable in the repeat: <xf:repeat ref="$others"> (BTW, now XForms is standardizing the use of ref everywhere, in place of nodeset).
Do your calculation: <xf:var name="my-sum" ref="sum($others/path/to/values)"/>.
Finally, I imagine that you want to do something with $my-sum, maybe show it with an <xf:output>.
Related
We are using XSLTForms and XSLT to display a page.
I have an instance on a page whose value is set as a document.
<xf:instance id="myDetails">
<xsl:copy-of select="$detailDocument" />
</xf:instance>
It works fine and the instance value is set correctly. However, later I need to update the value of this instance with another document. I tried something like follows but didn't work:
<xf:setvalue ref="instance('myDetails')"><xsl:copy-of select="$updatedDetailDocument" /></xf:setvalue>
This just makes the instance empty even though I know updatedDetailDocument is not empty. Does xf:setvalue even support setting instances ? Or is there any other way of doing the same ?
<xf:setvalue> is used to set text within an XML attribute or XML element. In order to set a tree or subtree of XML, you would need the <xf:insert> action instead.
You don't say how you are getting $updatedDetailDocument, but since this is dynamic you probably need to retrieve that updated document using <xf:submission>, in which case you won't need <xf:insert> because <xf:submission> can directly update your instance with replace="instance".
I have an xforms instance that I have a number of binds set up for so I can warn a user about input errors.
When he is done he needs to be able to submit the data from the instance. I would like to toggle 'active' on the button depending on whether or not the instance is valid.
What's the best way to 'attack' this problem? I'm currently using a group around the button that basically repeats what the model bindings already said which feels redundant and is error prone because of out of sync logic.
Also: this instance has 3 bindings, but I have others with 30-40 bindings.
Current code:
<xforms:group ref=".[instance('new-terminology-association')[matches(#code,'^\S+$')][matches(#codeSystem,'^[0-2](\.(0|[1-9][0-9]*))*$')][string-length(#displayName)>0]]">
<fr:button>
<xforms:label ref="$resources/create-association"/>
<xforms:action ev:event="DOMActivate">
...
</xforms:action>
</fr:button>
</xforms:group>
You could use the xxf:valid() function, pointing to the nodes you want to be valid. You can also point that function to a "parent" node, and ask it to check everything "under" that node is valid.
I think that function does what you're looking for, but because field values are only sent when users stab out of the field, this can create a somewhat unexpected user experience. For instance, imagine that the last field of your form, showing just before your button, is required. The user focuses on that field, and types a value. At this point the button is still disabled, since the value hasn't been sent to the server yet. Now the user hits tab, the value is sent to the server, the button would become enabled when the Ajax responses received, but since the button wasn't enabled at the time tab was pressed, the focus goes on something other than the button, which is somewhat unexpected. So, this is something to keep in mind.
There is absolutely no way in Orbeon 4.7 to make the button/trigger respond directly to xxf:valid. This looks like a bug to me. Workaround code: add observer for xxforms-valid and xxforms-invalid that set true|false in a new instance. Add readonly binding based on ".='false'" for that instance and use ref="instance" on the trigger. On a busy form with lots of buttons that is a bit of a waste, but it'll have to make due. Thanks for you help, appreciated!
<xf:instance id="button-control">
<button btn-term-add="false"/>
</xf:instance>
<xf:action ev:event="xxforms-invalid" ev:observer="new-terminology-association">
<xf:setvalue ref="instance('button-control')/#btn-term-add" >false</xf:setvalue>
</xf:action>
<xf:action ev:event="xxforms-valid" ev:observer="new-terminology-association">
<xf:setvalue ref="instance('button-control')/#btn-term-add">true</xf:setvalue>
</xf:action>
<xf:bind nodeset="instance('button-control')">
<xf:bind ref="#btn-term-add" readonly=".='false'"/>
</xf:bind>
....
<xf:trigger ref="instance('button-control')/#btn-term-add">
....
</xf:trigger>
I create a Map in my Service, which is called from my Controller. This map I pass into a GSP. I need to store the id into a hidden var. But the id comes in as myId =
[[20]]
and to generate unique names and id's i need to concatenate this with another string. Thus, I need just the number, 20. Below is what the service returns into groupRef
[[{myId=20, groups=[{groupId=33, gNames=[{name=Prime, show=true}]}]}]]
<g:set var="myId" value="${groupRef.myId}" />
which yields [[20]].
How do I get to just the number?
By the looks of it, you have a list, inside a list, inside a list - as many levels as there are [] bracket pairs. Try this:
<g:set var="myIdInside" value="myId[0][0]" />
And, check your Service, to see if you can modify what it's returning, to negate having to do what I just showed you above.
In two other questions (here and here) BalusC makes a straight up declaration:
Getters are solely there to access bean properties, not to do some business logic. There you have the bean constructor, initialization blocks or event methods for. All are executed only once during bean's life and that's exactly what you want.
Well gee -- this just invalidated a gazillion lines of code I have already written. Ok, then, what is the correct way of implementing a backing bean that fills a data table? I understand his point and the concept, but not the practice. My question is twofold:
Why is the way I am doing it wrong?
How do I fix it?
I use PrimeFaces p:dataTable a lot, and it's value attribute resolves to a collection. For reasons I don't go into here, I do not use PrimeFaces' lazy table loading feature. Instead I implement my own filter/sort controls, but they trigger AJAX events, which then results in the table being filled with records fetched from the data base.
The table is marked up like this:
<p:panel id="mqTable">
<h:outputText value="Sort/Filter: #{maintCategory.tableQueryParameters}" />
<p:dataTable
id="mqDataTable"
rows="#{maintCategory.pageSize}"
value="#{maintCategory.dataModel}"
selection="#{maintCategory.selected}"
var="cat"
selectionMode="single"
emptyMessage="No Categories Found">
Now the INCREDIBLY BAD UN-JSFish (or so I just found out) getter for dataModel goes like this:
public ATMDataModel getDataModel() {
TableQueryParameters p = getTableQueryParameters();
if (p.isChangePending()) clearDataModel();
p.setChangePending(false);
if (dataModel != null) return dataModel;
List<ET> list = getDAO().runQuery(p);
if (p.isNeedResultSize()) p.setResultSize(getDAO().runQueryCount(p));
dataModel = new ATMDataModel(list);
return dataModel;
}
A few explanations.
This is from an abstract super-class where ET is the "Entity Type." All my CRUDs use this same routine.
The class ATMDataModel is a wrapper for the list which implements SelectableListModel. The row selection logic in PrimeFaces requires this. (It is a pain that appeared in PF 3 but it makes row selection work more reliably.)
The class TableQueryParameters is something I wrote to encapsulate the current state of the table on the user's screen. It includes what sort parameters, what filter parameters, what page we are on, etc. Because this needs to be preserved, the backing bean is ViewAccesScoped (via MyFaces CODI) and the TableQueryParameters is a property within it.
The TableQueryParameters are updated in response via AJAX events, which also update the form causing getDataModel to be called. The method isChangePending goes true when anything changes. So the getDataModel method uses this to generate only one fetch from the DAO between changes no matter how many times it is called.
BUT if the TableQueryParameters do change, I have to call runQuery with those parameters to fetch the new set of records the user wants to see. If I don't call it in getDataModel where do I call it?
Please advise.
You're basically lazily loading the data in the getter. You're not hitting the DB on every getter call within the same request (or view) scope. This is affordable. I don't use CODI, but I'd imagine that the getTableQueryParameters() call is also particularly cheap and nothing to worry about.
As to the concrete question, you'd normally do the DB/business job in an action(listener) method which is attached to the UICommand component and/or the ajax event tag.
For example (works also as <p:commandButton action> though)
<p:ajax listener="#{bean.deleteSelectedRow}" />
...
<p:ajax listener="#{bean.saveRowDetail}" />
with
public void deleteSelectedRow() {
someService.delete(selectedRow);
dataModel = loadDataModel();
}
public void saveRowDetail() {
someService.save(selectedRow);
dataModel = loadDataModel();
}
Depending on the meaning of p.isChangePending(), I think you could also get rid of it this way, it look like that you were setting it in the action(listener) methods.
I have a class on the value stack that contains a list of objects, each object is another list of objects and finally there is the object I want to access. For Example:
FruitGroupsList-->FruitGroup-->Fruit
Let's say FruitGroupsList contains 2 FruitGroup Lists:
EdibleFruits
NonEdibleFruits
The EdibleFruits is a FruitGroup (list) that contains a bunch of Fruit Objects:
Apple
Pear
Plum
...
Each Fruit has a Name property.
I understand that I can Iterate through the FruitGroupsList like so:
<s:iterator value="FruitGroupsList" var="fgl">
<s:property value="%{#fgl.name}" />
</s:iterator>
How do I loop through each FruitGroup and get a property (such as FruitName)? I've tried various types of embedding other iterator tags but thus far I can't seem to solve this...
Thanks!
I'll assume you've only put one type in each list, otherwise you should really use a map.
So your veiw has access to your actions:
List<List<Fruit>> fruitGroupsList;
In which case you'd say:
<s:iterator value="fruitGroupsList">
<s:iterator>
<s:property value="whatEverPropertyAFruitHas"/> <!-- If this was a simple type such as String, you could just write <s:property/>
</s:iterator>
</s:iterator>
A list of lists requires two iterators. If things get more confusing then putting a getter in the action to extract some deeply nested items might be reasonable.
I have fixed myself. there was issue in Setter and getter of action class