Call SSJS from CSJS in XPages - xpages

I need to call a java bean method from a client side javascript library. Is there a way to call ssjs from csjs library?
something like this that works in csjs
var test = #{javascript:getConfig.getKeyValuesList("param")};

You want to use the Remote Service tool in the Ext. Library. That lets you define a function in SSJS and call it from CSJS.
There's discussion of it here:
http://www.notesin9.com/2014/05/21/tim-explains-json-rpc-codefortim/
There's an old NotesIn9 Video should should still be very valid:
http://www.notesin9.com/2011/08/25/notesin9-033-introduction-to-remote-services-in-xpages/

You can do it the way you showed in your example like
var test = #{javascript:yourBean.getSomething()};
The SSJS code gets executed first, the result gets inserted into CSJS code and send to client.
It depends on your use case if that can be a solution for you.
Your a bit modified example
var test = ['#{javascript:getConfig.getKeyValuesList("param").join("', '")}'];
would execute the methode getKeyValuesList(), return a List of strings, .join() would convert it to a string like "aaa', 'bbb', 'ccc" and send the following resulting code to client:
var test = ['aaa', 'bbb', 'ccc'];

I do this with a combination of CSJS libraries where I define objects with properties and methods and then on a custom control (usually the one with the resource for the library) I add a scriptBlock for getting the data into my client side objects. As frank says this only happens when the page is loaded but for configuration data like what you seem to be getting that works just fine.
Here is a sample csjs class for your library:
var appConfig = {
param1 : "",
param2 : ""
}
Then this is the scriptBlock code:
<xp:scriptBlock>
<xp:this.value><![CDATA[
// setup config parameters
appConfig.param1 = '#{javascript:getConfig.getKeyValuesList("param1")}';
appConfig.param2 = '#{javascript:getConfig.getKeyValuesList("param2")}';
})
]]></xp:this.value>
</xp:scriptBlock>
Happy coding.

Related

interrupt a Bean-method by calling a javaScript function?

What I want to do:
I want to call a javaScript function from a Bean-function
Then I want to pause my Bean-function
Then the JavaScript function do it's own thing and returns stuff back to the bean
Then the Bean-function wakes up and handle the result
Details:
I am using JSF 2.2, and ICEfaces 4.2.0.
I am using JavaScriptRunner.runScript() to call a javascript function. (This works well)
Calling bean function from JavaScript works well
According to the docs about JavaScriptRunner.runScript() the function should "Send immediately Javascript code to the client for evaluation and execution"
Problem:
The problem is that the javaScript function won't be called before the bean code has ended.
Is it possible to start the javaScript function by interrupting the bean-function?
EDIT:
Added an example Bean of how I how thought it should work, if it helps:
public class MyBean {
public String callJavaScriptFunctionAndWaitAndHandleResult() {
// Call a javascript function from the bean
callJavaScriptFunction();
// Waits untill the javascript has returned some stuff
pause(); // <-- IS IT POSSIBLE TO WAIT HERE AND RUN A JAVASCIPT FUNCTION?
// Handle the result you got from the javascript function
handleResultFromJavaScript();
}
}
Disclaimer: Code in the answer will contain untested code in PrimeFaces flavour and 'pseudo code'. Since I do not use/run IceFaces nor do I have the intention to, I cannot (will not) test the code and will only provide the PrimeFaces counterparts as an (untested) example
Answer
You seem to be stuck trying to get a technical solution to work that cannot work. JSF cannot 'pause' things and will only return data at the end of the bean method that is called. You are most likely mislead by the statement in the IcesFaces documentation
"Send immediately Javascript code to the client for evaluation and execution"
This cannot work due to the way JSF works and it is sort of not really good English. The developers should have stated something like
"Send Javascript code to the client at the end of the method call for immediate evaluation and execution"
The immediate means that it is not some <script> .... </script> that gets added to the page and that can be executed again and again by e.g. calling a function that is defined in the script. It does not mean you cannot call existing javasript functions (ones that are already in your DOM) from the returned script (effectively that is what we will be using)
So how to solve your problem. Start by breaking the method down in two, lets call them step1 and step2
void step1() {
// Do things
// return javascript
}
void step2() {
// Do other things using values that will be posted from the client by javascript
}
How to return javascript/call javascript from a bean is an existing Q/A here in Stackoverflow. For the IcesFaces counterpart I refer to their documentation. A PrimeFaces example is
PrimeFaces.current().executeScript("alert('This onload script is added from backing bean.'); clientSideFunction();");
But at the end of the javascript you want to call a server side method in a bean from javascript. The opposite of what you need in step one.
A PrimeFaces example being
<p:remoteCommand name="clientSideFunction" action="#{bean.step2}" />
And in since in calling step2() you want to pass parameters to the bean, you need to implement this as well.
clientSideFunction([{name:'x', value:10}, {name:'y', value:20}]);
You can use javascript variables in there (e.g. a complete json string in a variable) and need to process these variables (especially see the 'update' at the end)

Using Custom Functions with "I" in Page Object and Custom Helper in CodeceptJS

Hi CodeceptJS Community,
Is there a way to use custom defined functions (under steps_file.js) as I. customFunction() in page object files.
Is there a way to use native codeceptjs functions (like I.click()) in my custom helper files
I couldn't find any help in the documentation and in other sources. Is there any way to achieve this?
And is there any way to use xpath locators in puppeteer helper?
this.helpers['Puppeteer'].page.click(xpath);
I had the same problem to use custom steps in pageObjects.
To avoid it, i passed the actor (I) as parameter to my pageObject function.
page object:
const I = actor();
module.exports = {
doSomething(I){
I.login();
}
};
Test scenario:
Scenario('Test something' (I,pageObject)=>{
pageObject.doSomething(I)
})
In this case, pageObjects will has access to all custom steps from I :)
Thank you for your sharing Matheus. I have used a different solution. Instead of writing "I" object in every page object method (which was also one option for me), I have created a custom helper file and written all methods using puppeteer helper like below;
async method() {
await this.helpers['Puppeteer'].click(xpath);
}
I can call this method both in tests and page objects
I.method();
I was facing the same issue and when I looked into the typescripts definitions I noticed that actor() which is required in every page object etc. has custom steps arguments.
So this worked for me to extend the const I = actor(); witht the custom steps form steps_file.js;
const customSteps = require('./steps_file');
const I = actor(customSteps());
After that, I can use all methods in page objects like in tests scenarios which are accessing the methods from steps_file.js

Nodejs ES6 class not returning methods [duplicate]

I know that if I type:
$('body');
I get a jQuery object. However on chrome's console I'll only see the internal array of the jQuery object, despite the fact that jQuery methods are accessible like
$('body').hide();
Why the console don't show me all the accessible methods and how did jQuery manage to do this magic?
If it's just because these methods are defined on a prototype, then how come when I write these lines:
function Person(){this.myProp = 'test'};
var person = new Person();
Person.prototype.proto = 'test2';
and then I inspect person in chrome I will see:
__proto__: Person
constructor: Person()
proto: "test2"
but when Inspecting $('body'); then no proto is shown on dev tools?
The methods are on the prototype of the object. Both the console and console.log() do not, by default, show items on the prototype.
If you examine a jQuery object in the Chrome debugger, you can expand the prototype and can then see all the methods there.
So, what you are seeing is just the chosen implementation of the console. It shows direct instance properties, not items on the prototype.
When I put this code into a page:
function Person(){this.myProp = 'test'};
Person.prototype.proto = 'test2';
var person = new Person();
var jq = $("body");
And, then examine both person and jq in the Chrome debugger, I see this:
which shows the `proto property on both objects. And, if I expand that property for the jQuery object, it does indeed show all the methods.

Passing variable from jade to ng-init not working

I'm trying to pass an object from jade to ng-init in angular
This: doesn't work:
ng-init='tables=!{JSON.stringify(tables)}'
This: expands but,
ng-init='tables=#{JSON.stringify(tables)}'
the output is unescaped and filled with "s
ng-init="tables={"12":{"id":....
and the view isn't updated in either of the cases. This article implies that first one should work, but like I said, it doesn't even expand,
ng-init='tables=!{JSON.stringify(tables)}'
in source code shows up exactly the same in the HTML source
ng-init='tables=!{JSON.stringify(tables)}'
Actually, the #{...} approach seems to work fine.
It is probably the way console.log prints attributes' values that confused you.
ng-init="tables=#{JSON.stringify(tables)}"
Take a look at this short demo.
In what use-case you want to pass data directly from Jade to angular? I think you could to this job in controller like this :
$scope.init = function () {
// init stuff
}
...and in your view :
ng-init = init()

How I can call a javascript function with MonoTouch and vice versa?

i'm new using monotouch.
My problem is i want call a javascript function from a monotouch function and javascript function could call a monotouch function too.
I believe that with objective c this problem is possible, but i need making it with monotouch.
Help me please.
any help is thank for advance
To invoke Javascript code running in the UIWebView from your application, use the EvaluateJavascript method, like this:
myView.EvaluateJavaScript ("a = 1;");
To call back into your C# code, the only option is to hook up to the ShouldStartLoad property like this:
myView.ShouldStartLoad = myHandler;
[...]
bool myHandler (UIWebView webView, NSUrlRequest request, UIWebViewNavigationType navType)
{
// Determine what to do here based on the #request and #navType
}
You can of course, also use anonymous methods if you want to access local variables easily:
myView.ShouldStartLoad = (webView, request, navType) => {
// Determine here what to do
}
In the Javascript side, if you want to call back to Mono, you then set the location.href property to a "special" url, like this:
// Javascript code:
location.href = "myapp://action?par1=abc&par2=def"
The information will be available on the request object: request.Url.AbsoluteString
I just released MonoTouch JsBridge to make this easier. It allows you to add event listeners and fire events between the native side and the UIWebView. It was inspired by Titanium.
https://github.com/crdeutsch/MonoTouch-JsBridge
I haven't tried it in monotouch, but it should be the same as in ObjC:
UIWebView.EvaluateJavascript

Resources