Suggested new implementation of ComponentPropertyModel
------------------------------------------------------

                 Key: WICKET-2119
                 URL: https://issues.apache.org/jira/browse/WICKET-2119
             Project: Wicket
          Issue Type: Improvement
          Components: wicket
    Affects Versions: 1.3.5
            Reporter: Willis Blackburn


I would like to propose a replacement for ComponentPropertyModel.

The existing version addresses a specific situation:  How to use 
CompoundPropertyModel with a child component that requires two models?

However, I think that the existing implementation has some issues:

1.  It doesn't actually behave like the model-finding logic of Component.  
Component searches up the component hierarchy until it finds a component with a 
model that implements IComponentInheritedModel.  ComponentPropertyModel just 
uses the parent component's model.  So if, for example, a Page with a 
CompoundPropertyModel contains a model-less Form, and the Form contains 
model-less fields, then the fields will find the Page model, but any 
ComponentPropertyModels will try to access the Form model.

2.  ComponentPropertyModel can *only* use a property of the parent's model and 
not the parent's model itself.

3.  It implements IComponentAssignedModel, which is confusing for Wicket 
beginners.  Sometimes IComponentAssignedModel is unavoidable, but in this case, 
the component is only needed in order to access its parent, which is an issue 
in itself (issue 1).  In almost all cases, the parent of a Component using 
ComponentPropertyModel is already known, so why not just pass it to 
ComponentPropertyModel directly?

My proposed implementation accepts a Component and delegates operations to that 
Component's model.  It also optionally allows an expression for accessing a 
specific property of the target Component's model.  This addresses a very 
common use case:  A Component needing to use the model of some other Component 
directly.  As an example, AjaxEditableLabel creates two components that both 
use AjaxEditableLabel's model.

Having a component that directly uses the model of some other component is 
difficult with existing model implementations.  The obvious way to do it is to 
call getModel on the parent component, then use the returned model in the child 
components, either directly or in combination with PropertyModel.  There are 
two gotchas with this approach:

First, the model of the parent component may not be known in the parent 
constructor:  The parent may not have a model and may expect to get its model 
from an IComponentInheritedModel higher in the component hierarchy, however the 
parent has not yet been added to *its* parent in the constructor, and so the 
inherited model is not yet available.  Therefore, a Component that wants to 
create children that use its own model cannot create those children it in its 
constructor.  It must lazily create them in the onBeforeRender method instead.

Second, and more generally, an application can call setModel on the component 
at any time.  If the component passes its model to its children, then it also 
has to intercept setModel and reset the child models.  AjaxEditableLabel does 
this, but it only has two child components to manage.

A strategy for child components that want to use their parent's model is to 
create a PropertyModel in which the target object is the Component containing 
the actual model and the property expression starts with "modelObject."  
Basically, my proposed ComponentPropertyModel implements this functionality, 
except that the "modelObject" part of the expression is implied.  For this 
particular use case, it is clearer and a bit more efficient than new 
PropertyModel(someComponent, "modelObject.property.expression").

Using this model, AjaxEditableLabel would become much simpler.  It could create 
the child Label and TextField components once, in the constructor, passing new 
ComponentPropertyModel(this), and not have to worry about onBeforeRender or 
setModel.

Let me know what you think.

I wrote a test case for this, but I can't actually run it due to the issue with 
the component instantiation listener that Application installs;  see my other 
jIRA issue about this.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to