Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recommended method of building portable contained reactive components? #83

Open
hsnoil opened this issue Jan 23, 2024 · 6 comments
Open

Comments

@hsnoil
Copy link

hsnoil commented Jan 23, 2024

Many frameworks have methods of building portable components before the webcomponent spec, what is the recommended way to do this with Mikado?

What I came up with is something like this (though it feels like I am hacking around the foreach and I'd have to do an app.render(data) on every change, is there a better way?):

index.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Mikado</title>
    <script type="module" src="js/main.js" async></script>
</head>
<body><!----></body>
</html>

main.js

import Mikado, {register} from "../node_modules/mikado/dist/module-debug/mikado.js";
import {route} from "../node_modules/mikado/dist/module-debug/event.js";
import tpl_app from "../compiled/app.js";
import tpl_form from "../compiled/form.js";
import tpl_textbox from "../compiled/textbox.js";

register(tpl_form)
register(tpl_textbox)

const app = new Mikado(tpl_app, {
    mount: document.body,
    recycle: true,
    cache: true
});

const state = {
    form: { id:"form", items:{ username: 'cookie' } },
    setState: function (s,k,v) {
        s[k] = v
    }
}

const data = {}
route("testrun", function(target, event){
console.log("DATA",data,state)
const id = target.dataset.id
const fn = target.dataset.fn
console.log(id,fn,target)

state[id][fn](state[id]);

});
app.render(data,state);

template/app.html

<main>
  <header>Test Form</header>
  <section include="compiled/form" foreach="state.form"></section>
</main>

template/form.html

<form>
    <script>{{@
        state.setState(data,'items', {
            username: { type:"text", title:"Username", name:"user", value:((data||{}).items||{}).username },
            password: { type:"password", title:"Password", name:"pass", value:'' }
        });
        state.setState(data,'fn_submit', function(data) {
            console.log("got", data)
        });
    }}</script>
    <section include="compiled/textbox" foreach="data.items.username"></section>
    <section include="compiled/textbox" foreach="data.items.password"></section>
<div click="testrun" data-id="{{data.id}}" data-fn="fn_submit">button</div>
</form>

template/textbox.html

<span>
{{@
         state.setState(data,'value', (data||{}).value )
}}
    <input type="{{?data.type}}" placeholder="{{?data.title}}" name="{{?data.name}}" value="{{?data.value}}">
</span>
@john5000
Copy link

It appears that Mikado mounts listeners on the window object (the root of all listeners) and so events won't know what component to go do. (See src/event.js:391).

Mikado needs to be changed to mount the listener on the base of each component.

@ts-thomas
Copy link
Collaborator

ts-thomas commented Jan 24, 2024

I don't understand what you are trying to do. For reactive approach Mikado gives you 2 possibilities: 1. using reactive property notation within template expression and also optionally 2. using observable array. For web components there is explanation in the Readme. None of them was used.

Can you explain me what is your goal? You can give me some example of how the final result should look like but without giving the imlementation, just the result is important to me. I don't understand your example above, also I'm pretty sure that this could be solved better, when I'm understand what you need.

@ts-thomas
Copy link
Collaborator

Mikado needs to be changed to mount the listener on the base of each component.
I don't know what you exactly mean with "component". When it is shadow DOM component, then this makes sense to me. But that is just one usage scenario. When using non-shadow DOM components it can't, because it needs a global event delegation solution and binding routing to every template doesn't provide this. It isn't needed to use the event delegation, when you need non-global event capturing then just assign a native listener. This can also be done within custom callbacks.

@ts-thomas
Copy link
Collaborator

ts-thomas commented Jan 24, 2024

@john5000 I will add a new feature binding delegation listeners to the shadow root when used.

@ts-thomas
Copy link
Collaborator

ts-thomas commented Jan 24, 2024

@hsnoil Probably I understand your example, the confusing part is the use of state.setState which completely should not be there. Why you use it?

@hsnoil
Copy link
Author

hsnoil commented Jan 25, 2024

@ts-thomas I know one can just do data.items = but my goal in long term was to do some auto structuring of what is passed to the values and get more data about where it is, thus the use of a function. But I can see how in this minimum example it looks weird, sorry about that

Also, a side note did you see my other post about how things come out as compiled/textbox instead of textbox for the naming? or should I open a new issue for it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants