5

カスタム コントロールでフィールドを動的にバインドすることに関する優れた投稿や記事を多数読んだことがありますが、それらはすべてドキュメント データ ソースを前提としています。

マネージド Bean データ ソースの可能性を許可したいと考えています。プロパティタイプをcom.ibm.xsp.model.DataSourceorに設定しようとしましたcom.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あり、自分のフィールドを呼び出しましたDatabase。通常はバインドし#{issue.Database}ますが、それを動的に行う方法がわかりません。理想的には、ドキュメント データ ソースもサポートしたいのですが、両方できない場合はマネージド Bean にバインドする必要があります。

編集:問題は配列表記にあるようです。値をハードコードする#{issue.Database}と機能しますが、ハードコードする#{issue[Database]}と失敗します。したがって、問題は、ドット表記の代替表現があるかどうかです。今日は時間がありませんが、dsn と fieldName を分離する代わりに、#{issue} を dsn に渡して、それをデータ バインディングとして使用した場合、うまくいくでしょうか? 機会があればそうしてみます。

Edit2: 問題は私が使用している Bean に関連している可能性があるため、そのコードをここに投稿します。

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

}

問題モデル

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 となるパラメータとして文字列を渡すことです。値が myBean.Color の String としてパラメーター bindTo があるとします。

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

$ が最初に評価され、compositeData が実際の値に置き換えられます。アプローチの美しさ: どの EL でも機能します。ドキュメント 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

Make sure that one of the following is true about the object that you're passing to the Custom Control:

  1. It really is a bean (specifically, follows bean conventions). For example, if you'll be binding to the database property, the object should have (at a minimum) a getDatabase method that returns the current value of the database property; if the property is not read-only, the class should also have a setDatabase method that accepts the new value.
  2. It's a DataObject: your object implements the com.ibm.xsp.model.DataObject interface. The generic getValue and setValue methods this interface requires you to implement will be used to, respectively, retrieve and update values for any property, including database.
  3. It's a Map. Any property name you bind to will be treated as a key for the map.
  4. It's an instance of com.ibm.jscript.types.FBSObject. This is the underlying Java class that all SSJS object literals ({ }) become when the SSJS string is parsed at runtime. Be wary of using this type in managed beans, because these objects are not serializable.

渡すオブジェクトがこれら 4 つのいずれかである限り、質問に記載されている EL 構文は有効です。プロパティ タイプを、渡すオブジェクトの実際のクラス名、またはそれが拡張する基本クラス (またはそれが実装するインターフェイス) のいずれかに設定します。または、何でも受け入れるようにするには、プロパティ タイプを に設定しますobject

But remember, declaring a class as a managed bean in the faces-config.xml only "manages" a variable name and scope... this declaration doesn't actually make your Java class a bean. Unless it conforms to bean conventions, it's not a bean. If it does conform to bean conventions, it's a bean, whether or not you declare it as a managed bean. This distinction is a source of much confusion in the XPages community, so I just wanted to belabor that again in this context.

于 2014-02-12T18:57:57.780 に答える