How can I change Vaadin Components in Java through Javascript - javascript

I implemented Shepherd in my Vaadin Project, so i can guide users in tours through my web application.
But, i need to get access from the javascript on the Accordion Components in Vaadin, to open or close specific tabs. For this, i need to have access on the open() and close() method for the Accordion Components. So how can i access them through Javascript?
Already seen the Tutorial on the Website of them:
Vaadin calling java from javascript,
but sadly nothing over there, what could help me.
I already tried to use something like this:
UI.getCurrent().getPage().executeJs("window.startTour($0, $1)", this, Accordion1.getElement());
But when i try to bind it in javascript through:
window.startTour = (element, accordion) => { ... }
and in this window:
beforeShowPromise: function () {
return new Promise(function(resolve) {
element.$server.openAccordion(accordion.$server, 1);
resolve();
});
},
with the following method in java:
#SuppressWarnings("unused")
#ClientCallable
public void openAccordion(Object object, int index) {
Accordion accordion = (Accordion) object.get(this);
accordion.open(index);
}
i only get the following error message:
Class '...' has the method 'openAccordion' whose parameter 0 refers to unsupported type 'java.lang.Object'
No matter what i use as first parameter, everythin that extends Object doesnt work and i dont know why.
I found a recent post with the same question, but it was not helpful for me:
Unable to send a new bean instance to the server
Im using Intellij and in my Project: Java, Spring, Vaadin and Shepherd
Already tried to use different parameters, but only the int parameter is working, Object doesnt work.
The Problem is, i cant change the opened Tab of the Accordion from the Javascript over the Java, because of this error, so i have to implement for each Accordion 2 methods to open and close it.
Maybe somebody can help me with it or knows some tricks to master this.
Thanks

When using #ClientCallable you can pass only json or primitive types from JavaScript call to server. There is a real systems boundary here. Object is not supported and furthermore, you can cast that parameter to Java object.

Related

Running client side javascript without loading a new (blank) view on Odoo 8

I need to run some client-side javascript from a button in a form view in Odoo 8. This button runs a python method which returns this dictionary:
{"type": "ir.actions.client",
"tag": "my_module.do_something",}
do_something is defined in a .js file as follows:
openerp.my_module = function (instance) {
instance.web.client_actions.add("my_module.do_something", "instance.my_module.Action");
instance.my_module.Action = instance.web.Widget.extend({
init: function() {
// Do a lot of nice things here
}
});
};
Now, the javascript is loaded and executed properly, but even before launching the init function, Odoo loads a brand new, blank view, and once the javascript is over I can't get browse any other menu entry. In fact, wherever I click I get this error:
Uncaught TypeError: Cannot read property 'callbackList' of undefined
What I need instead is to run the javascript from the form view where the button belongs, without loading a new view, so both getting the javascript stuff done and leaving all callbacks and the whole environment in a good state. My gut feeling is that I shouldn't override the init funcion (or maybe the whole thing is broken, I'm quite new to Odoo client-side js) , but I couldn't find docs neither a good example to call js the way I want. Any idea to get that?
Sorry, I don't work on v8 since a lot of time and I don't remember how to add that, but this might help you: https://github.com/odoo/odoo/blob/8.0/doc/howtos/web.rst
Plus, if you search into v8 code base you can find some occurence of client actions in web module docs https://github.com/odoo/odoo/search?utf8=%E2%9C%93&q=instance.web.client_actions.add
Thanks to the pointers simahawk posted in another answer, I have been able to fix my js, which is now doing exactly what I needed. For your reference, the code is as follows:
openerp.my_module = function (instance) {
instance.web.client_actions.add("my_module.do_something", "instance.my_module.action");
instance.my_module.action = function (parent, action) {
// Do a lot of nice things here
}
};

How to call existing javascript function from android activity

I'm building an ebook reader, so I have a webview that is loading a page stored locally on the device which it retrieved from the ebook itself. On this page, it has a javascript function controls.nextPage() that loads and runs just fine; it's used to not actually navigate to new web pages, but instead redraw virtual pages using javascript. I have this function bound to a button on the web page itself so that I can manually click it to test, again, works just fine when I touch the button on my webview.
Now I am trying to trigger this exact function from within my app. Ideally, I want to do this from a gesture swipe but that is too complicated for this specific question, as I have other issues with the gestures I need to solve first. For now, I've set up a button in my navigation drawer to trigger it and test it:
NavigationView navigationViewRight = (NavigationView) findViewById(R.id.nav_view_webview_right);
navigationViewRight.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camera) {
// *** - Focus here - *** //
runOnUiThread(new Runnable() {
#Override
public void run() {
mWebview.evaluateJavascript("controls.pageNext()", null);
}
});
} else if (id == R.id.nav_share) {
}
drawer.closeDrawer(GravityCompat.END);
return true;
}
}
);
Note, I've also tried calling window.controls.pageNext() to no avail.
So my page is loaded, and I've hit my in-page button to test the function; works. I go to hit my navigation drawer button in the app? Error (when using window.controls.pageNext():
[INFO:CONSOLE(1)] "Uncaught TypeError: Cannot read property 'pageNext' of undefined", source: (1)
So it seems to be that evaluateJavascript() is being run in a fresh environment/thread. How can I tell it not to?
To get around this,I've tried to create an empty javascript interface in the hopes that I could simply initialize my page javascript into it and thus be able to call it from Android.
mWebview.addJavascriptInterface(new TestInterface(), "TestInterface");
public class TestInterface {
#JavascriptInterface
public void test() {
runOnUiThread(new Runnable() {
#Override
public void run() {
mWebview.evaluateJavascript("console.log('test')", null);
}
});
}
}
From my webapp, the javascript can call the interface just fine. calling TestInterface.test(); yields:
[INFO:CONSOLE(1)] "test", source: (1)
But when I tried to assign a new function to that interface from my webapp:
TestInterface.testTwo = function() {
console.log('testTwo');
};
TestInterface.testTwo();
Android wouldn't have it:
[INFO:CONSOLE(674)] "testTwo", source: http://127.0.0.1:8080/js/main.js (674)
What's weird is that it's not really giving me much info to go on. I do know that the rest of my page has issues loading after the testTwo() attempt that test() did not, so I'm assuming failure to load the rest of the script.
Lastly, out of curiousity, I changed my navigation drawer button to try and run the new function like this:
mWebview.evaluateJavascript("TestInterface.testTwo()", null);
Log:
[INFO:CONSOLE(1)] "Uncaught TypeError: TestInterface.testTwo is not a function", source: (1)
Yes but is it something else? I dunno. Thoughts? Thank you.
So I figured out in the end what my issue was. By running mWebview.evaluateJavascript("window.location", null); I realized that I in fact was not actually on the page I thought I was. My ebook page was being loaded into an iframe or some other type of skeleton/wrapper in such a way that the webapp functions were not in fact available when running evaluateJavascript().
So once figured that out, I can confirm some things that I originally questioned above:
So it seems to be that evaluateJavascript() is being run in a fresh
environment/thread. How can I tell it not to?
It does not. Just make sure you know what page is actually loaded.
To get around this,I've tried to create an empty javascript interface in the hopes that I could simply initialize my page javascript into it and thus be able to call it from Android.
This does in fact work. I'm not sure what my mistake was before, but if I create a javascript interface in Android, it's functions are available to the webapp AND I can in fact write new objects to the interface object from within the webapp. So, initializing new objects into TestInterface from within the webapp can be run within the Android app via:
mWebview.evaluateJavascript("TestInterface.someNewFunctionFromWebapp()", null);
I can NOT however overwrite any existing objects/properties of that javascript interface object. so TestInterface.test() is immutable.

CefSharp RegisterJsObject and non-static context

I have a window which contains a ChromiumWebBrowser.Now I want to get a message from that Browser by a JavaScriptObject and when I get it, I want to look inside my list, what image, video or hyperlink I shall show next and then do exactly that.There is only the problem of the static and non-static methods. the complete class and all methods inside where the browser is made filled are non-static. The JavascriptObject is static.There are many examples out there that show how to create this object but not how to use it.Now my question: "Is there any way of calling the Javascript inside the HTML to access non-static objects?"
edit:
Ok, I try to be more precise and detailed.
I have an app, which creates numerous windows, which are inheriting a ChromiumWebBrowser-object, an Image-object and a MediaElement-object.
When the window is created (and every few minutes afterwards) I read a XML-file (which can be edited by another user) that tells me what I shall show in my window. Some things are easy to do, like at the end of a video I look for the next item to show. But on websites its a little bit harder. So I searched and came up with the JavaScriptObject of the ChromiumWebBrowser. I implement it in the window right after the InitializeComponent() by this code:
FirstBrowser.RegisterJsObject("callbackObject", new JavaScriptCommunicationObject());
SecondBrowser.RegisterJsObject("callbackObject", new JavaScriptCommunicationObject());
Now I can use the follwing JavaScript to communicate with my app:
<script type="text/javascript">
callbackObject.callNextMedia('NextMedia');
</script >
Inside the window I declared a new class and a method. But this method is static, so I cannot call any methods from the mainclass:
public class JavaScriptCommunicationObject
{
public void CallNextMedia(string message)
{
if (message.Equals("NextMedia"))
{
MixedMediaWindow.FileCounter++;
MixedMediaWindow.ShowNextMedia();
}
}
}
I could make the FileCounter static, so I could change it from the second one. But I cannot call the ShowNextMedia(). So I wanted to ask if there is a way to call it by any direct means. I could set a static flag (boolean) and check it every few milliseconds for a change and if it was changed, so I could call the ShowNextMedia()-method from inside the DispatcherTimer. But I wanted to avoid too much Timers, a direct method-call would be much nicer.

Add a public function to a jquery plugin, to be called from another script

I'm using the Adobe Accessible Mega Menu plugin and am looking to extend this, (basically add a function that can be called from another script).
I've looked into extending jquery plugins, javascript closures and various other threads on the subject and I can see how this works
I can also see a bunch of public attributes and methods (ln 695 on) however attempting to call these merely returns the jquery object?
Equally adding a function and attempting to call that doesn't seem to work?
I've added a function called testFunction which fires an alert and should (i think) be called :
$("nav:first").accessibleMegaMenu("testFunction");
but no luck far..
Does anyone know how I can add a function to the above script, that can be called from another script?
https://codepen.io/anon/pen/VjzkqE
edit: solved - functions need to be accessed through the prototype obj as in :
nav.accessibleMegaMenu.AccessibleMegaMenu.prototype.customFunction(param);
I have implemented this approach on a project by using extend function from jquery and prototype to extend infinitescroll plugin you can take this approach and implement it to your plugin I hope this would be useful for you as well
$.extend($.infinitescroll.prototype, {
fucntion1: function() {
//function implementation
},
fucntion2: function() {
//function implementaion
}
});
take a look for the question Best Way to Extend a jQuery Plugin

Instantiating javascript objects from ASP.NET Pages

Most of the examples you find on the web, of using javascript from ASP.NET pages puts the javascript in the markup file (*.aspx). This is, of course, a really bad idea(tm), for all but the simplest uses of javascript.
What we want, of course, is to wrap the javascript up into a class, and to instantiate an instance of that class and tie it to the code-behind.
Microsoft provides a framework for doing this for user controls and server controls, in its IScriptControl interface. This allows a developer to create a javascript "component" - to define a javascript class in a *.js file, to include the *.js file on the page that contains the control, to instantiate an instance of the component, to set variables in the component from values in the code-behind, and to get a reference to the component in javascript on the client side.
The thing is - IScriptControl only works for user and server controls. It cannot be used to instantiate javascript objects at the page level.
So - how do people do this? We have some patterns we've been using, that seem to work. I was wondering what everyone thought of them, and what other people were using.
We start by defining a javascript class in a *.js file. In the code-behind, we create a loadJavascript() function, that we call from Page_Load on initial load or full postback (but not on partial postbacks).
In loadJavascript(), we include the *.js file with ScriptManager.RegisterClientScriptInclude(), and then construct a bit of javascript that instantiates an instance of the class, assigns a reference to a known name, and registers the object's initialize() and dispose() methods as handlers for window.load and window.unload.
E.g.:
string url = this.ResolveUrl("./FooBar.js");
ScriptManager.RegisterClientScriptInclude(this, this.GetType(), url, url);
string script = #"
if (typeof {0}_obj == 'undefined')
{0}_obj = {{}};
{0}_obj.fooBar = new FooBar();
Sys.UI.DomEvent.addHandler(window, 'load',
function()
{{
{0}_obj.fooBar.initialize('{1}', '{2}');
}}
);
Sys.UI.DomEvent.addHandler(window, 'unload', {0}_obj.fooBar.dispose);
";
script = String.Format(script,
new object[]
{
this.ClientID,
this.foo.ClientID,
this.bar.ClientID
});
ScriptManager.RegisterStartupScript(
this, this.GetType(), this.ClientID, script, true);
We construct an object name in the global namespace, based on the ClientID of the page, if we haven't already. We add an instance of our new class as a member of our global object. We add a window.load handler that calls our object's intialize() method, passing the clientIDs of the controls on the page that the object's methods need to access. And we add a window.unload handler that calls our object's dispose() method, that does whatever cleanup that is necessary.
This seems to be working, for us. We've used this pattern on a number of pages, some of which did significant amounts of partial-postbacks, without any problems.
I was wondering, first, what people thought of the pattern.
But more, I was wondering if we'd been reinventing the wheel, and if there were other approaches to dealing with the issues we were addressing, that we weren't aware of.
Anyone have any better ideas?
But more, I was wondering if we'd been reinventing the wheel, and if there were other approaches to dealing with the issues we were addressing, that we weren't aware of.
I think this the most good approaches, I use the same way some years now with out any problem in very complex javascript code. I do not see why you question your self :)
The idea is this you follow, now maybe there are some variations, maybe I not call the unload, nether create an object to keep the foobar and call the foobar rightway, but the idea is the same. I also check if the Javascript file have been loaded...
string script = #"
if (typeof (FooBar) != "undefined") {{
var {0}fooBar = new FooBar();
Sys.UI.DomEvent.addHandler(window, 'load',
function()
{{
{0}fooBar.initialize('{1}', '{2}');
}}
);
}}

Categories

Resources