There is no doubt that the role of JavaScript changed for the software development stack during the last years. There are impressive examples how to visualize data in web and mobile applications. A popular library to create graphs and charts is D3.js . But is it only targeted to HTML based frontends? This is a small Proof-Of-Concept how to use JavaScript applications in PowerBuilder. It means not only to call a JavaScript application from PB, but to use it as an high integrated part of a solution.

Architecture

The first step for us is to think about how to run the JavaScript code. The best (but not only) way is to run it in browser. In PowerBuilder it is really easy to put an WebBrowser COM control onto a window and load a HTML document. In this HTML document you can run your Script. Done! Blog post is over, isn’t it?

It is not. There are problematic facts. It is possible to navigate to a HTML document and load the app, but we loose control immediatly. The only way to pass data to the application is in url before loading or by manipulating the source files before loading. The consequence is to reload the app whenever we have to interact. This will not result in a good user experience. Another point is that we cannot get any results of interaction in the JavaScript application to PowerBuilder. So this is not the final solution.

To workaround these problems we have to take a look into the .NET world. There is a solution for these problems. The .NET WebBrowser Control has one method and a property we should notice.

  1. Document.InvokeScript invokes JavaScript from .NET applications
  2. ObjectForScripting could be an .NET-UserControl to receive messages from JavaScript by using window.external.HelloMyDotNetMethod(‘hola!’)

What we have to do is to use the described Control as an wrapped component in PB. This practice is was very well documented by Bruce Armstrong. So we could build a wrapper to interact with JavaScript applications.

JS_UML.pngWith this piece of software it is easy to use JavaScript examples with the mentioned D3.js library in PowerBuilder. For a small Demo I selected this impressive example by Emil Stolarsky (thank you!). I modified it in a way to use DataWindows to load molecules. New items are noticed in PB and inserted to the Controls. The selected item in browser is marked in the corresponding datawindow in PowerBuilder.


JsExample.pngCool, isn’t it? It’s time for some code.


Snippets

The JavaScript example already have methods to add new atoms to the molecule. What we have to do is to call it from PB. We have two methods to realize this. The first is InjectScript. It will create a new Script-Tag in the HTML document including the passed script. The second method is InvokeScript to trigger the new code. Notice that InvokeScript cannot take any arguments. Any data you have to pass, has to be in the injected code. For adding atoms by type (as_type) this code will work.



ole_browser.object.JsInject("window.addAtomFromPB = function(){addAtom('" + as_type + "');}")
ole_browser.object.JsInvoke("addAtomFromPB")

The second part is receiving data from the JavaScript application. To realize this we have to extend the JavaScript code a bit. For example to trigger PB everytime an atom was selected by the user, we have to extend the JavaScript code in this way.



var atomClicked = function (dataPoint) {
         if (dataPoint.symbol === "H")
             return;
         if (atomSelected)
             atomSelected.style("filter", "");
         atomSelected = d3.select(this)
            .select("circle")
             .style("filter", "url(#selectionGlove)");
        // Send to PB what's the selected atom
        if(window.external){
            window.external.JsTrigger("atomClicked->" + atomSelected[0][0].parentNode.__data__.id);
        }
    };

The JsTrigger event is passed from the interop control to PB and can be used in this way.



method = mid(arguments,1,pos(arguments, "->")-1)
args = mid(arguments, len(method)+3)
choose case lower(method)
    case "atomclicked"
        row = dw_nodes.find("id='" + args + "'", 1, dw_nodes.rowCount() +1)
        dw_nodes.setRow(row)
        dw_nodes.selectRow(0, false)
        dw_nodes.selectRow(row, tr
end choose


Conclusion

There is a lot of progress to find new ways visualizing data in web applications with HTML5 and JavaScript. Maybe PowerBuilder can participate in the shown way.


Pitfalls

I really recommend to try this example by your own. But Maybe you will run into trouble loading the web application. The problem is that you have to set the compatibility mode for the application. Solve it by creating a DWORD entry name it like the example exe and set the value to 00002af9 in key HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION.

Keep in mind to install the ComInteropWebBrowser.dll to the gac by using gacutil -i and regasm.

Links

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply