I trying to use reportContext.setPersistentGlobalVariable to define global variable on the OnFetch Javascript method of the data set like that:
flag = 1;
if(row.Percent>10)
reportContext.setPersistentGlobalVariable("flag", flag);
and to retrieve the variable on the beforeRender method like that:
var flg = reportContext.getPersistentGlobalVariable("flag");
if(flg==1)
reportContext.getDesignHandle().findElement("chartToHide").drop();
but by running the report receiving this error:
org.eclipse.birt.report.engine.api.EngineException: There are errors evaluating script "reportContext.setPersistentGlobalVariable("flag", true);":
Fail to execute script in function __bm_onFetch().
In theory this code should work because the method setPersistentGlobalVariable expects a serializable object:
void setPersistentGlobalVariable( String name, Serializable obj );
but in practice in Rhino scripts it seems it can only handle a String, try this:
var flag = "1";
if(row.Percent>10)
reportContext.setPersistentGlobalVariable("flag", flag);
var flg = reportContext.getPersistentGlobalVariable("flag");
if(flg=="1")
reportContext.getDesignHandle().findElement("chartToHide").drop();
Related
I'll explain the problem I'm solving with an example.
I usually define my own libraries in js this way:
window.myLib = (function () {
var public = {}; // for storing public methods and values
var private = {}; // for storing private methods and values
// Atributes and methods here
return public; // return the public part to be used globally
})();
Now I want to execute an overridable method as a callback from a click event. I would do this:
<input type="checkbox" id="mCheck" onchange="myLib.myMethod()">
Then, in the library I declare the callback "myMethod" that calls another public "overridable" method which I want to use globally, "outside of the library":
//...
public.overridable = function(param){console.log("Override this!");};
public.myMethod = function(){
if(private.condition) // Just to put some logic
public.overridable(private.value);
};
//...
Here comes the problem. If I redefine the "overridable" method like this:
myLib.overridable = function(p){console.log(p)};
Then the callback of the click events keeps firing the original "public.override" which outputs the "Override this!" message instead of the value of the parameter.
How can I override the public method to redefine the callback outside the library??
Thanks in advance.
The snippets you've given are already the correct way to do this. If you're having problems it's because of some detail in your implementation - for example, if you store public.overridable in some variable and call it that way instead of referencing public.overridable each time.
I've put together your snippets in a working example below to show that it works exactly as desired.
window.myLib = (function () {
var public = {}; // for storing public methods and values
var private = {}; // for storing private methods and values
// Atributes and methods here
public.overridable = function(param){console.log("Override this!");};
public.myMethod = function(){
if(private.condition) // Just to put some logic
public.overridable(private.value);
};
private.condition = true;
private.value = "test";
return public; // return the public part to be used globally
})();
myLib.overridable = function(p){console.log(p)};
<input type="checkbox" id="mCheck" onchange="myLib.myMethod()">
You can always permanently modify that public implementation, but I assume what you want is a temporary override. If so, I think your best bet is to redesign the library. If you need to be able to alter behavior dynamically, you need your API to support it.
public.myMethod = function (impl = public.overridable) {
if(private.condition)
impl(private.value)
}
// ...
myLib.myMethod () // uses default behavior
// ...
myLib.myMethod (overridingFunction) // overrides that behavior.
I'm relatively new to JS and i have come across this scenario, where i need to identify if a method defined in a JS object follows a particular interface.
Let me explain with the help of an example:
let logger1 = {
log: function(message, meta){
//logging functionality
}
};
let logger2 = {
log: function(level, message, meta){
//logging functionality
}
}
There are 2 logger objects (logger1 or logger2), which has its own logging functionalities. They can get passed from the client to a library, that the client consumes. Library expects the log method to be of a particular interface, which is already mentioned in the library documentation. Inside the library, how would we verify if the logger object passed in has the 'log' method that matches the interface, the library is expecting ?
let Library = function(logger){
//Here I can verify if the 'log' function is defined. But how do i make sure the log
//function matches the interface that the library is expecting ?
//Let's say the interface that the library is expecting is function(level,message,meta),
//which is satisfied only by logger2.
if(logger && typeof(logger.log) === 'function'){
this.logger = logger;
}
else{
this.logger = console;
}
}
let lib1 = new Library(logger1);
let lib2 = new Library(logger2);
You cannot really. A Javascript function can omit parameters that it doesn't use, so the function may have fewer parameters and still be compatible. The function may define more parameters which will become undefined if not passed, and hence still be compatible. It may internally use arguments and hence not define any parameters, and still be compatible. It may name any of its parameters any way it wants, and still be compatible, so even inspecting the parameter names won't help you at all.
The only thing you can do it use something like Typescript and add compile-time checks.
Hmm, tricky one.
We would just determine the interface first and then the implementation. In this case we would code logger1 to have the signature: ( message, meta ) and logger2 ( message, meta, level ) .
That way we can call either function with eg. ( 'test', 'extra', 1 ) and logger1 will just ignore the level argument.
If you work with a system that has to juggle alot of different argumented versions, it might be better to just use an object as the only argument every time: function( config ) and just add extra properties when needed.
That way you can also force the interface to stay the same while also being extendable in some way.
There is a property length property for function which gives number of arguments it holds
Example:
let logger1 = {
log: function(message, meta){
//logging functionality
}
};
console.log(logger1.log.length); // 2
let logger2 = {
log: function(level, message, meta){
//logging functionality
}
}
console.log(logger2.log.length); // 3
I want to parse an object into client-side javascript through Jade. Normally this would work:
script var object = JSON.parse(#{JSON.stringify(object)});
but my object is circular and I need to do this
script var object = CircularJSON.parse(#{CircularJSON.stringify(object)});
but it throws the error
Cannot call method 'stringify' of undefined
which I guess is because Jade doesn't recognise my CircularJSON method.
Any way to make it?
It could be required and passed in the locals
response.render("index.jade", {CircularJSON : require('circular-json')});
Or it could be defined as a function in the scope of jade
- var CircularJSON = function(e,t){function l(e,t,o){var u=[],...//whole function
script var player = CircularJSON.parse('!{CircularJSON.stringify(player)}');
If I have a javascript object, I would normally interact with the object and its methods like this:
var obj = someObject.getInstance();
var result = obj.someMethod();
where someMethod is defined like this:
someObject.prototype.someOtherMethod = function() { //do stuff };
someObject.prototype.someMethod = function(foo) { this.someOtherMethod(); };
However, I am getting an error when I want to call someMethod in Ruby via ExecJS:
context = ExecJS.compile(# the javascript file)
context.call('someObject.getInstance().someMethod')
# Gives a TypeError where Object has no method 'someOtherMethod'
On the other hand, functions that are defined in the javascript module are working fine:
someFunction = function() { // do stuff };
# in Ruby
context.call('someFunction') # does stuff
Can ExecJS handle Javascript objects and their methods, or am I only able to call functions with it?
With regards to the specific application, I am looking into https://github.com/joenoon/libphonenumber-execjs, but the parse function in Libphonenumber does not work for the above reason.
Discovered the answer through some experimentation. I managed to get the desired functionality by using context.exec() instead of call.
js = <<JS
var jsObj = someObject.getInstance();
var res = jsObj.someMethod();
return res;
JS
context.exec(js);
However, if your method returns a Javascript object, you have to serialize it first or otherwise parse the results so that it can be returned by ExecJS into a suitable Ruby object.
I'm using following code in JScript (WSH) to connect to local registry using WMI: var registry = GetObject('winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\default:StdRegProv'); and that works.
Then I have to determine if I'm allowed to delete key without really trying to delete it (e.g. perform a non-destructive check). I looked over docs and found that I need StdRegProv.CheckAccess() method. Problem is that CheckAccess returns result as out argument and I could not find VBScript's ByRef equivalent in JScript.
Somewhere in the Internet I've found that using SWbemServices.ExecMethod would help somehow, but I hadn't figured out how can I use that yet.
Could anyone provide me with code sample in JScript performing function call with argument passed by reference?
Heh, got it working.
For anyone who will need it, CheckAccess invokation in JScript looks something like this:
function CheckAccess(defKey, subkeyName, required) {
var providerName = "StdRegProv";
var funcName = "CheckAccess";
// connect to WMI
var services = GetObject("winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\default");
// get provider
var registry = services.Get(providerName);
var in_params = registry.Methods_(funcName).InParameters.SpawnInstance_();
in_params.hDefKey = defKey;
in_params.sSubKeyName = subkeyName;
in_params.uRequired = required;
var outParams = services.ExecMethod(providerName, funcName, inParams);
return Boolean(outParams.bGranted);
};