通过自定义控件属性或自定义事件传递函数给自定义控件?

4

我想做的事情是,我有一个自定义控件和一个按钮。如果我将它放在页面上,我希望最终用户程序员定义按下按钮时发生什么。

我有三个想法来实现这个目标, 但不知道是否可行或者不知道如何做到。

  1. 通过自定义属性传递函数。按钮将调用该自定义属性作为函数。这可能吗?如果可以,我该如何做?我试过了,但似乎不起作用。

    compositeData.ssjs_clickOK("Hello World");

  2. 为自定义控件定义自定义事件。这可能吗?应该如何操作?

  3. 使按钮调用需要由用户程序员定义的唯一功能名称。看起来有点凌乱,但可能行得通。我的按钮代码如何查看是否已定义了该函数?如果 (MySpecialFunction != null) 是否有效?

4个回答

5
我在我的一个应用程序中使用以下内容将函数传递给自定义控件:
1) 在自定义控件中添加一个属性,用于保存要在操作按钮中执行的函数。我将其称为“querySave”。属性类型必须为“javax.faces.el.MethodBinding”。编辑器必须为“Method Binding Editor”。
2) 以下是此示例中自定义控件中操作按钮背后的代码:
if (compositeData.querySave) if (!compositeData.querySave.call()) return;
currentDocument.save();

这段话的意思是:如果在属性“querySave”中定义了一个函数,则调用它。如果该函数返回false,则不保存文档。
第3步是定义一个SSJS函数,以执行您需要操作按钮执行的操作。通常我会将其放在SSJS库中,并确保XPage可以访问该函数。
第4步是在包含此控件的XPage中,使用我们在第1步中创建的属性编辑器(例如querySave),并输入您在第3步中创建的函数名称。重要提示:不要在输入函数名称时添加括号或参数-如果这样做,函数将在加载时执行而不是在单击操作按钮时执行。此外,请勿直接向编辑器添加任何代码,只需添加函数名称即可。在此编辑器中的任何代码也将在加载时执行。
感谢Bill Hanson在Experts Exchange上的回答

--

更新:

这是一个具有自定义属性的自定义控件的具体示例,其中调用了名为validateDocument的SSJS函数:

<xc:component_buttons>
    <xc:this.validateFunctionName><![CDATA[#{javascript:validateDocument}]]></xc:this.validateFunctionName>
</xc:component_buttons>

这里是自定义控件中调用函数的按钮示例:

<xp:button id="submit" value="Save">
    <xp:eventHandler event="onclick" submit="true" refreshMode="complete">
        <xp:this.action>
            <xp:actionGroup>
                <xp:this.condition><![CDATA[#{javascript:
                if (compositeData.validateFunctionName) {
                    compositeData.validateFunctionName.call();
                }}]]>
                </xp:this.condition>
                <xp:save></xp:save>
            </xp:actionGroup>
        </xp:this.action>
    </xp:eventHandler>
</xp:button>

这个有点儿成功,但是我觉得可能是你最后一步搞混了。我的做法是创建了一个函数并将其放在了一个 SSJS 库中,我在 xpage 上作为资源包含了这个库。然后我只是在我的 CC 属性中放置了函数的名称,但是我收到了以下错误信息:Script interpreter error, line=4, col=36: Java method 'setValue(undefined)' on java class 'com.ibm.xsp.component.xp.XspInputText' not found. setValue 是我的函数名称。我只是把它放在编辑器里而已,没有其他更改。 - Bruce Stemplewski
如果我不传递参数,这个函数工作得很好。但是我希望我的按钮能够将一个值传递给这个函数。就像回调一样。 - Bruce Stemplewski
Bruce,我已经更新了我的答案,并提供了具体的例子。希望能有所帮助。 - Per Henrik Lausten
好问题,布鲁斯。我不知道因为我没有尝试过。您可以将参数传递为其他自定义属性。问题是在使用.call()调用函数时如何将参数传递给函数。 - Per Henrik Lausten
我使用了Sven的解决方案中的一部分来传递参数。我通过一个数组来传递参数。但是我认为你的想法也可以,我可能会使用它。似乎更直接明了。 - Bruce Stemplewski

4
请看这个问题:Pass javascript code to Custom Control 我的回答描述了如何通过方法绑定从自定义控件传递SSJS代码。
编辑:
  1. Create a custom control "ccSSJS"
  2. Add a property ssjsCode to your CC
    • Type: javax.faces.el.MethodBinding
    • Editor: Method Binding Editor
  3. This is the source of the CC

    <?xml version="1.0" encoding="UTF-8"?>
    <xp:view xmlns:xp="http://www.ibm.com/xsp/core">
    
       <xp:button value="Label" id="button1">
         <xp:eventHandler event="onclick" submit="true"
            refreshMode="complete">
            <xp:this.action>
               <![CDATA[#{javascript:
                  var args = new Array();
                  args["abc"] = "123";
                  args["cde"] = "456";
                  compositeData.ssjsCode.invoke( facesContext, null );
               }]]>
            </xp:this.action>
         </xp:eventHandler>
       </xp:button>
    </xp:view>
    
  4. Create a XPage and add the Custom Control

    <?xml version="1.0" encoding="UTF-8"?>
    <xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xc="http://www.ibm.com/xsp/custom">
    
    <xc:ccSSJS>
          <xc:this.ssjsCode>
             <![CDATA[#{javascript:
                var app = facesContext.getApplication();
                app.createMethodBinding("#{javascript:print( args['abc'] )}", null); 
             }]]>
          </xc:this.ssjsCode>
       </xc:ccSSJS>
    
    </xp:view>
    
如果您点击自定义控件中的按钮,将会调用方法ssjsCode

似乎这适用于 CSJS。有没有办法在 SSJS 中实现? - Bruce Stemplewski
在我的回答中添加了一个示例。 - Sven Hasselbach
谢谢更新。我该如何使用CC按钮提供的值来设置我的xPage上的编辑框的值?我尝试了app.createMethodBinding("#{javascript: getComponent('inputText1').setValue(args[0]); }", null); 但是我收到了一个错误。xPage上的事件处理程序如何知道由CC设置的args数组?我没有看到它被传递到哪里。 - Bruce Stemplewski
但是我的错误在哪里?如果我将相同的代码放在按钮中,它就可以正常工作。 - Bruce Stemplewski
那么对于我向最终用户程序员提供的文档,我需要让他们了解 args 参数吗? - Bruce Stemplewski
显示剩余6条评论

1

在包含自定义控件的页面上的任何位置定义一个任意事件处理程序,并确保给它一个ID:

<xp:eventHandler id="customEvent" event="customEvent">
<xp:this.action>
<![CDATA[#{javascript://your custom code}]]>
</xp:this.action>
</xp:eventHandler>

您可以将与事件处理程序相关联的方法绑定传递到接受MethodBinding(或“对象”)的自定义控件的自定义属性中:
getComponent("customEvent").getAction();

然后,从您的自定义控件内部,您可以直接调用绑定方法:

var customMethod = compositeData.get("customEvent");
var customArguments = compositeData.get("customEventArguments");
customMethod.invoke(facesContext, customArguments);

确保您的自定义控件的“customEventArguments”属性设置允许多个...这将强制该属性被视为数组,而调用方法则期望数组。

0
这里有第四个选项。不要在您的自定义控件中包含按钮。相反,添加一个可编辑区域,其中id="actionButton"。您可以使用类似于以下内容的内容在自定义控件的设计定义中告诉开发人员他们需要添加按钮以及位置:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" style="background-color:#4a4a4a;color:#fff;">
Add a button to the facet below.<br/>
<xp:callback facetName="actionButton" id="callback1"></xp:callback>
</xp:view>

在设计定义中包含xp:callback将为开发人员提供一个运行时的拖放区域,以添加按钮(按钮可能需要在面板或其他容器控件中,我不确定)。如果您已经在客户控件上有其他可编辑区域,则还需要在设计定义中包含它们。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接