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

Preserve Component State Independent of Location #2135

Closed
yossicadaner opened this issue Apr 25, 2018 · 10 comments
Closed

Preserve Component State Independent of Location #2135

yossicadaner opened this issue Apr 25, 2018 · 10 comments
Labels
Type: Question For issues that are purely questions about Mithril, not necessarily bug reports or suggestions

Comments

@yossicadaner
Copy link

BS"D

Is it possible to preserve a component's state even it gets moved to another listing of children?
Say I have

  • Left Sidebar
    • Chat
      and I move Chat to Right Sidebar
  • Right Sidebar
    • Chat

I know I could technically store and reload the state values, but it is possible to do this in another way, say by just providing a common key?

@yossicadaner yossicadaner changed the title Preserver Component State Independent of Location Preserve Component State Independent of Location Apr 25, 2018
@spacejack
Copy link
Contributor

@yossicadaner I don't believe you can, at least not without an undesirable amount of hackery.

You can preserve the component instance if it moves within a list of siblings (in an array, using keys) but I don't think you can if it moves arbitrarily across the dom tree.

I think your best bet is to externalize its state.

@pygy
Copy link
Member

pygy commented Apr 25, 2018

What you are trying to achieve is not supported. It could be achieved for a fixed version of Mithril, using a unholy amount of hackery, but any such hack could be broken by a Mithril point release that tweaks the diff/patch algo. So I wouldn't recommend it, at all.

As @spacejack suggested, you can achieve what you want by externalizing your state to a common object or stream.

const chatState = {
   log: [],
   currentDraft: "",
   cursorPosition: 0
}

const Chat = {
    view: () => m(".chat", 
        chatState.log.map(msg => m(".", msg.author, ": ", msg.text)),
        m("input", {
            oninput() {
                // save the current draft and cursor position
                // submit on "enter"
            },
            oncreate(vnode) {
                // set the cursor position
            }
     )
}

@orbitbot
Copy link
Member

I've tried a simplistic version of moving components around in designated sections for a drag and drop implementation, but it ended up in a very weird state where the data layer indicating what should be drawn where was coherent but Mithril just didn't populate the dom properly and wouldn't correct itself. So wouldn't advise trying, really.

If maintaining the component state is really important for whatever reason, you could probably achieve the same with CSS changes while keeping the DOM tree more or less intact.

@yossicadaner
Copy link
Author

yossicadaner commented Apr 25, 2018

It could be achieved for a fixed version of Mithril, using a unholy amount of hackery, but any such hack could be broken by a Mithril point release that tweaks the diff/patch algo. So I wouldn't recommend it, at all.

Possibly there are simpler methods of doing this. For example, if mithril provided control over initializing the .dom attribute/ the dom node or from an existing 'vnode'?

@pygy
Copy link
Member

pygy commented Apr 25, 2018

In order to do that, we'd have to provide expose the nextSibling (and optionally the parent node, but that can be obtained from client code already by passing it as an attr)...

It may be something we'll do at some point (rather than domSize), in order to get rid of fragments (DOM fragments, used under the hood, not m.fragment() vnodes).

I don't want to commit to it though, or to ensuring that patterns that rely on it keep on working when we update the diff code.

@leeoniya
Copy link
Contributor

some food for thought...

domvm achieves this by offering imperative component instantiation via createView() and allowing these component instances to be injected into any other domvm tree via injectView() vnodes. this way it does not have to track keys globally.

https://jsfiddle.net/phtd6vqb/

@pygy
Copy link
Member

pygy commented Apr 25, 2018

@leeoniya That's neat! I'll have to dig into domvm at some point.

I've tried to have it move back and forth between the "left" and "right" panes, and it starts in the top one, then blinks below... Am I doing something wrong?

https://jsfiddle.net/dvkm3qzm/

@leeoniya
Copy link
Contributor

heh, no it should work, time to dig! :D

@leeoniya
Copy link
Contributor

fixed!

@dead-claudia dead-claudia added the Type: Question For issues that are purely questions about Mithril, not necessarily bug reports or suggestions label Oct 28, 2018
@barneycarroll
Copy link
Member

Mithril Machine Tools has a mechanism for this via the Mobile > Unit composite component. The Mobile component has a view which exposes the Unit component: Unit components identified with the same key attribute can be rendered anywhere within their Mobile context and retain state and DOM.

Here's an example of the 'mobile' chat box.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Question For issues that are purely questions about Mithril, not necessarily bug reports or suggestions
Projects
None yet
Development

No branches or pull requests

7 participants