Fredrik is on the right track -- you should set the value manually during an event -- but I would add two caveats:
- Call
setValue
instead of replaceItemValue
(e.g. document1.setValue("myComboBox", "Default Value");
). The comparative advantages might not be applicable in this specific case, but you should be in the habit of always calling setValue
instead of replaceItemValue
(and getValue
instead of getItemValue
) so that, when you've encountered a scenario where it makes a real difference, you just get that benefit for free... the rest of the time, the methods are equivalent, so you might as well just use the one that requires less typing. :)
- You'll probably need to do this in
afterPageLoad
: the data source may not be ready yet during beforePageLoad
; depending on why you're referencing the default value elsewhere in your page, beforeRenderResponse
might be too late; and afterRenderResponse
would definitely be too late...
...which leads me to why the defaultValue
attribute does not behave the way we might expect it to, especially for those of us with experience developing Notes client apps.
The XPages engine splits the processing of every HTTP request into several "phases". Depending on the type of request (initial page load, partial refresh event, etc.) and other factors, the lifecycle will consist of as many as 6 phases and as few as 2.
This tutorial page provides an excellent description of these phases, but in the context of this question, the following are specifically of interest:
Apply Request Values
When an event runs against a page that has already been loaded (e.g. a user clicks a button, or selects a value from a combobox that has an onChange
event, etc.), the HTTP request sent to the server to trigger the event includes POST data that represents the value of all editable components. This phase temporarily stores these values in the submittedValue
property of any affected components, but the data source doesn't "know" what the new values are yet.
Process Validations
This phase runs any applicable validators and, if any fail, skips straight to the last phase (which means it never runs the code of the event that was triggered).
Update Model Values
If no validations fail (or none are defined), this phase takes the submitted values and actually stores them in the corresponding data source. Until this point, the data source is completely unaware that there has been any user interaction. This is intended to avoid prematurely polluting any back end data with user input that might not even be valid. Remember, not every data source is a "document"; it might be relational data that is changed via an UPDATE
the instant setValue
is called... which is basically what this phase does: it takes the submittedValue
and calls setValue
on the corresponding data source (and then sets submittedValue
to null
). This separation allows components to simply be visual representations of the state of the back end data -- visual representations that the user interacts with; our code should always be interacting directly with the back end data via the abstraction layer of a data source.
Render Response
Once all of the other phases have run (or been skipped), this phase sends a response to the consumer. In other words, it sends HTML (or JSON, or XML, or PDF, etc.) back to the browser. But the most salient point in the context of this question is that the prior phases are always skipped on initial page load. When the user first accesses a page, they haven't had a chance to enter any data yet, so there are no request values to be applied. Since no data has been posted, there's nothing to validate. And -- most pertinent of all -- there's nothing to be pushed to the data model. So a representation of the component tree (or a subset of it, in the case of a partial refresh event) always needs to be sent to the user, but until the user interacts with that representation, the data source remains in whatever state it was when the most recent response was rendered... which is why, if you want a specific property of the data source to have a specific value before the user interacts with it, your code needs to set that property's value manually.
In summary, components are visual. Data sources are abstract. Perhaps this behavior would be more self-explanatory if the component property had simply been called defaultClientValue
instead of defaultValue
, because that's essentially what it is: a default suggestion to the user for what data to send back to the data source. But until they do, the data source has not received that value. So if, on initial page load, you need a data source property to have a value that it wouldn't already have in its default state, you should manually call setValue
to give it the desired value.
P.S. Ironically, if you'd called partialRefreshPost
instead of partialRefreshGet
, you likely would have achieved the result you were looking for, because the former sends all the form data, while the latter just asks the existing component state to be rendered again. But then you're forcing all of the form data to be sent just to update one data source property, so it's better to simply do what's described above.