动态将自定义控件中的“编辑框"绑定到托管Bean [英] Dynamically bind an Edit Box in a custom control to a managed bean
问题描述
我已经阅读了许多有关在自定义控件中动态绑定字段的出色文章和文章,但是它们都假定了文档数据源.
I've read a number of excellent posts and articles about dynamically binding fields in a custom control, but they have all assumed a document data source.
我想允许使用托管bean数据源.我尝试将属性类型设置为com.ibm.xsp.model.DataSource
或com.ibm.xsp.extlib.model.ObjectDataSource
,但都不适用于以下xml:
I want to allow the possibility of a managed bean data source. I tried setting the property type to com.ibm.xsp.model.DataSource
or com.ibm.xsp.extlib.model.ObjectDataSource
and neither of those work with the following xml:
<xp:inputText
id="input"
value="${compositeData.dsn[compositeData.fieldName]}"
>
</xp:inputText>
在使用控件的地方,我像这样传递了自定义数据:
Where the control is used I have passed in custom data like so:
<xc:input
dsn="#{issue}"
fieldName="Database"
>
</xc:input>
出于测试目的,我有一个名为issue
的托管bean,并且将我的字段称为Database
.我通常会绑定到#{issue.Database}
,但是我不知道如何动态地执行该操作.理想情况下,我也想支持文档数据源,但是如果我不能同时支持两者,那么我需要绑定到托管bean.
For my test purpose, I have a managed bean named issue
and I called my field Database
. I would normally bind to #{issue.Database}
but I can't figure out how to do that dynamically. Ideally, I would like to support document data sources as well, but if I can't do both then I need to bind to the managed bean.
问题似乎出在数组符号上.如果我将值硬编码为#{issue.Database}
,它将起作用,但是如果我将其硬编码为#{issue[Database]}
,则失败.因此,问题是是否存在点符号的替代表示形式.我今天没有时间,但是我是否想如果我只是将#{issue}传递给dsn并将其用作我的数据绑定,而不是将dsn和fieldName分开,是否行得通?如果有机会,我会尝试的.
The problem seems to be the array-notation. If I hardcode my value to #{issue.Database}
it works but if I hardcode it to #{issue[Database]}
it fails. So the question is if there is an alternative representation of dot-notation. I don't have time today, but I wonder if instead of separating dsn and fieldName if I just passed #{issue} into dsn and used that as my data binding would that work? I will try that when I get a chance.
Edit2:看来问题可能与我使用的Bean有关,我将在此处发布其代码.
As it appears the problem may be related to the bean I'm using, I'll post the code for that here.
AbstractMapModel
public abstract class AbstractMapModel implements Serializable, DataObject {
private static final long serialVersionUID = 1L;
private Map<Object, Object> values;
public Class<?> getType(final Object key) {
Class<?> result = null;
if (getValues().containsKey(key)) {
Object value = getValues().get(key);
if (value != null) {
result = value.getClass();
}
}
return result;
}
protected Map<Object, Object> getValues() {
if (values == null) {
values = new HashMap<Object, Object>();
}
return values;
}
public Object getValue(final Object key) {
return getValues().get(key);
}
public boolean isReadOnly(final Object key) {
return false;
}
public void setValue(final Object key, final Object value) {
getValues().put(key, value);
}
}
AbstractDocumentMapModel
public abstract class AbstractDocumentMapModel extends AbstractMapModel {
private static final long serialVersionUID = 1L;
private String unid;
public AbstractDocumentMapModel() {
String documentId = ExtLibUtil.readParameter(FacesContext
.getCurrentInstance(), "id");
if (StringUtil.isNotEmpty(documentId)) {
load(documentId);
}
}
protected abstract String getFormName();
public String getUnid() {
return unid;
}
public void setUnid(String unid) {
this.unid = unid;
}
public void load(final String unid) {
setUnid(unid);
Document doc = null;
try {
if (StringUtil.isNotEmpty(getUnid())) {
doc = ExtLibUtil.getCurrentDatabase().getDocumentByUNID(
getUnid());
DominoDocument wrappedDoc = DominoDocument.wrap(doc
.getParentDatabase().getFilePath(), // databaseName
doc, // Document
null, // computeWithForm
null, // concurrencyMode
false, // allowDeleteDocs
null, // saveLinksAs
null // webQuerySaveAgent
);
for (Object eachItem : doc.getItems()) {
if (eachItem instanceof Item) {
Item item = (Item) eachItem;
String itemName = item.getName();
if (!("$UpdatedBy".equalsIgnoreCase(itemName) || "$Revisions"
.equalsIgnoreCase(itemName))) {
setValue(item.getName(), wrappedDoc.getValue(item
.getName()));
}
DominoUtil.incinerate(eachItem);
}
}
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
DominoUtil.incinerate(doc);
}
}
protected boolean postSave() {
return true;
}
protected boolean querySave() {
return true;
}
public boolean save() {
boolean result = false;
if (querySave()) {
Document doc = null;
try {
if (StringUtil.isEmpty(getUnid())) {
doc = ExtLibUtil.getCurrentDatabase().createDocument();
setUnid(doc.getUniversalID());
doc.replaceItemValue("Form", getFormName());
} else {
doc = ExtLibUtil.getCurrentDatabase().getDocumentByUNID(
getUnid());
}
for (Entry<Object, Object> entry : getValues().entrySet()) {
String itemName = entry.getKey().toString();
doc.replaceItemValue(itemName, DominoUtil
.toDominoFriendly(entry.getValue()));
}
if (doc.save()) {
result = postSave();
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
DominoUtil.incinerate(doc);
}
}
return result;
}
}
IssueModel
public class IssueModel extends AbstractDocumentMapModel implements
Serializable {
private static final long serialVersionUID = 1L;
@Override
protected String getFormName() {
return "frmIssue";
}
@Override
protected boolean querySave() {
return super.querySave();
}
@Override
public boolean isReadOnly(final Object key) {
boolean result = super.isReadOnly(key);
/**
* Implement read only logic here as follows
*
* if ("jobTitle".equalsIgnoreCase((String) key)) { if
* (!ExtLibUtil.getXspContext().getUser().getRoles().contains("[HR]")) {
* result = true; } }
*/
return result;
}
}
ccFieldset
<?xml version="1.0" encoding="UTF-8"?>
<xp:view
xmlns:xp="http://www.ibm.com/xsp/core"
>
<div
class="form-group"
>
<xp:label
id="label"
for="input"
value="${compositeData.label.text}"
>
<xp:this.styleClass><![CDATA[${javascript:styleClass = "control-label col-" + compositeData.sz + "-" + compositeData.label.columns;
return styleClass;}]]></xp:this.styleClass>
</xp:label>
<xp:div>
<xp:this.styleClass><![CDATA[${javascript:styleClass = "col-" + compositeData.sz + "-" + compositeData.input.columns;
return styleClass;}]]></xp:this.styleClass>
<xp:inputText
id="input"
>
<xp:this.value><![CDATA[${javascript:"#{"+compositeData.BindTo+"}"}]]></xp:this.value>
<xp:this.styleClass><![CDATA[${javascript:styleClass = "input-" + compositeData.sz;
return styleClass;}]]></xp:this.styleClass>
</xp:inputText>
</xp:div>
</div>
</xp:view>
xpage中的工作字段
<div
class="form-group"
>
<xp:label
value="Database"
id="database_Label1"
for="database1"
styleClass="col-sm-2 control-label"
>
</xp:label>
<div
class="col-sm-6"
>
<xp:inputText
value="#{issue.Database}"
id="database1"
styleClass="input-sm"
>
</xp:inputText>
</div>
</div>
在xpage中无法使用ccFieldset
<xc:fieldset sz="md">
<xc:this.input>
<xc:input
columns="10"
bindTo="issue.Database"
>
</xc:input>
</xc:this.input>
<xc:this.label>
<xc:label
columns="2"
text="test"
>
</xc:label>
</xc:this.label>
</xc:fieldset>
推荐答案
技巧是将String作为参数传递给您,该参数将是您要使用的EL.假设您有一个参数bindTo作为String,其值是myBean.Color
The trick is to hand over a String as parameter that would be the EL you want to use. Let's say you have a parameter bindTo as String with the value myBean.Color
<xp:this.value><![CDATA[${javascript:"#{"+compositeData.BindTo+"}"}]]></xp:this.value>
$将首先求值,然后用实际值替换CompositeData.方法的优点:适用于任何EL. Document Bean等,因此您的自定义控件无需对其容器进行任何假设.
The $ will evaluate first and replace the compositeData with the actual value. The beauty of the approach: works for any EL. Document Bean etc., so your custom control doesn't need to make any assumptions on its container.
因此,您可以使用各种绑定来调用组件:
So you could call your component with all sorts of bindings:
<xc:myComponent BindTo="document1.subject"></xc:myComponent>
<xc:myComponent BindTo="viewScope.someVariable"></xc:myComponent>
<xc:myComponent BindTo="myBean.Color"></xc:myComponent>
让我们知道它如何为您服务!
Let us know how that works for you!
这篇关于动态将自定义控件中的“编辑框"绑定到托管Bean的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!