In HTML you could just do
<script>
window.myCallback = (e) => console.log("change", e)
</script>
<select onchange="mycallback">...</select>
with alliance UI components as tags
{% component "@alliancesoftware/ui" "Select" %}...
there's no way to do that easily currently because it's rendering a component under the hood. Soon some of these components will just render HTML directly and apply the styles, but even then there's still a use case for passing it direct to components because of things like comboboxes etc that will remain in React.
Achieving this isn't too hard, question is exact API. As a proof of concept:
from alliance_platform.codegen.typescript import Identifier
from alliance_platform.frontend.bundler.ssr import SSRSerializerContext
from alliance_platform.frontend.prop_handlers import CodeGeneratorNode
from alliance_platform.frontend.prop_handlers import ComponentProp
from alliance_platform.frontend.templatetags.react import ComponentSourceCodeGenerator
from allianceutils.template import parse_tag_arguments
from allianceutils.template import resolve
from django import template
register = template.Library()
class CallbackProp(ComponentProp, CodeGeneratorNode):
def __init__(
self,
callback_name: str,
node,
context,
):
self.callback_name = callback_name
super().__init__(callback_name, node, context)
def get_tag(self):
return "Primitive"
def generate_code(self, generator: ComponentSourceCodeGenerator):
return Identifier(self.callback_name)
def get_representation(self, ssr_cache: SSRSerializerContext):
return self.callback_name
class CallbackNode(template.Node):
def __init__(self, callback_name: str, target_var: str):
self.callback_name = callback_name
self.target_var = target_var
super().__init__()
def render(self, context):
context[self.target_var] = CallbackProp(resolve(self.callback_name, context), self, context)
return ""
@register.tag("js_callback")
def js_callback(parser: template.base.Parser, token: template.base.Token):
tag_name = token.split_contents()[0]
args, kwargs, target_var = parse_tag_arguments(parser, token, supports_as=True)
if len(args) != 1:
raise template.TemplateSyntaxError(
f"'{tag_name}' must receive a single argument which is the name of the callback"
)
if target_var is None:
raise template.TemplateSyntaxError(
f"You must use {{% {tag_name} ... as ... %}} syntax to specify a target variable name for the callback prop"
)
return CallbackNode(args[0], target_var=target_var)
Then usage can be
<script>
window.myCustomOnSelectionChange = (selection) => console.log("selection", selection)
</script>
{% js_callback "myCustomOnSelectionChange" as onchange %}
then you can just pass onchange as a prop to any component and it will receive it as a JS identifier.
{% component "@alliancesoftware/ui" "Select" onSelectionChange=onchange %}...{% endcomponent %}
js_callback is probably a bit misleading as it really is just any JS identifier - so maybe just js_identifier
In HTML you could just do
with alliance UI components as tags
there's no way to do that easily currently because it's rendering a component under the hood. Soon some of these components will just render HTML directly and apply the styles, but even then there's still a use case for passing it direct to components because of things like comboboxes etc that will remain in React.
Achieving this isn't too hard, question is exact API. As a proof of concept:
Then usage can be
then you can just pass
onchangeas a prop to any component and it will receive it as a JS identifier.js_callbackis probably a bit misleading as it really is just any JS identifier - so maybe justjs_identifier