during the migration from RichFaces 3 to 4, we are facing an unexpected behaviour of rich:tree element. We registered a selectionChangeListener which is supposed to include a facelet with h:inputText fields next to the tree depending on the new selection. The facelet is supposed to show detailed information on the selected node.
This works correctly when the first selection is made. However, when we select another node of the same type, the same facelet is included (which is correct in this case as the node type is the same), but the values of the previous node are displayed in the facelet, even though the object holding the value of the component is instantiated correctly.
Inspecting the log files revealed that the TreeSelectionChangeEvent is processed during the Apply Request Phase (2). During that phase, the object holding the textfield's value is updated correctly, but is changed back to the old value during Update Model Phase (4).
General question on this issue is: Is it correct that this event is processed during Apply Request Phase even though the immediate attribute of the tree is set to false? (I would have expected the event to be processed during Invoke Application Phase (5)) And, if this is correct behaviour, how could we circumvent the problem that the old value is restored?
Thanks for your suggestions in advance.
as much as I understood, during the Apply Request Phase, the listener-event is executed and you update fields which are also represented as h:inputFields in the currently rendered view?
During Update Model Phase, the data out of the original h:inputText overwrites the already made changes?
Without being able to test it out locally: With switchType="ajax" the rich:tree-component gives two attributes
execute and
render.
You want the facelet-part to re-render, but not the input values to be executed (because that's what the listener already did).
Assuming you use rich:tree in ajax switch-type, have you tried to set execute="#this" and render="<theFaceletComponent>"?
If the component id wasn't found, use :#{rich:clientId('<theFaceletComponent>')} for an absolute identifier.
Hope, that helps ...
Related
It is written in docs, that
The <Field/> will rerender any time the field state it is subscribed to changes.
So, if I'd have several Fields, all of them will be re-rendered, while changing only one of them.
Are there any ways to prevent re-renders of other Fields, that are not changing at the moment?
Yes, that's because your entire form is rerendering. Your question is exactly the reason that Final Form was designed from the ground up to allow fine grained render control.
Here's a video of me explaining it last month.
Check out this example of how to do it.
Another workaround is to use React.memo (react version >= 16.6.0)
Make each input field a separate component an wrap it in memo.
export default React.memo(MyInputComponent);
If you are passing values down to MyInputComponent, pass only the needed prop value not the whole form data object.
<MyInputComponent value={formData.myValue} />
This way the MyInputComponent will re render only if formData.myValue has changed.
My program flow requires that I first set the value of a select option in the Viewmodel and then I load the available options into the Viewmodel. This causes problems, typically the first available option will be seen in the selection list after this, while the selected option value stays at the specified value.
I was hoping that setting the new "valueAllowUnset" would help, but instead my page becomes unresponsive when using it.
Therefore I currently set the original value again after loading the options. Strangely, this only works when I set the value, set a different value and then set the value again, e.g.
self.data()[field](orgValue);
self.data()[field]({});
self.data()[field](orgValue);
(I store values for multiple selection lists in the self.data observable and access them with the property index "field".)
I tried to strip this down to a simple JSFiddle (http://jsfiddle.net/timvdh/HN6DE/), but the behavior does not show there, although the example pretty much resembles my actual application. However, I am using about 30 select lists there.
So I was hoping, that someone can make an educated guess about what goes wrong in my application, I am hoping that the fact that I have to set the original value three times maybe gives a clue.
EDIT: This fiddle demonstrates, that setting the selected option before and after filling the options list does work with "valueAllowUnset": http://jsfiddle.net/timvdh/HT5Tp/
I am using JQuery Mobile with knockout.js and that caused the problem (sorry I did not even think about JQM being the problem in the first place). I am now setting the option before filling the list and after filling the list I call
$("#selectmenuID").selectmenu("refresh");
to display the option.
The hanging browser was not caused by knockout, there are additional subscriptions to the selectmenus in my app. "valueAllowUnset" changed the behavior of the selectmenus and triggered loops caused by problems in my code.
I have a view data source that uses a view key to access documents and show them in a repeat with var "posts". within the repeat I have a document data source with var "post" that gets's the the unid of the documents using posts.getUniversalID().
further down the repeat I have another document data source "newcomment" that is a response and take the parent id as: post.getDocument().getUniversalID()
below the newcomment data source I have an editbox and a submit button which saves the comment as a response to the "post" using newcomment.save()
Here is my problem
two people access the same xpage. personA enters the page and starts writing a comment to a post. in the same time personB creates a new post and submit it before personA submits the comment. What happens now is that the comments gets binded to the latest post and not to the post personA responded to.
I tried anothoher thing also, let's say there is 10 posts in that database. personA and personB access the xpages. personA start writing a comment to post number 8. at the same time personB creates two new posts in the database. when personA now submits the comment it seem to get bind to the same index which is now two posts up. but still index 8. which is ofcourse the wrong post.
If I change the repeat to "createControlsAtPageCreation" ie.e repeatControls=true the comment is attached to the correct post but then I run into another problem that the view is not updated to show the latest posts.
my repeat is wihtin a custom control that is loaded dynamically using the dynamic content control in extlib.
As information here is what I have found about the repeatControls settings
Setting the repeatControls property to true instructs the repeat control to create a new copy of its children for each iteration over the dataset.
When the Repeat control is configured with the property
repeatControls=“true” , it repeats its contents only once, at page load time
So my question here is that I do not understand what is going on. why is my comment attached to the wrong parent document? and is there a way I can prevent this and still have new posts displayed correctly
thanks for your help
Without the code it's a bit hard to imagine what exactly is going one here but this looks very similar to problem that I had with repeat control and value binding.
Long story short the problem was connecet to repeatControls property set to false. When it was like that data binding were working only for first element in collection - all data was somehow magically saved to this first object! I managed to get this working by using combination of dynamic content control rebuild and repeatControls set to true. Only then databindings were working property.
It seems like if You are repeating rendering only (and this is what repeatControls set to false do) the decoding phase of jsf lifecycle goes foobar.
Without your XSP markup, it's difficult to be absolutely definitive but it appears that you're app code is creating and persisting the datasources and components per row during page load - therefore increasing the overall size and complexity of the component tree also. You should alternatively try an approach that will lazy-load the datasource only when requested by the end-user (eg: edit / reply).
Refer to the XPages Extension Library demo application (XPagesExt.nsf) for examples that use such a dynamic approach. In particular, look at Core_InPlaceForm.xsp which demonstrates using the xe:inPlaceForm control within a xp:repeat. And also see Domino_ForumView.xsp which demonstrates using the xe:forumView and xe:forumPost controls to manage and visualize a hierarchical thread. Also consider the concurrency mode that best suits your requirements when it actually comes to saving any given post or comment (fail, createConflict, force, exception) and document locking for high contention situations. The above-mentioned controls all provide the highest level of dynamic control and datasource creation and destruction.
Please feel free to send me on a worked example database, where I can understand your exact use case - DM me or email me.
I was checking out the code for this template from the OmniFaces Showcase app, when I encountered the following condition used in a p:selectOneMenu:
disabled="#{facesContext.postback and not facesContext.renderResponse}"
From using the app, it seemed that the selectOneMenu is never disabled, so what does this code really do?
I know that facesContext.postback is true whenever the page is resultant from POST requests generated by JSF components (commandButton/commandLink, etc), but what would be the usual expected state of facesContext.renderResponse when evaluated in the View?
UPDATE: oops, just now I saw the comment: They're disabled in other phases than render response, because they otherwise complain that the model value cannot be set even though there's no form.
So, I'm guessing the condition is evaluated several times during Faces lifecycle, and the component is disabled until the last state (renderResponse) is reached, when facesContext.renderResponse evaluates to true, the whole expression evaluates to false and the component is then enabled. Is that about right?
Those <p:selectOneMenu> components are actually abused to have a nice <div><ul><li> dropdown menu with a minimum of code ;) Their values represent the current menu group and page which are by design read-only (they have no setter method). The navigation takes place by JavaScript window.location which is handled during change event. They are not part of any form and do not participate in any form submit.
The disabled attribute is theoretically not mandatory, but when a non-ajax JSF form elsewhere in the very same page is submitted synchronously, then PrimeFaces SelectOneMenuRenderer will still try to decode() it in its entirety even though it is not enclosed in any form at all. It would ultimately cause the following exception when the model value is to be updated because there's no setter for that value:
javax.el.PropertyNotWritableException: /WEB-INF/templates/showcase.xhtml #28,80 value="#{parent.children[0].viewId}": The class 'org.omnifaces.showcase.Page' does not have a writable property 'viewId'.
at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:136)
at javax.faces.component.UIInput.updateModel(UIInput.java:818)
at javax.faces.component.UIInput.processUpdates(UIInput.java:735)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1242)
at org.primefaces.component.panel.Panel.processUpdates(Panel.java:304)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1242)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1242)
at javax.faces.component.UIViewRoot.processUpdates(UIViewRoot.java:1231)
at com.sun.faces.lifecycle.UpdateModelValuesPhase.execute(UpdateModelValuesPhase.java:78)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
When the disabled attribute evaluates true during postback, then the SelectOneMenuRenderer will skip the decode() during apply request values phase and thus also skip the update of model value. However, if it evaluates true as well during render response phase, then it becomes unselectable (and thus unusable). So, it should not evaluate true during render response phase. The expression
disabled="#{facesContext.postback and not facesContext.renderResponse}"
achieves exactly that. All with all, it's basically kind of a workaround for the odd behavior of SelectOneMenuRenderer (for which I've not really investigated the underlying cause yet).
To test it yourself, pull the project, remove the disabled attribute and invoke a synchronous submit in for example the <o:onloadScript> showcase page.
This evaluates to the getter state for reading whether renderResponse() has been invoked. This method is used to instruct the JSF lifecycle to skip subsequent phases and go straight to emitting the response (e.g. in the case of a validation failure.)
First time user long time reader. I have thoroughly looked for an explanation for the problem I'm having via the mighty search engine Google, but alas I have failed to produce any significant insight.
I need to be able to ensure that a model form is not reloaded with invalid data. Since the model stored in memory on the server is edited directly with the parameters of the web form first, and THEN checked for validity, without additional code invalid model data will ALWAYS be sent back to the form. This is less than desirable to me. My question is this: how do I ensure this doesn't happen?
What I'm thinking is I need some mechanism for saving the state of the object before it's modified with the parameters sent from the web form, and then after a failed validation restore the object to it's previous, correct and unmodified state of being.
Help!
Thanks,
Les
The object isn't actually modified in the db if validation fails, even though the object is in an invalid state in the form ... the thinking behind this is that the user wants to see the errors they made so they can correct them.
If you don't want that to be the case, then just read back the object with a WhateverObject.find(x) and assign it to the variable that the form is referencing and it will 'restore' the object to its previous unmodified state.
To add to what concept47 said you can also get the value for a particular field using
object.field_was
Have a look at ActiveRecord::Dirty for details (http://ar.rubyonrails.org/classes/ActiveRecord/Dirty.html)
Using that you could retrieve the original values for just those fields that had validation errors.