Why component from Xpages Extension lib doesn't support converter - xpages

My xpage is using xe:djDateTextBox (bellow):
<xe:djDateTextBox id="djDateCreatedFrom"
value="#{compositeData.archiveDocument.entryDateFrom.time}"
title="#{javascript:languageGetLabelName('_arch_from_date')}"
style="width:49%;" showReadonlyAsDisabled="true"
readOnly="#{javascript:!compositeData.editMode}">
<xe:this.converter>
<xp:convertDateTime>
<xp:this.pattern><![CDATA[${javascript:"dd.MM.yyyy"}]]></xp:this.pattern>
</xp:convertDateTime>
</xe:this.converter>
public class ArchiveDocument extends Param{
/**
*
*/
private Calendar entryDateFrom;
public ArchiveDocument() {
super();
entryDateFrom = Calendar.getInstance();}
public Calendar getEntryDateFrom() {
return entryDate;
}
public void setEntryDateFrom(Calendar entryDate) {
this.entryDate = entryDate;
}
.....
}
If I set standard date time picker instead of xe:djDateTextBox everything works fine: (bellow)
<xp:inputText id="txtDateCreatedFrom"
style="width:75.0%"
value="#{compositeData.archiveDocument.entryDateFrom.time}"
readonly="#{javascript:!compositeData.visible}"
dojoType="dijit.form.DateTextBox">
<xp:this.converter>
<xp:convertDateTime>
<xp:this.pattern><![CDATA[${javascript:"dd.MM.yyyy"}]]></xp:this.pattern>
</xp:convertDateTime>
</xp:this.converter>
<xp:dateTimeHelper></xp:dateTimeHelper>
</xp:inputText>
Settings for IE, Domino server, pattern in xpage:
My IE settings for languages: English (United STates) [en-US]
Pattern:"dd.MM.yyyy"
Domino server 9.0.1 FP2
Web User Preferences: Default regional locale: Server locale
My page doesn't show date time like 27.11.2014 as it should.
It show date time like 11/27/2014.
If I'm using standard date time picker everything works fine.
Thanks in advance!

Is your page displaying a pre-saved value or is it just defaulting to the current date? If the former, you may be misunderstanding what the converter does.
The job of the converter is to convert the server-side date/time value to a text string and vice versa. The converter code all runs server-side, so if there's not a pre-existing value, it will just pass a blank string. So the converter is not the place to look to modify the format the browser offers, Dojo will be defining the value.
The Dojo locale settings will be what is being used for the date time format being used for a default value or entered on the browser. I'm not sure if this will help explain dates and localization http://xomino.com/2014/01/14/dealing-with-dates-and-localization-in-xpages/

Related

Error setting sessionScope variable in KendoUI grid to open document

My app uses KendoUI Grids for user views, but Xpages with custom controls for form pages (at least for now).
The Xpage looks for a sessionScope variable to determine if it is a new doc (nothing in the scope Var) or and update (unid is in the var).
<xp:this.data>
<xe:objectData
saveObject="#{javascript:PCModel.save()}"
var="PCModel">
<xe:this.createObject><![CDATA[#{javascript:var pc = new com.scoular.model.PC();
var unid = sessionScope.get("key");
if (unid != null) {
pc.loadByUnid(unid);
sessionScope.put("key","");
viewScope.put("readOnly","Yes");
} else {
pc.create();
viewScope.put("readOnly","No");
}
viewScope.status = pc.status;
return pc;}]]></xe:this.createObject>
</xe:objectData>
</xp:this.data>
This worked for a completely Xpage app. I just put a value in the sessionScope key and called the Xpage.
In the Kendo UI code I am using client-side javascript and I don't see a way to set the sessionScope.
I can control the URL, so I could switch gears and use that, however the data for my app is in a different DB than my code.
Any help would be greatly appreciated.
The easiest way is indeed using the URL:
call the XPage with a parameter ?key=... and change your CSJS code line to
var unid = param.key;
In case you really need to set a sessionScope variable from client side
then add this empty computed text field
<xp:text
escape="true"
id="setSessionScope"
value="#{javascript: if (param.key) {sessionScope.key = param.key} ''}" />
to your XPage and set the sessionScope variable in CSJS code with
XSP.partialRefreshGet("#{id:setSessionScope}", {params: {'key': 'your key'}})

calculate the rendering of a custom control

In an xpage I would like to be able to decide which custom controls have to be rendered or loaded.
I have a custom control named 1, another 2, 3 etc
When a scoped variable has the value 1, custom control 1 should be displayed/rendered/loaded.
A value of 2 , custom control 2 has to be displayed. etc
I came up with following sollution :
I calculate if that custom control has to be loaded or not depending on the value of the scoped variable.
Since I have 8 of these custom controls on 1 page I was wondering ,since only 1 out of those 8 custom controls have to be rendered ,if there isn't a better way with less code to do the same job. Won't my sollution put a lot of load to my server ?
A better solution is to inject your custom control on the fly. This can be easily done with java:
package ch.hasselba.xpages;
import java.util.UUID;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import com.ibm.xsp.extlib.builder.ControlBuilder;
import com.ibm.xsp.extlib.builder.ControlBuilder.ControlImpl;
import com.ibm.xsp.component.UIIncludeComposite;
import com.ibm.xsp.context.FacesContextExImpl;
import com.ibm.xsp.util.FacesUtil;
public class XPagesUtil {
public void injectCC( final String ccName , final String componentName ){
FacesContextExImpl fc = (FacesContextExImpl) FacesContext.getCurrentInstance();
UIComponent cmp = FacesUtil.findChildComponent(fc.getViewRoot(), componentName );
UIIncludeComposite objCtrl = new UIIncludeComposite();
objCtrl.setPageName( ccName );
objCtrl.setId("new_" + UUID.randomUUID() );
ControlBuilder cBuilder = new ControlBuilder();
ControlImpl<UIIncludeComposite> objImplControl = new ControlImpl<UIIncludeComposite>(objCtrl);
ControlImpl<UIComponent> objImplParent = new ControlImpl<UIComponent>(cmp);
objImplParent.addChild(objImplControl);
cBuilder.buildControl(fc,objImplParent,false);
}
}
To use the code on your XPage, you now can do the following:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.afterPageLoad>
<![CDATA[#{javascript:
importPackage( ch.hasselba.xpages.extlib );
var nameOfCC = "/IncludeCC.xsp";
new ch.hasselba.xpages.XPagesUtil().injectCC(nameOfCC, "parent");
}]]>
</xp:this.afterPageLoad>
<xp:div id="parent" />
</xp:view>
You can now calculate the variable nameOfCC.
Sven's solution looks absolutely brilliant but also kinda scary at the same time. Though I'm definitely going to play with that.
There is a more "out of the box" possibility that might work for you. the Dynamic Content Control of the extension library. My understanding is that it's designed for exactly this. You still need to predefine your custom controls (unlike Sven's Java injection) but the dynamic content control is better performing then trying to control all the rendering manually. There's a demo in the ext. library demo app but heres a snippet I've used:
<xe:dynamicContent
id="dynamic">
<xp:this.facets>
<xp:panel
xp:key="cat">
<xc:cc_form_category></xc:cc_form_category>
</xp:panel>
<xp:panel
xp:key="subCategory">
<xc:cc_form_subCategory></xc:cc_form_subCategory>
</xp:panel>
<xp:panel
xp:key="rental">
<xc:cc_form_rentalID></xc:cc_form_rentalID>
</xp:panel>
<xp:panel
xp:key="default">default content</xp:panel>
</xp:this.facets>
</xe:dynamicContent>
That's basically the setup of the custom controls. then I've been using some Client Side JavaScript when I want to show one or make a change.
XSP.showContent("#{id:dynamic}","cat")
XSP.partialRefreshPost('#{id:mainPanel}', {})
I think if it kinda like a Switch Statement really.
Hope that helps.

Show Ext Lib Value Picker Programmatically?

I'm trying to find a way to open the Extension Library Value Picker automatically after load of my XPage. I tried putting the following in the onClientLoad event:
dojo.byId('#{id:MyValuePicker}').click();
But it appears that the value picker does not have a click() method to open the dialog. Any ideas are appreciated. Thanks.
EDIT: Changed code based on #stwissel's comment and viewid issue:
Put the folloiwng in a scriptBlock:
<xp:scriptBlock>
<xp:this.value><![CDATA[
var viewID = "#{javascript:viewScope.viewID}";
XSP.selectValue('extlib.dijit.PickerList',{
"msep":",",
"trim":true,
"listWidth":"550px",
"dlgTitle":"Select One Or More Values",
"control":"#{id:BoundControl}",
"url":"\/Database.nsf\/Test.xsp?$$viewid="+viewID+"&$$axtarget=#{id:MyValuePicker}"
})
]]>
</xp:this.value>
</xp:scriptBlock>
The viewID is set in the beforePageLoad event:
viewScope.viewID = com.ibm.xsp.application.UniqueViewIdManager.getUniqueViewId(facesContext.getViewRoot())
to get this working with bootstrap, use extlib.dijit.BootstrapPickerList3.
Or much better is 'extlib.responsive.dijit.xsp.bootstrap.PickerList'

ReadOnly field in Xpage not submitted

I have a field in my Xpage that I want to be readOnly and submitted to the database upon Save. This field gets a value from a Ajax call
Setting the property ReadOnly to true creates a <span> instead of a readonly field.
Setting the property "Show disabled control for readonly" creates a input text field with the property readonly=readonly.
<input type="text" class="xspInputFieldEditBox" readonly="readonly" name="view:_id1:_id2:_id3:_id28:callbackFieldControlSet:InstrumentShort" id="view:_id1:_id2:_id3:_id28:callbackFieldControlSet:InstrumentShort">
It will not be saved to the database.
According to my knowledge readonly fields are submitted but not disabled.
What I'm I doing wrong here?
/M
You can add the readonly attribute with the attr-property:
<xp:inputText id="inputText2" value="#{document1.ReadOnly}">
<xp:this.attrs>
<xp:attr name="readonly" value="true" />
</xp:this.attrs>
</xp:inputText>
Btw: The behaviour of the disabled and the readonly property is correct, because this is a definition on the server side. You want to edit the component with a value, that is why it must be allowed to accept values. Just disabling it on the client side has technically no effect.
I think this is a bug. You are right, the read only field should get saved. In version 8.5.1 when the property of "Show disabled control for readonly" was not present I used to set the field as readonly through JavaScript. Here's the code snippet:
<xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[function makeFieldReadOnly() {
document.getElementById("#{id:inputText2}").readOnly = true;
}
window.onload = makeFieldReadOnly;]]></xp:this.value>
</xp:scriptBlock>
In the above snippet the function makeFieldReadOnly marks the edit box inputText2 as readonly when page is loaded.

Rich Calendar Validator

I'm new to JSF and I'm sure I'm doing something stupid, but I've been trying different things for days and cant make any progress. I'm trying to do validation when a user types in a date instead of using the rich calendar but for some reason I cant seem to get the validator to fire. The page code is as follows:
<a4j:outputPanel id="responseReleaseDate" rendered="#{appealSearchManager.isVendor}">
<p><h:outputText value="#{messages.ResponseReleaseDate}"/></p>
<rich:calendar id="responseReleaseDateBegin" datePattern="MM/dd/yyyy"
enableManualInput="true"
buttonIcon="/images/calendar_icon.jpg" buttonClass="calendar"
validator="#{appealSearchManager.validateResponseReleaseDateBegin}"
value="#{appealSearchManager.responseReleaseDateBegin}">
</rich:calendar>
<rich:calendar id="responseReleaseDateEnd" datePattern="MM/dd/yyyy"
enableManualInput="true"
buttonIcon="/images/calendar_icon.jpg" buttonClass="calendar"
validator="#{appealSearchManager.validateResponseReleaseDateBegin}"
value="#{appealSearchManager.responseReleaseDateEnd}">
</rich:calendar>
</a4j:outputPanel>
The bean code I'm trying to invoke is as follows:
public void validateResponseReleaseDateBegin(FacesContext facesContext, UIComponent uiComponent, Object value) throws ValidatorException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM/dd/yyyy");
if (value != null && !value.equals("")) {
try {
simpleDateFormat.parse(value.toString());
} catch (ParseException e) {
throw new ValidatorException(new FacesMessage(
FacesMessage.SEVERITY_ERROR,
MessageFormat.format((RootUtils.getCommonBundle().getString(BundleConstants.INVALID_ITEM)), "Response Release Date"),
MessageFormat.format(RootUtils.getCommonBundle().getString(BundleConstants.INVALID_DATE_FORMAT), "Date", "MM/DD/YYYY")));
}
}
}
The wierd thing is that I can reach the validateResponseReleaseDateBegin(...) method using the code below (I know, it doesnt make sense for a text field, it was just for testing purposes). But I never hit the method when I enter input for the rich calendar.
<div class="div30">
<p><h:outputText value="#{messages.ProgramInvoiceId}"/></p>
<h:inputText id="programInvoiceId"
validator="#{appealSearchManager.validateResponseReleaseDateBegin}"
value="#{appealSearchManager.programInvoiceId}"/>
</div>
Any ideas why this validator works in one place and not another?
Thanks!
This makes no sense. The <rich:calendar> will already implicitly convert the String submitted value to Date before setting it as model value. If you enter a date in invalid format, the <rich:calendar> will already throw a ConverterException for that. Its message should already be visible in any <h:messages> or <h:message> component associated with the component.
As conversion runs before validation, your validator is never fired when conversion fails. Even when your validator was fired, the Object value argument in the validator is already of the type java.util.Date. So if your validator was fired, it would always have thrown an exception because Date#toString() does definitely not match MM/dd/yyyy.
I'm not sure why you need this validator. Perhaps you just wanted to supply a custom conversion error message? In that case, you should be using its converterMessage attribute instead.
<rich:calendar ... converterMessage="Invalid date" />
Or, if you really need to "validate" the date format by yourself, implement a custom Converter instead and register it by converter attribute or <f:converter> tag instead.

Resources