Affects Version/s: 1.3.5
Fix Version/s: None
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.