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

Mithril is nuking away jQuery calendar #463

Closed
kvanbere opened this issue Feb 18, 2015 · 23 comments
Closed

Mithril is nuking away jQuery calendar #463

kvanbere opened this issue Feb 18, 2015 · 23 comments
Labels
Type: Bug For bugs and any other unexpected breakage

Comments

@kvanbere
Copy link

jQuery inserts a calendar at the top level of the page (last child of body tag) to show and bring to focus above everything else for picking dates. Mithril doesn't know about this calendar. Sometimes when an element is added to the end of the page via mithril, this calendar will get killed and jQuery will go into a buggy state where the popup calendars stop working completely.

I right clicked the calendar, break on -> node removal and it came to this line of code when the bug happened:
https://github.com/lhorie/mithril.js/blob/next/mithril.js#L194

@kvanbere
Copy link
Author

Okay, so we found a workaround for this.

To make sure mithril never pushes and pops from the same scope that the calendar is inserted (body) we wrapped the whole page inside a useless div which bodge-patched the bug on our side.

body
-- controls
-- controls
-- ...
-- calendar

===>

body
-- div
---- controls
---- controls
---- ...
-- calendar

@gilbert
Copy link
Contributor

gilbert commented Feb 26, 2015

I wouldn't call it bodge-patch. It's expected behavior that Mithril clears out the entire contents of the element you assign it to.

@kvanbere
Copy link
Author

The calendar is added in config (so it's after mithril has been initialized). It's expected that 3rd party integration will work, especially with jQuery.

Mithril should not touch nodes that don't belong to it ...

@barneycarroll
Copy link
Member

@kvanberendonck can you put up a jsFiddle? The suggested usage of config to house 3rd party DOM plugins is to create a Mithril DOM node specifically for that plugin and use config's el argument to manipulate the DOM inside that node. What you're talking about should be trivial using this method. Manipulating that node's parents or siblings is effectively 3rd party code touching nodes that belong to Mithril, which should be expected to break.

@kvanbere
Copy link
Author

Looks like I didn't mention it in OP, but we're using config here in combination with isInitialised too. The issue is jQuery does stuff to DOM outside the config scope and mithril blows it up.

... I can make a fiddle for this but not soon

@kharin
Copy link

kharin commented Mar 2, 2015

This is not a bug, even more so if jQ is doing it outside of Mithril's scope. Also, rendering into a container div is an established practice be it Mithril or React, since by rendering into body you're breaking your users' browser extentions which also tend to append stuff to body.

@kvanbere
Copy link
Author

kvanbere commented Mar 2, 2015

The way you just put it, it still sounds like a bug to me.

Breaking browser plugins and arguably the worlds most commonly used js library is a compelling behaviour to fix.

@barneycarroll
Copy link
Member

But you know how you've broken it and how to fix it, right?

@kvanbere
Copy link
Author

kvanbere commented Mar 3, 2015

I'll be honest, my team would have never figured it out. I literally had to debug the guts of mithril to know what was going on, and I wasted a good day or two doing so.

It's also seemingly random and manifests itself in strange places, sometimes and sometimes not. It's also not documented anywhere.

If nobody is going to fix this, put a note in the documentation somewhere justifying why it's intended behaviour that mithril is mixing up objects and destroying DOM "sometimes".

@barneycarroll
Copy link
Member

You said it yourself: you were using config to manipulate DOM structure
outside the config scope. That's somewhat obviously 'out of scope' by your
own admission. The documentation says "This special parameter allows you to
call methods on the DOM element after it gets created." You say "my team
would have never figured it out", but you did, 45 minutes after your
original post.

Is it a case of the documentation not being clear enough? It might be worth
adding something to the effect of "A config function and it's arguments
are specifically associated with the DOM elements they are bound to. If you
want access to DOM elements in an external scope, use those elements'
config attributes."

On Tuesday, 3 March 2015, Kyle Van Berendonck notifications@github.com
wrote:

I'll be honest, my team would have never figured it out. I literally had
to debug the guts of mithril to know what was going on, and I wasted a good
day or two doing so.

It's also seemingly random and manifests itself in strange places,
sometimes and sometimes not. It's also not documented anywhere.


Reply to this email directly or view it on GitHub
#463 (comment).

@kvanbere
Copy link
Author

kvanbere commented Mar 3, 2015

You can tailor it like it sounds I was doing something outrageous, but we know that this breaks core functionality of jQuery -- one of the worlds most largely used javascript libraries -- and as already mentioned browser plugins, etc.

And FWIW I didn't post this bug until I had already spent a lot of time debugging and was about to give up trying to understand what is actually happening with so many moving parts ..

@barneycarroll
Copy link
Member

It's not outrageous, it's just misusing the function. When you use it according to the documentation, it works. Or doesn't it?

@kvanbere
Copy link
Author

kvanbere commented Mar 3, 2015

You classify this then as misusing config:

var myconfig = function(dom, init) {
    if (init) return;
    $(dom).datepicker();
}

Or, this also, as it will implicitly insert resize handles:

var myconfig = function(dom, init) {
    if (init) return;
    $(dom).resizeable();
}

Yes, that's outrageous and completely intuitive.

@barneycarroll
Copy link
Member

The misuse I was referring to was using config to manipulate elements outside of scope. Are you saying you're still suffering from unexpected behaviour when using it as above? I've knocked up a fiddle to try and find bugs with the plugins you mention but I couldn't find any. Could you fork it to reproduce them, perhaps?

@kvanbere
Copy link
Author

kvanbere commented Mar 3, 2015

To reproduce it, the app actually has to move quite dynamically and cause mithril to touch a lot of DOM. In an application of several hundred dynamic data entry screens with rows and fields that appear and disappear, it was only reproducible in one or two places.

I made a bogus one with lots of dynamic redraws on it and all types of random broken crap to see if I could reproduce it in a fiddle, but I can't ( http://jsfiddle.net/43r7jtj6/ ).

I wonder if the configuration of the calendar makes a difference.

@lhorie
Copy link
Member

lhorie commented Mar 3, 2015

@kvanberendonck I feel like this should be fixable, since Mithril keeps a record of managed DOM elements in the cached tree and it should be able to tell that a DOM element is not managed internally. Were you using <body> as a rendering target (i.e. m.route(document.body, ...) or generating it with m("body")?

@lhorie lhorie added the Status: Needs test case For pull requests that lack one or more test cases for the feature or behavior in question label Mar 3, 2015
@kvanbere
Copy link
Author

kvanbere commented Mar 4, 2015

m.route(document.body, ...) is how mithril is setup.

If I undo the patch which fixes the issue and dump out mithrils guts with the debugger maybe it will give an idea of how to build a test case.

@lhorie
Copy link
Member

lhorie commented Mar 4, 2015

Ok, thanks. I'll look into it

@ariutta
Copy link

ariutta commented Mar 12, 2015

Here's a simplified example of a similar issue I ran into and how I solved it. Mithril creates a header, body and footer, and another library adds a sub-component to the body. Mithril uses routes to change the header and footer when the user clicks the link in the footer.

Once it's created, the sub-component should not be re-rendered, and any event emitters and listeners need to continue working, even if the route changes. My example works -- the time doesn't change and clicking the input box brings up an alert -- but I don't know whether this is a good way to do this.

@barneycarroll
Copy link
Member

@ariutta that's a really interesting and legitimate case in point — ironically I think the compoments branch would have solved this issue until a recent fix in response to a user complaining that reinstating the same component on route change was unexpected behaviour.

@lhorie
Copy link
Member

lhorie commented Mar 14, 2015

minimal reproducible test case: http://jsfiddle.net/yhLwmqfx/

@lhorie lhorie removed the Status: Needs test case For pull requests that lack one or more test cases for the feature or behavior in question label Mar 14, 2015
@lhorie
Copy link
Member

lhorie commented Mar 14, 2015

Fixed in origin/next. This will be release in v0.1.31 (or 0.2 if there's a version bump)

@lhorie lhorie closed this as completed Mar 14, 2015
@lhorie lhorie added the Type: Bug For bugs and any other unexpected breakage label Mar 14, 2015
@kvanbere
Copy link
Author

Thanks Leo! Nice find!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug For bugs and any other unexpected breakage
Projects
None yet
Development

No branches or pull requests

6 participants