Page 1 of 1

Calling/Accessing a function in one module from another

PostPosted: Fri Jan 29, 2010 9:07 pm
by Chuck.Amata
I am trying to use one module (navigation framework ) to fire a method on a form in another module. I can't seem to find a way to expose or pass the form method I would like to call to this module though.

This is what I've tried:
1. Establish a global module variable in module 1 and a global method in module 1 to set the variable to point at a method in module 2. When a button is pressed in a form within module 1, the onAction form method in module 1 calls the form method (preferred) in module 2 using the global variable.

I've looked at the solution model and the currentController functions and have tried a number of combinations that seem to make sense to pass the required information but to no avail.

Any insight or ideas would be greatly appreciated.

Re: Calling/Accessing a function in one module from another

PostPosted: Fri Jan 29, 2010 9:55 pm
by jgarfield
It sounds like you need to include the "other" module in the navigation framework.

You should be able to do this via the Solution's properties panel, specifically the moduleNames property.

Once you've added the module in, you should just be able to directly access the form method like so

Code: Select all
forms.myFormName.myMethodName()

Re: Calling/Accessing a function in one module from another

PostPosted: Fri Jan 29, 2010 10:00 pm
by ROCLASI
Hi Chuck,

You can call methods in other submodules just fine. But if you want to call a method of a module that your module is a submodule of then you have a challenge.
How is this?
The scope of modules are downwards. In other words a module can only see it's objects and from it's submodules. Not from the modules that itself might be part of (upward scope).
In the following diagram module2 has no knowledge of objects in module1 and the main solution. And module1 doesn't know of the objects in the main solution. They can only 'look' downwards. The main solution does see all objects of both modules.

submodules1.png
submodules1.png (6.73 KiB) Viewed 10664 times


Now in the next diagram modules 1 and 2 are submodules of the main solution. So both the modules see ONLY their own objects. The main solution however does see all objects of both modules.

submodules2.png
submodules2.png (5.85 KiB) Viewed 10662 times


Oddly enough this is only a restriction when you are developing because when Servoy loads your solution with all it's submodules then it considers all the loaded objects as one solution (in memory).
This is also the reason that you could use an eval() to trigger a method in a module higher up to (module) tree.

So how to work around this?

Well you can go the eval() route and call methods using eval("forms.formName.methodName()").
But that is pretty cumbersome.

Another way would be to use a link module that links all modules.
How does this work ?

You create another module in your workspace that has nothing else than modules referenced.
So in this case the linkmodule has solution, module1 and module2 as it's submodule.

linkmodule.png
linkmodule.png (7.78 KiB) Viewed 10663 times


So that's it ?
No, now you reference the linkmodule in all modules (and solution).
So the linkmodule will be the (only) submodule referenced by all other modules.

Now you have a situation where every module is referenced (by way of the linkmodule) to each other.
This way you 'flatten' the scope of the modules and everybody sees everybody.

Next time you add a new module to your solution you only have to reference it in the linkmodule and *BOOM* all other modules see it. :)

Hope this helps.

P.s. the credit for this little trick goes to the STB people.

Re: Calling/Accessing a function in one module from another

PostPosted: Fri Jan 29, 2010 10:21 pm
by Chuck.Amata
Thank you very much for the quick reply. This explains exactly what I was seeing.

Re: Calling/Accessing a function in one module from another

PostPosted: Sat Jan 30, 2010 11:22 am
by pbakker
Well you can go the eval() route and call methods using eval("forms.formName.methodName()").
But that is pretty cumbersome.


eval() == evil!

Not saying you should use this hack to access objects in the parent solutions/modules if you're module structure is not correct, but if you do something like this, do it the correct way:
Code: Select all
forms['formName']['methodName']()


Paul

Re: Calling/Accessing a function in one module from another

PostPosted: Sat Jan 30, 2010 11:52 am
by ROCLASI
Ah, of course. Almost forgot about that.
I stand corrected.

Re: Calling/Accessing a function in one module from another

PostPosted: Thu Feb 04, 2010 3:06 pm
by jcompagner
what is exactly the use of a module if you make circular references and you just point everything to everything?

Then thats nothing more then a (one) big solution, so then you could just have had one big solution.....

in my eyes if you have solution -> module
and you want to let the model call stuff from the solution there is only one good way
The solution should register callback inside the module like:

solution method:
{
global_or_form_method_of_module.registerCallback(globalmethodofsolution or formname/methodname combo)
}

then in the module method when you want to do the callback:
{
forms[solutionCallbackFormName][solutionCallbackMethodName](arguments)
}

this is just like registering listeners on events in java.

Re: Calling/Accessing a function in one module from another

PostPosted: Thu Feb 04, 2010 3:26 pm
by ROCLASI
Hi Johan,

Using modules vs one big solution. When using modules you can reuse code. Simple :)
When loaded servoy considers the modules part of a solution anyway, right ? So it's just a scope issue.

Registering modules like you suggested is a proper way of programming but doing it the STB way you have the benefit of Eclipse helping you with code completion and all that. So it's easier coding.

Re: Calling/Accessing a function in one module from another

PostPosted: Thu Feb 04, 2010 4:36 pm
by jcompagner
ROCLASI wrote:Hi Johan,
Using modules vs one big solution. When using modules you can reuse code. Simple :)
When loaded servoy considers the modules part of a solution anyway, right ? So it's just a scope issue.


But yo can also reuse that one big solution i was talking about, so the reuse nature of code isn't gone.
Because your modules if they are completely intertwined then they are not stand alone modules
Real reuse of modules is this:

You have 3 modules that don't depend on anything.

Module X
Module Y
Module Z

Solution A uses Module X and Y
Solution B uses Module X and Z
Solution C uses Module Y and Z

If you linked X, Y and Z together then its impossible for Solution A to just use X and Z (and the other examples)
Because it has to include all of them And what is the result of that? yes one big module (X , Y and Z together)

For example a module should be able to load standalone as the active solution in serclipse
Without any errors. (it should compile by itself)
But in your case what ever module you take you always load exactly the same set, again an example that it is just one big monolithic thing.

Re: Calling/Accessing a function in one module from another

PostPosted: Fri Feb 05, 2010 2:43 am
by ptalbot
jcompagner wrote:what is exactly the use of a module if you make circular references and you just point everything to everything?

Then thats nothing more then a (one) big solution, so then you could just have had one big solution.....

Quite, but it's also a way to avoid clutter in your solution explorer!
Naming conventions can help but having hundreds of forms at the same level is not always easy to use.

So you can just make modules to organize your 'big solution' in logical pieces of code that works together: like a java package inside one project.
Still everyone can see and call everyone in the same project, and that's valid too I think.
And one developer can be in charge of one module, it doesn't mean that he nevers 'links' to the solution itself.

A different (and probably more efficient) way would be if it was possible to have a hierarchy of forms inside a solution, then the need to use modules for this purpose would be less obvious. But I guess that it is not the kind of feature that will happen before Servoy 6, is it? ;-)

In the solutions we are building right now we have a few modules, like RESOURCES, NAVIGATION, etc... and none of these would easily be reusable as such, but still it is an efficient way to organize our solutions. And yer, we also have other modules like UTILS, FEEDBACK, I18N which are reusable but they are not the majority.

Re: Calling/Accessing a function in one module from another

PostPosted: Fri Feb 05, 2010 11:47 am
by jcompagner
we have something like that in the planning yes, dont know the target
The idea is something like gmail, that you can assign labels to the solution explorer elements, and based on those labels you can have them grouped.

Re: Calling/Accessing a function in one module from another

PostPosted: Thu Aug 04, 2011 6:09 pm
by msedita
I was using the link module technique so that, for example, a module could access media, relations, etc. that exist in the calling solution ( I know that Johan doesn't like this but it works for me). Now, in Servoy 6, this displays an error in developer "a cycle was detected in the build path of project: xxxx". Is there any way to turn this error reporting off?

Re: Calling/Accessing a function in one module from another

PostPosted: Thu Aug 04, 2011 6:24 pm
by jcompagner
Yes we really didn't like it! :)
And i was not alone because this is not even a Servoy generated error but an 3th party one (dltk/eclipse itself)

but you can make it a warning: Preferneces-> Dynamic Languages there you have a build path problem entry

Re: Calling/Accessing a function in one module from another

PostPosted: Thu Aug 18, 2011 5:16 pm
by Harjo
jcompagner wrote:in my eyes if you have solution -> module
and you want to let the model call stuff from the solution there is only one good way
The solution should register callback inside the module like:

solution method:
{
global_or_form_method_of_module.registerCallback(globalmethodofsolution or formname/methodname combo)
}

then in the module method when you want to do the callback:
{
forms[solutionCallbackFormName][solutionCallbackMethodName](arguments)
}

this is just like registering listeners on events in java.


I want to understand this, and do it right.
I have a core-module which does some core stuff, but in that method I MUST set some elements, on a form, which are in my main solution, like this:

Code: Select all
function core_onFind(vEvent) {
     //do some core stuff here, which for this example is not interesting
     //blabla
     //here it get's interesting:
        forms.menu_bar.elements.btn_back.enabled = false
   forms.menu_bar.elements.btn_home.enabled = false
   forms.menu_bar.elements.btn_mail.enabled = false
   forms.menu_bar.elements.btn_forward.enabled = false
}


If I make this module the active one, indeed Servoy gives me warning about all four lines, that It cant find the form: menu_bar, with the warning:
The property menu_bar is undefinde for the type Forms<core_module>

oke, I can fix this warning by doing this:
Code: Select all
function core_onFind(vEvent) {
     //do some core stuff here, which for this example is not interesting
        forms['menu_bar'].elements['btn_back'].enabled = false
   forms['menu_bar'].elements['btn_home'].enabled = false
   forms['menu_bar'].elements['btn_mail'].enabled = false
   forms['menu_bar'].elements['btn_forward'].enabled = false
}


but now, I loose my reference to this form: menu_bar & the 4 different elements, because it is hard-coded, right??
So how do I change this, with your suggestion: registerCallback? I have searched the forum, for this, but found zero results (only this topic, where you mentioned it)

Re: Calling/Accessing a function in one module from another

PostPosted: Fri Aug 19, 2011 3:30 pm
by jcompagner
how do you loose references??

They way you do it is correct, except that you code hard

forms['menu_bar']

that is just weird menu_bar is in your main solution and that code is in a module
Because menu_bar doesn't have to be there if that module is used somewhere else

if you want to do it the right way:

module:
globals.
Code: Select all
registerSomeFindFormThatDoesDefineSpecificApiSoSomeStandardElements(stringFormname) {
  mycallbackform = stringFormname;
}

then in your code or the module:

Code: Select all
function core_onFind(vEvent) {
     //do some core stuff here, which for this example is not interesting
        forms[mycallbackform ].elements['btn_back'].enabled = false
   forms[mycallbackform].elements['btn_home'].enabled = false
   forms[mycallbackform].elements['btn_mail'].enabled = false
   forms[mycallbackform].elements['btn_forward'].enabled = false
}



then in your main solution, something in the onload/onopen:

Code: Select all
globals.registerSomeFindFormThatDoesDefineSpecificApiSoSomeStandardElements('menu_bar')