5

我已经阅读了许多关于在自定义控件中动态绑定字段的优秀文章和文章,但它们都假定了文档数据源。

我想允许托管 bean 数据源的可能性。我尝试将属性类型设置为com.ibm.xsp.model.DataSourcecom.ibm.xsp.extlib.model.ObjectDataSource这些都不适用于以下 xml:

<xp:inputText
    id="input"
    value="${compositeData.dsn[compositeData.fieldName]}"
>
</xp:inputText>

在使用控件的地方,我已经传入了自定义数据,如下所示:

<xc:input
    dsn="#{issue}"
    fieldName="Database"
>
</xc:input>

为了我的测试目的,我有一个名为的托管 bean issue,我调用了我的 field Database。我通常会绑定到,#{issue.Database}但我不知道如何动态地做到这一点。理想情况下,我也想支持文档数据源,但如果我不能两者都做,那么我需要绑定到托管 bean。

编辑:问题似乎是数组符号。如果我将我的值硬编码到#{issue.Database}它可以工作,但是如果我将它硬编码到#{issue[Database]}它会失败。所以问题是是否存在点符号的替代表示。我今天没有时间,但我想知道如果我只是将 #{issue} 传递给 dsn 并将其用作我的数据绑定,而不是将 dsn 和 fieldName 分开,那是否可行?当我有机会时,我会尝试。

Edit2:看来问题可能与我正在使用的 bean 有关,我将在此处发布代码。

抽象地图模型

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);
    }
}

抽象文档地图模型

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;
}

}

问题模型

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>
4

2 回答 2

8

诀窍是交出一个字符串作为参数,这将是您要使用的 EL。假设您有一个参数 bindTo as String,其值为 myBean.Color

  <xp:this.value><![CDATA[${javascript:"#{"+compositeData.BindTo+"}"}]]></xp:this.value>

$ 将首先评估并用实际值替换compositeData。该方法的美妙之处:适用于任何 EL。Document Bean 等,因此您的自定义控件不需要对其容器进行任何假设。

所以你可以用各种绑定来调用你的组件:

 <xc:myComponent BindTo="document1.subject"></xc:myComponent>
 <xc:myComponent BindTo="viewScope.someVariable"></xc:myComponent>
 <xc:myComponent BindTo="myBean.Color"></xc:myComponent>

让我们知道它是如何为您工作的!

于 2014-02-13T00:05:10.223 回答
3

确保您传递给自定义控件的对象满足以下条件之一:

  1. 它确实是一个 bean(具体来说,遵循bean 约定)。例如,如果您将绑定到database属性,则对象应该(至少)具有getDatabase返回属性当前值的方法database;如果该属性不是只读的,则该类还应该有一个setDatabase接受新值的方法。
  2. 它是一个DataObject:您的对象实现了com.ibm.xsp.model.DataObject接口。此接口需要您实现的泛型getValuesetValue方法将分别用于检索和更新任何属性的值,包括database.
  3. 这是一张地图。您绑定到的任何属性名称都将被视为地图的键。
  4. 它是 的一个实例com.ibm.jscript.types.FBSObject{ }这是在运行时解析 SSJS 字符串时所有 SSJS 对象文字 () 成为的底层 Java 类。小心在托管 bean 中使用这种类型,因为这些对象是不可序列化的。

只要您传入的对象是这四个之一,您的问题中列出的 EL 语法就是有效的。将属性类型设置为您传递的对象的实际类名或它扩展的基类(或它实现的接口)。或者,为了确保它可以接受任何内容,只需将属性类型设置为object.

但是请记住,将一个类声明为托管 beanfaces-config.xml只是“管理”一个变量名和范围……这个声明实际上并没有使您的 Java 类成为一个 bean。除非它符合bean 约定,否则它不是 bean。如果它确实符合 bean 约定,那么它就是一个 bean,无论您是否将它声明为托管bean。这种区别在 XPages 社区中造成了很多混乱,所以我只想在这种情况下再次强调这一点。

于 2014-02-12T18:57:57.780 回答