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:
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.
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.
[attachment=2]submodules1.png[/attachment]
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.
[attachment=1]submodules2.png[/attachment]
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.
[attachment=0]linkmodule.png[/attachment]
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.
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:
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
}
this is just like registering listeners on events in java.
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.
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.
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.
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…
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.
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.
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?
jcompagner:
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
}
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:
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:
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)
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
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: