S
SolidJS2w ago
sh03

Pass a named function callback to an old JS library

I have a library that accepts a data-callback="someFn" attribute in one of the elements. Is there a way in SolidJS to create this function at the component level and pass it down to that attribute?
49 Replies
mdynnl
mdynnl2w ago
data-callback="someFn" is just a simple attribute which can't hold anything except strings, so that library must have some way of defining a function with that name e.g. lib.registerCallback('someFn', () => {})
sh03
sh03OP2w ago
Not really, as most old JS libraries do, the someFn is expected to exist in the global JS scope.
mdynnl
mdynnl2w ago
some way of defining a function with that name
that was provided as an example but the point still stands and i'm not sure what the question really is then because that depends entirely on the library this is valid in soild as it is data-callback="someFn"
sh03
sh03OP2w ago
The question is how to define a global scope JS function that can be called like that and still only exist at the component level. ChatGPT gave me this as starting point:
export const Comp = () => {
function someFn() {
// ...
}

onMount(() => {
(window as any).__someFn = someFn;
});

onCleanup(() => {
delete (window as any).__someFn;
});
export const Comp = () => {
function someFn() {
// ...
}

onMount(() => {
(window as any).__someFn = someFn;
});

onCleanup(() => {
delete (window as any).__someFn;
});
bigmistqke
bigmistqke2w ago
The question is how to define a global scope JS function that can be called like that and still only exist at the component level.
that is a contradiction
TaQuanMinhLong
:Worry_Think: window.fn = ... :ryanshades: I actually use this with XLSX lib
sh03
sh03OP2w ago
It needs to temporarily exist in the global scope as long as the component is on the page. Once it's unmounted it can be removed. No contradiction 😅
bigmistqke
bigmistqke2w ago
you could do something like your snippet, but you will have to do some type of reference counting too (because if you have 2 of those components and 1 cleans up you don't want that global function to be undefined suddenly)
TaQuanMinhLong
Since vite doesn't know how to bundle XLSX, and end up with bloated js External script is even lighter
bigmistqke
bigmistqke2w ago
and you will have to be careful not to have conflicts too
sh03
sh03OP2w ago
Yeah I can just generate a random hash to append to the that global fn name. That's not an issue.
mdynnl
mdynnl2w ago
what is that library you've spoken of anyway?
sh03
sh03OP2w ago
Not gonna mention the library because I already know people will freak out about the fact that there are alternatives for that library in solid but then I have to explain how they don't fit my needs. 😬
TaQuanMinhLong
:confusednick:
bigmistqke
bigmistqke2w ago
maybe what if you would add it to the dom-element's 'callback'-property and do this.callback?
mdynnl
mdynnl2w ago
yeah, something like that
sh03
sh03OP2w ago
it's google sign in
mdynnl
mdynnl2w ago
i'm not sure how this came off. did you really experience this here?
TaQuanMinhLong
But what's the goal tho, I've never needed something similar to this data-callback
sh03
sh03OP2w ago
I've been around forums and survived on SO for 17 years. That built up that assumption.
TaQuanMinhLong
:_Worry_Universe:
sh03
sh03OP2w ago
This is much nicer community than I've ever experienced so I'm kinda thrown off by that
bigmistqke
bigmistqke2w ago
ye it's cozy here! and people up for cursed experiments but to circle back to your question: i think this is valid way of doing it
sh03
sh03OP2w ago
I thought I had it but now no errors and no components show up 😂
import { onCleanup, onMount } from "solid-js";

type Props = {
clientId: string;
};

export default (props: Props) => {
function onGoogleSignIn(googleUser: any) {
var profile = googleUser.getBasicProfile();
console.log("ID: " + profile.getId());
console.log("Name: " + profile.getName());
}

onMount(() => {
// TODO: generate random hash to append to function name
(window as any).__onGoogleSignIn = onGoogleSignIn;
});

onCleanup(() => {
delete (window as any).__onGoogleSignIn;
});

return (
<>
<div>
<div
id="g_id_onload"
data-client_id={props.clientId}
data-callback="__onGoogleSignIn"
></div>
<div class="g_id_signin" data-type="standard"></div>
</div>
<script src="https://accounts.google.com/gsi/client" async defer></script>
</>
);
};
import { onCleanup, onMount } from "solid-js";

type Props = {
clientId: string;
};

export default (props: Props) => {
function onGoogleSignIn(googleUser: any) {
var profile = googleUser.getBasicProfile();
console.log("ID: " + profile.getId());
console.log("Name: " + profile.getName());
}

onMount(() => {
// TODO: generate random hash to append to function name
(window as any).__onGoogleSignIn = onGoogleSignIn;
});

onCleanup(() => {
delete (window as any).__onGoogleSignIn;
});

return (
<>
<div>
<div
id="g_id_onload"
data-client_id={props.clientId}
data-callback="__onGoogleSignIn"
></div>
<div class="g_id_signin" data-type="standard"></div>
</div>
<script src="https://accounts.google.com/gsi/client" async defer></script>
</>
);
};
and then:
import { clientOnly } from "@solidjs/start";

export const GoogleSignIn = clientOnly(() => import("./component"));
import { clientOnly } from "@solidjs/start";

export const GoogleSignIn = clientOnly(() => import("./component"));
Is my currently "not working" solution
bigmistqke
bigmistqke2w ago
mb <script src="https://accounts.google.com/gsi/client" async defer></script>? not sure if that would work
TaQuanMinhLong
:Worry_Think:
sh03
sh03OP2w ago
Yeah it stopped working as soon as I wrapped the component in a clientOnly But that's required for accessing window no?
bigmistqke
bigmistqke2w ago
i think onMount will not run on server all effects run on client afaik
sh03
sh03OP2w ago
npm
google-oauth-gsi
A user-friendly API for GIS SDK, using the new Google Identity Services SDK 🚀. Latest version: 4.0.1, last published: 9 months ago. Start using google-oauth-gsi in your project by running npm i google-oauth-gsi. There are no other projects in the npm registry using google-oauth-gsi.
sh03
sh03OP2w ago
Although 800 downloads is low 😅
TaQuanMinhLong
:Worry_Think:
sh03
sh03OP2w ago
Or maybe it's high considering only insane people would do this
bigmistqke
bigmistqke2w ago
removing clientOnly didn't work?
sh03
sh03OP2w ago
Moving the script outside didn't work. I can try removing clientOnly entirely, let's see...
TaQuanMinhLong
How do Google packages work under the hood? They make an abstraction layer and fire an API call for it? :Worry_Think:
sh03
sh03OP2w ago
Yeah no, it doesn't work without clientOnly . The dev server just exists with this error
No description
sh03
sh03OP2w ago
Weird that it errors out on the unmount
bigmistqke
bigmistqke2w ago
move the onCleanup in onMount?
sh03
sh03OP2w ago
You mean like this:
onMount(() => {
// TODO: generate random hash to append to function name
(window as any).__onGoogleSignIn = onGoogleSignIn;

onCleanup(() => {
delete (window as any).__onGoogleSignIn;
});
});
onMount(() => {
// TODO: generate random hash to append to function name
(window as any).__onGoogleSignIn = onGoogleSignIn;

onCleanup(() => {
delete (window as any).__onGoogleSignIn;
});
});
?
bigmistqke
bigmistqke2w ago
yup
sh03
sh03OP2w ago
Ok seems to work as the one tap login thing appears But then I'm back to "The value of 'callback' is not a function. Configuration ignored."
mdynnl
mdynnl2w ago
you can also do if (!isServer) { ... } instead of onMount
sh03
sh03OP2w ago
I think I know what's up The imported script is run before the onMount Maybe if I create the script tag in the onMount that's better
bigmistqke
bigmistqke2w ago
if it's a component you will only use in your own project you could also just yolo it and do
if(!isServer){
windows.__onGoogleSignIn = ...
}
export default () => {
return <div data-callback="__onGoogleSignIn" />
}
if(!isServer){
windows.__onGoogleSignIn = ...
}
export default () => {
return <div data-callback="__onGoogleSignIn" />
}
sh03
sh03OP2w ago
Yeah that seems to work I keep forgetting that in solid there's no restriction to be in a component to do most things Like I'm assuming I can call an async solid start function like const authenticateWithGoogle = action(async () => { ... }) outside of a component, right?
bigmistqke
bigmistqke2w ago
not 100% sure myself not a solid start expert
mdynnl
mdynnl2w ago
usually, no but you can turn it into one using useAction inside a component which must be inside a route context so, yes 😆
sh03
sh03OP2w ago
Thank you all very much ❤️
bigmistqke
bigmistqke2w ago
you are very welcome!
Want results from more Discord servers?
Add your server