Meteor Small Hints #1: Execute a function by name which works on client and server
Calling a function by name in Meteor gave me at the beginning some headache concerning the passed context.
I.e. the helper function which manages the function by name execution, must work on the client, as well as server side, due to the fact that a Meteor method may be configured for both sides.
I.e. the helper function which manages the function by name execution, must work on the client, as well as server side, due to the fact that a Meteor method may be configured for both sides.
In my code I have a configuration object which has as an attribute initfunc, which defines a function which should be called in an initalization process.
{
name: 'SiteName'
type: 'singleton'
singletonSpace: 'sitename'
initfunc: 'Extension.getSiteName'
}
The initfunc will be used in the following method call, e.g.
getDefaultFeatureValue: (name) ->
configFeature = this.getConfigFeature name
if configFeature.initfunc != undefined
Plattform.executeFunctionByName configFeature.initfunc window
else
configFeature.init
As one can see I pass to the executeFunctionByName the function name, as well as the global window variable as context. The execute function is looking like that.
executeFunctionByName : (functionName, context) ->
args = Array::slice.call(arguments, 2)
namespaces = functionName.split('.')
func = namespaces.pop()
i = 0
while i < namespaces.length
context = context[namespaces[i]]
i++
value = context[func].apply context, args
return value
Now this worked fine to the point where getDefaultFeatureValue was called from a server method as well.
The problem was that the global variable window is only defined on the browser. The variable isn’t available in the NodeJS server part and you have to use the global variable.
Plattform.executeFunctionByName configFeature.initfunc global
I extended the code, so that the caller may not provide the context (in case he wants to call the function in a global context). The function itself will look then for a global context (the typeof code part in the beginning)
executeFunctionByName : (functionName, context) ->
if typeof context == 'undefined'
if typeof global == 'undefined'
context = window
else
context = global
args = Array::slice.call(arguments, 2)
namespaces = functionName.split('.')
func = namespaces.pop()
i = 0
while i < namespaces.length
context = context[namespaces[i]]
i++
value = context[func].apply context, args
return value
The final method was simplified not having to provide the global context.
getDefaultFeatureValue: (name) ->
configFeature = this.getConfigFeature name
if configFeature.initfunc != undefined
Plattform.executeFunctionByName configFeature.initfunc
else
configFeature.init
comments powered by Disqus