How do you use compositeData inside a REST control - xpages

I have a custom control with an ExtLib REST control on it. I'm creating JSON from the rest control. It's working fine if I hardcode everything inside the doGet tag.
But when I try and access the custom properties via compositeData in the do get I get an error:
com.ibm.domino.services.ServiceException: Error while rendering service
Caused by: com.ibm.xsp.exception.EvaluationExceptionEx: Error while executing JavaScript action expression
at com.ibm.xsp.binding.javascript.JavaScriptMethodBinding.invoke(JavaScriptMethodBinding.java:126)
at com.ibm.xsp.extlib.component.rest.CustomService$ScriptServiceEngine.renderServiceGet(CustomService.java:311)
at com.ibm.xsp.extlib.component.rest.CustomService$ScriptServiceEngine.renderService(CustomService.java:262)
... 20 more
Caused by: com.ibm.jscript.InterpretException: Script interpreter error, line=11, col=14: [ReferenceError] 'compositeData' not found
Is there a way to use composite to create my JSON object?
I'm trying to create an object like this:
var object = {};
object.height = compositeData.height
return toJson(object)

The REST Control should be considered as an independent component that has no direct access to the page on which it exists because it is possible to call the REST service via a url similar to database.nsf/page.xsp/RESTServiceName.
what you should do instead is call your REST service with a url that includes parameters to pass into the control such as database.nsf/page.xsp/RESTServiceName?height=20&width=50 and then reference them within the control using param.get("height") and param.get("width").
Another option could be to put the parameters into a scope variable and read them from there.

When the data is called from the Rest object it doesn't call the XPage in that moment, so the component tree isn't loaded. You could try using ${} instead of #{} when computing?

Related

How to obtain information of a field or variable on the Client side

I am using the Receipts page (IN301000) for reference purposes:
I would like to be able to obtain a field's information on the client side with the GetElementByID() method.
When I inspect the field, and identify the rendered ID, I obtain data:
However, if I refresh the page and invoke the method again, I obtain NULL:
Does anyone know how to make that information always available?
The final goal here is being able to pass data to the client side. I can - for instance -populate an unbounded field with the FieldSelecting event, and would like to ideally read data out of it.
If there are client variables that could be set from the graph, it would work as well.
Thanks!
You likely get null because the script is executed in the top iFrame instead of the main iFrame which contains the control.
The JavaScript global variable px_alls contains the editor controls and can be indexed by editor control ID.
px_alls["edTransferNbr"].getValue();
document.getElementById("ctl00_phF_form_t0_edTransferNbr_text").value;
Script executed in main iFrame context:
When the script is executed in the context of the top iFrame you would have to select the main iFrame.
var mainframe = document.querySelector('[name=main]').contentDocument;
mainFrame.getElementById('ctl00_phF_form_t0_edTransferNbr_text').value;
Script executed in top iFrame context:

Xpages equivalent to Database Script initialize

I am running Xpages in XPiNC.
My usual pattern for an Xpages app is to have a xpHome.xsp page that is set to be the first page that is opened. In this I page I set any scope variables that are at the application level, then head to the "real" first page.
Now I have run into a problem. My current database will send out emails when a status changes, and this will include a doc link to the document, which points to the correct Xpage to open. However, because the user is not going through the home page, then my applicationScope vars are being set.
I thought I could fix this by setting a semaphore in the initApp function - the last thing it would do is to place a "Y" in an applicationScope.semaphore field. So when I open my Xpage the first thing it does is check for that, and if it is null, then I call the initApp function.
For some reason this is not working. But even so I would like to find the equivalent of the old database script "Initialize" event. Something I can call whenever the db is opened for the first time.
How do others handle this problem?
Create a managed Java bean "app" which
works on application scope
sets all application parameters
offers all application parameters
Access the bean with app.xxx in EL or Javascript or call methods directly like app.getXxx() or app.doWhatEverYouWant() in JavaScript.
The bean "app" gets initalized automatically when one of the methods gets called first time.
You can find an example here for start or google for "XPages managed beans" for more Information.
Yes, you have to switch your current code partly to Java but it should be worth it in the long run.
If you want to or have to stay with JavaScript then initialize your application scope variables in a custom control which is included in every XPage like layout.xsp in beforePageLoad event.
Use an additional variable applicationScope.initialized. Check if applicationScope variables aren't initialized yet in JavaScript with
if (!applicationScope.initialized) {
... initialize your applicationScope variables ...
applicationScope.initialized = "yes";
}

Is there a way to use a javascript object as a custom control property?

I'm currently building a custom control to be used as an application's view navigator (classic OneUI style). First of all: this is a 8.5.3 based project, and unfortunately there's no way to use Extlib stuff or other extensions / plug-ins. So we have to build all the tricky stuff ourselves using only what came "out-of-the-box" with 8.5.3.
I'd llike to build my navigator using a repeat control containing <xp:link> controls. Datasource could be an array of javascript objects where each single object would look like this:
var navEntry = {"entryLabel" : "label-of-link",
"entryTarget" : "target-url-of-link",
"entryStyle" : "style-to-emphasize-selected-link"}
Each array element then would describe a single navigator entry.
Since the navigator will be used in all possible "DominoView" Xpages it yould make sense to build the array of JS objects at the Xpage level and then pass that info into the custom control.
I'm aware that there are multiple ways to do this, and one could be "Custom Control Properties". If there was a way to pass my JS object array.
(Hope I could make clear what I'm trying to do here...)
That object looks like a HashMap to me really. You should be able to pass that in to a custom control via custom property if you use the type java.util.HashMap I'd think. You'll need to type it in I'm sure. I've passed custom objects in by using java.lang.Object.
The custom control will get loaded during the Page Load event, and usually properties have to be available at that point. If they're loaded during the Render Response phase, that's too late. So your SSJS object will need to be Compute on Page Load.
To use contents of a repeat control, you would need to set repeatControls=true, otherwise the repeat is only built during render response. Until then it's just a single set of controls with no data in them. However, Im pretty sure repeatControls="true" means you only get the number of rows you define. You can't change it via a pager.
You can manually define the type of the custom property. For a standard SSJS Object you use "com.ibm.jscript.std.ObjectObject", for a SSJS Array you use "com.ibm.jscript.std.ArrayObject" etc. As editor for the custom property, I set the string editor ("String value").

Custom Control datasource use in Xpage

How can I use a custom control datasource (named doc) in XPage Application layout?
I need to control read mode and edit mode through the basic node of the place bar.
When I put the code doc.isEditable() in the rendered property, the following error is display in the browser:
Error while executing JavaScript computed expression
Script interpreter error, line=1, col=6: [ReferenceError] 'doc' not found
JavaScript code
doc.isEditable();
I am new to Xpage.
Can you post some code? not entirely sure what you mean.
Generally the best place to define a data source is at the top of the XPage so that every control beneath it has access to it. If your defining a data source after your trying to query it you would get an error like this

Getting to scope variables in client side javascript (CSJS) on XPages

I am setting a viewScope variable in a server side javascript (SSJS) button.
viewScope.put("branchName",doc.getItemValueString("BranchName"))
How can I access that variable on the client side?
If you need to access the viewScope variable from a client side script you can use the xp:scriptBlock tag to setup a number of global javascript variables.
<xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[var myVar = #{javascript:viewScope.get("scopeVar")}]]></xp:this.value>
</xp:scriptBlock>
The main problem with this method is that the inner server side javascript is only computed when that element is initially rendered or when a partial refresh is performed on the element so there is no guarantee that the client side JS variable is set to the correct value.
You can't access viewScope Variables directly, but you could bind it to a hidden field
then access that value via csjs
XSP.getElementById("#{id:inputHidden1}").value
There are other ways to access it also, using something like rpc or an ajax request.
use the below code:
var value = "#{javascript:viewScope.variablename}"
I would take a look at the JSON RPC included with the extension library. This component will allow you to define a SSJS function that may/may not accept arguments. Let's say you add the RPC with an ID of myRPC and a method called getViewScopeVar that accepts a single String argument and returns the value of the viewScope variable with the name that you include as the argument. You can then call that method like:
myRPC.getViewScopeVar("branchName")
This is the easiest most effective way to interact with server side elements from client side javascript. Plus it gives you the option of all the required methods being in one place as long as you place that RPC on a strategic custom control (i.e. like a layout custom control that every xpage is based off of).
If you need frequent updates you can use the Ajax service from the extension library.

Resources