interrupt a Bean-method by calling a javaScript function? - jsf

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)

Related

LitElement and .bind(this)

I'm finding a little confusing sometimes you need to bind the context to a function call and sometimes not. When exactly can you avoid it and when you not?
What's the difference between those lines?
<a #click="${this.handler.bind(this)}">link</a>
<a #click="${this.handler()}">link</a>
<a #click="${this.handler}">link</a>
<a #click="${()=>this.handler()}">link</a>
Also sometimes in the constructor() you need
this.handler = this.handler.bind(this)
to make the function call works, sometimes you not. What's the differences between all those cases?
In the first 4 lines I am guessing you usually wrap them in between ${ and }.
With this mention these 3 lines:
<a #click="${this.handler.bind(this)}">link</a>
<a #click="${this.handler}">link</a>
<a #click="${()=>this.handler()}">link</a>
would be pretty similar in the effect. When you attach an event handler you need to pass a reference to a function/method to call, while the second line:
<a #click="${this.handler()}">link</a>
will most likely just be wrong. That's because you will be calling this.handler() as soon as the rendering is done. The only way it might make some sense it would be if the handler method returns a function.
Going back to the first 3 lines: they will indeed have very similar effect, as in all of them you are passing references to a local method render, but:
the first one doesn't need binding as the method will anyway be
called in this context (but I guess it doesn't hurt either)
the third one adds the definition of an anonymous function as an
event handler, which when called it will invoke this.handler
So the second one is basically the simplest and easiest to read.
When it comes to the need to call bind in some of the cases: that's needed when your method is called from another context. Let's say you pass it as a callback parameter to a method running in another class. When you method will be called there, it will have by default the context of that other object. So you will need to use .bind(this) to make sure that when the method is called in your element's context.
Your method does work, but it's running from another this. So maybe that's why some of the times you don't notice the need to .bind(this). If the method just shows a message, calls some other external service, or anything else that is not part of your object's definition (that doesn't use this.something), it will work without using bind.
UPDATE: in fact I think an event handler will always run in the context of the element that originated that event. I am guessing that lit just does that .bind(this) when we use that #click= syntax, as it would make a lot of sense.
Note that binding directly in templates is generally not a good idea. It can result in performance issues and components re-rendering when they shouldn't.
https://github.com/43081j/eslint-plugin-lit/blob/master/docs/rules/no-template-bind.md
As to why you sometimes need to bind consider this:
#customElement('main-page')
export class MainPage extends LitElement {
#property()
public name = "bob";
render() {
return html`<button #click=${this.clicked}>Click Me!</button>`;
}
clicked() {
console.log("clicked " + this.name);
console.log("this in clicked: " + this)
setTimeout(this.sayHi, 1000);
}
sayHi() {
console.log("this in sayHi: " + this)
alert(`Hello, ${this.name}!`);
}
}
If we click on the button, we get the name logged properly:
But the name isn't shown in the alert:
If we look at this in both functions we get different results:
One is an HTMLElement and the other one is a Window. What this refers to is different once we pass sayHi to setTimeout.
Bind will fix this by making sure that this refers to the right object.
While we could do setTimeout(this.sayHi.bind(this), 1000); and it would fix our issue but it's not very clean and it's error prone. We could bind it in the constructor, but this also isn't much better.
The cleanest way to do it is to directly bind this by using an arrow function instead:
sayHi = () => {
[...]
This notation binds this to the object itself. We then do not need to bind it explicitly ourselves.
Once we do that, both this refer to the right object:

How to dispose of a ViewModel in Durandal after Logout

I might be on the wrong track here, but here goes:
In my PhoneGap Durandal app, I have a Profile View/VM which only returns data the first time it is hit - after that it checks a bool called initialised and wont hit the DB again the 2nd time. This works fine.
However after Logout, I need to invalidate the cache. I could use a message to tell the Profile VM to clear the variable (ie. invalidate the cache) but I thought perhaps there is a higher-level way of doing this in Durandal - e.g. On Logout, I tell dispose of all ViewModels in memory (there may be other Singleton objects with session specific info in them).
Advice please...
This is more of a javascript question and this is just my understanding of how javascript works.
Javascript will automatically dispose of objects that are no longer referenced through a mechanism called Garbage Collection.
Here is a good article on how Garbage Collection works. Basically it will dispose of objects that are no longer referenced in your program.
There is another method in javascript that allows you to remove objects. The delete method:
delete someobj;
Which too my knowledge is pretty much equal to someobj = undefined;
Hope this helps.
***Edit
Durandal follows the screen activator pattern for it's viewmodels. So apart of the viewmodel lifecycle it will call an activate, candeactivate, and deactivate method.
You could do your disposing in the deactivate method.
(Durandal 2.0) You could always hook into the composition life-cycle callback methods on your view-model. There are four: activate(), attached(), deactivate(), and detached(). They are called automatically by Durandal on your view-model, if they exist. In my projects, if I need a view to invalidate its cache, I hook into the deactivate() method and put the cleanup logic there. Similarly, I use the detached() method to unbind events and destroy UI widgets.
Simple example:
define(['modules/myDataService'],
function(dataservice) {
var cache;
function activate() {
return dataservice.getData().done(function(response) {
cache = response;
});
}
function deactivate() {
cache = null;
}
return {
activate: activate,
deactivate: deactivate
};
});
Source documentation: http://durandaljs.com/documentation/Hooking-Lifecycle-Callbacks/

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

Perform GM_xmlhttpRequest() from eval

I have a little Greasemonkey script that communicates with a servlet on (my) server. The servlet is sending back JavaScript code, which I eval() in the onload handler of the GM_xmlhttpRequest.
So far, all is working fine. Now, I'd like to use send another GM_xmlhttpRequest from within that eval()ed code. and here I'm stuck. I do not see any error, but all GM_* functions appear not to be working from within the eval(responsetext).
If I hard code the GM_xmlhttpRequest in the onload handler (no eval()), it is working fine.
It is possible to work around this problem, you can call GM_* functions with setTimeout set to 0 from eval'ed code. Try something like:
function myFunction()
{
GMXmlHttpRequest(...)
}
eval('setTimeout(myFunction, 0)');
A better solution is to extend Function.prototype with a function called safeCall that does this for you. Whenever you have any eval'ed code that will call into GM_* functions you'll need to have safeCall somewhere in that call chain.
Greasemonkey (GM) is hosting the user script, which means that it can add functions and objects to the user script, when you call eval() the script runs unhosted (the vanilla JavaScript is running it) and you don't get the GM API inside of it.
There is another solution. I have the similar problem, I don't want to put all my logic in user script, because if I change them, user need to update them by themselves. So what I want to do is separating the main logic from loading logic, the main logic will be loaded at beginning by the user script and eval them.
So I made a function "sendRequest", which is a wrapper of GM_xmlhttpRequest(), I need it anyway, because the method, server url and onError callback are always same for my application, so I just put them into my "sendRequest" function to make the xmlhttprequest simple.
In the main logic javascript code, which is loaded from server, there is no greasemonkey function call at all. If I want to for example communicate with server, I will call sendRequest instead. It works.

How to forward a request to non-JSF page in action method?

I want to forward request to a non-JSF page from JSF action method.
I am using below code in my JSF action :
public String submitUserResponse() {
// ...
parseResponse("foo.jsp", request, response);
// ...
return "nextpage";
}
private String parseResponse(String uri, HttpServletRequest request, HttpServletResponse response) {
if (uri != null) {
RequestDispatcher dispatcher = request.getRequestDispatcher(uri);
dispatcher.forward(request, response);
return null;
}
// ...
return "xxxx";
}
The submitUserResponse() action method is being called when user clicks the submit button from the JSF page and this method returns nextpage string. Here the request forwards to next JSF page in normal flow. But in my requirement, I need to forward request to next non-JSF page. It is going, but it is displaying below exception in server.
java.lang.IllegalStateException: Cannot forward after response has been committed
I observed that code lines between parseResponse(...) and return "nextpage"; are still being executed after forwarding my request using dispatched.forward(uri). Same thing happened with response.sendRedirect(url). How is this caused and how can I solve it?
Here my doubts are: 1.why next lines of code is being executed after forwarding my request using dispatched.forward(uri) . Same thing happening in response.sendRedirect("").
Because you didn't call return to jump out of the method block. The include(), forward() or sendRedirect() really doesn't have some magic that they automagically does that. Those are still just Java methods like any other (except of System#exit() of course). They will be invoked in order and the code will just continue until end of method block or return statement. It's just all about the code flow you write and control yourself.
That said, the normal JSF practice is that you should use ExternalContext#dispatch() or ExternalContext#redirect() for this (the first is applicable in your case). Not only it keeps your code free from unnecessary "under-the-hood" clutter in JSF code such as the Servlet API, but it also removes the need to call FacesContext#responseComplete() which you could also have done to fix your initial IllegalStateException problem.
In a nutshell: replace your code by
public void submitUserResponse(){
String uri = "foo.jsp";
FacesContext.getCurrentInstance().getExternalContext().dispatch(uri);
}
That's all. No need to unnecessarily dig the Servlet request/response from under the JSF hoods. Note that the method is declared void. This is perfectly acceptable, although some know-it-better like IDE's will complain about it, if so, then just ignore it or replace by String and add return null;.
See also:
How to navigate in JSF? How to make URL reflect current page (and not previous one)
ExternalContext.dispatch() not working
This worked for me:
FacesContext.getCurrentInstance().getExternalContext().dispatch("/ServletUrl");
(pay special attention to the fwd slash '/')

Resources