-
Notifications
You must be signed in to change notification settings - Fork 45
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
Event ~key changing does not cause event handler closure to update #97
Comments
Hmm, I have an idea how that could happen but I'm not sure it would, do you have a minimal example of it?
You don't need to patch it, you can just write your own version of that function in your own module, I left it all very open on purpose. :-)
Yeah I figured that might be where it is, but I thought I had it pretty well tested on that
I concur, it should indeed be properly removed, that's what the whole comparison is for. Overall though, if the 'shape' the attributes/properties changes for a given tree branch then you generally want to use But still, it should work... If you can reduce it to a minimal example that would be awesome! I'll leave this open for now to see if I can come up with a test-case myself when I get time, but looking at the code right now I really have no idea where it would be faulting, it's pretty straight-forward and I've not experienced this at my job where I use bucklescript-tea for quite a long time now... |
I am curious, do you use the same 'name' in other nodes in the tree? Maybe in another node that might get 'mutated' to this node or vice-versa? If so that would definitely prevent the function callback from updating as names should be unique across an entire application (think of the |
Thanks for responding so fast!
We're currently in the middle of our Elm->Bucklescript port so I don't currently have time to generate a minimal example of it, but now that I know it's a bug and not a gap in my understanding I'll definitely try to book in time to get one soon.
Yep for sure, that's actually what I've done -- by 'patched' here I just meant amended/based on. Incidentally, is adding optional The lack of
Could you possibly restate this in some other words? I feel like I'm like 80% there to understanding it but I'm struggling to re-formulate it in my own words which is showing me that I don't actually understand it 😄
Theoretically no, the identifiers should be unique -- but one symptom of this bug that's fixed by the addition of Both that symptom (incorrect identifier) and the initial symptom in the bug report (stale identifier) can be 'fixed' by deleting the event handler cache used in |
Funny thing, I just happend to have the same issue. Here is some code: type model = {
visibleDate : Js.Date.t;
}
type msg =
| Clicked of Js.Date.t
| NextMonth
| PreviousMonth
[@@bs.deriving accessors]
let update model = function
| Clicked date ->
let () = Js.log2 "Calendar got selected date" date in
model,Cmd.none
| NextMonth ->
let nextMonth = addMonths model.visibleDate 1 in
let day = min (getDaysInMonth nextMonth) (getDate model.visibleDate) in
let visibleDate = setDate nextMonth day in
{model with visibleDate = visibleDate},Cmd.none
| PreviousMonth ->
let prevMonth =
let prev = Js.Date.makeWithYM
~year:(model.visibleDate |> Js.Date.getFullYear)
~month:(model.visibleDate |> Js.Date.getMonth) () in
subMonths prev 1 |> lastDayOfMonth in
let day = min (getDaysInMonth prevMonth) (getDate model.visibleDate) in
let visibleDate = setDate prevMonth day in
{model with visibleDate = visibleDate},Cmd.none
let calendarNav model =
let open Html in
div [ class' "calendar-nav" ]
[ div
[ class' "calendar-nav-prev-month" ]
[ button
[ class' "button is-primary"; onClick PreviousMonth ]
[ span [ class' "icon"]
[ i [ class' "fas fa-chevron-left" ] [] ]
]
]
; div [ class' "calendar-month" ] [ text @@ format model.visibleDate "MMMM YYYY" ]
; div
[ class' "calendar-nav-next-month"; onClick NextMonth ]
[ button
[ class' "button is-primary" ]
[ span [ class' "icon"]
[ i [ class' "fas fa-chevron-right" ] [] ]
]
]
]
let dateView date =
let open Html in
let dateString = Js.Date.toString date in
let cb = Vdom.onCB "click" {j|$(dateString)-cb|j} (fun _ -> Clicked date|. Some ) in
node "div" ~key:{j|$(dateString)-div|j} [ class' "calendar-date"; id {j|$(dateString)-div|j} ]
[ node "button" ~key:{j|$(dateString)-button|j}
[ class' "date-item"; cb; id {j|$(dateString)-button|j} ]
[ date |> getDate |> string_of_int |> text ]
]
let calendarView model =
let open Html in
let dayLabels =
Belt.Array.make 7 @@ startOfWeek model.visibleDate
|. Belt.Array.mapWithIndex (fun i d ->
format (addDays d i) "ddd"
) in
let startDay =
model.visibleDate |> startOfMonth |> startOfWeek in
let endDay =
model.visibleDate |> endOfMonth |> endOfWeek in
let days =
let size = 1 + differenceInDays endDay startDay in
Belt.Array.make size startDay
|. Belt.Array.mapWithIndex (fun i d ->
addDays d i
) in
div [ class' "calendar-container" ]
[ div [ class' "calendar-header" ]
(Belt.Array.map dayLabels (fun day ->
node "div" ~key:day [ class' "calendar-date" ] [ text day ]
) |> Belt.List.fromArray)
; div [ class' "calendar-body" ]
(Belt.Array.map days (fun day ->
dateView day
) |> Belt.List.fromArray)
]
let view model =
let open Html in
let navView = calendarNav model in
div [ class' "calendar" ]
[ navView; (calendarView model) ]
Note, this is "ported" from https://gist.github.com/stevensacks/79c60d0f8b1f8bc06b475438f59d687e I'm curious about that |
Ok, after rereading this and other issues, I understood that I also have to key the e.g. let genKeyForMonth date =
format date "YYYYMM"
let genKeyForDay date =
format date "YYYYMMDD"
let onMonthClick date msg =
let key = genKeyForMonth date in
Html.onCB "click" key (fun _ -> Some msg)
let onDayClick date msg =
let key = genKeyForDay date in
Html.onCB "click" key (fun _ -> msg date |. Some) and in the let calendarNav model =
(* ... *)
button
[ class' "button is-primary"
; (model.visibleDate |. genPreviousMonth |. onMonthClick PreviousMonth)
]
[ span [ class' "icon"]
[ i [ class' "fas fa-chevron-left" ] [] ]
]
(* ... *)
let dateView date =
let open Html in
div [ class' "calendar-date" ]
[ button
[ class' "date-item"
; (date |. onDayClick clicked)
]
[ date |> getDate |> string_of_int |> text ]
] So the behaviour with the handlers not getting unregistered was due to not "inform" the VDOM about that the month changed, which is now done with proper keying. |
Absolutely. :-) The original Elm API didn't have them hence the lack of their initial inclusion, but as they are optional then they are backwards compatible anyway so it definitely makes sense.
Yeah the lack of Elm having them had some 'fun' as well (required use of lazy and other constructs to work around). But definitely would accept!
Heh, just in general you want to use
Well that's odd, considering the cache exists in part on the VDom node itself and on the actual DOM element itself, so being a scoping issue sounds exceedingly odd indeed... Especially as the key for the event callback should prevent the 'then' case from ever executing...
Yeah, in 'thought' every DOM Event Callback should have a globally unique ID. Elm does not do that (and it's had some "fun" issues related to it in the past) but trying to hold to it's API as close as I really could definitely enforces some mis-patterns. I'm wondering if it's time to dump the Elm API for the thought of actually fixing the interfaces, the compiler would definitely let people know what needs to be changed so...
Well the event callbacks themselves should have the ID as it allows the most fine-grained mutations. Putting a |
With
Thanks for that explanation. Apart from that, I would probably be comfortable with dumping the ELM API. |
I mean the literal id on the event callback variant, not the key or unique on the element, the element should generally not have either (maybe a unique depending on situation, but even then generally not). Thus on the https://github.com/OvermindDL1/bucklescript-tea/blob/master/src-ocaml/tea_html.ml#L262 line of |
Got it,
This should be somewhere bold in the docs/source imho. For a beginner who learns from reading the code (yeah I'm looking at you, |
Yeah it bugged me writing it too but I was trying to follow the Elm naming conventions at the time (not sure I care so much anymore)... ^.^;
Well it's optional within it's own |
I have an issue where event handler callbacks on a div that close over information do not get replaced even when the
key
of the event property changes.I'm using a patched Tea_html.onWithOptions that looks like the following:
I have event handlers on my DOM node that make use of this like so:
The code above doesn't work some (all?, this code is pretty deep into our view but I have it fully reproducible in a number of our integration tests) of the time, and results in the the callback messages being received by an update function/model that no longer has those identifiers (because the identifier has changed and the old one is no longer around).
The code does work when I give the
div
aunique
parameter where it is unique on the identifier, because it executesreplaceNode
branch of_MutateNode
I understand why the fix works, but I don't understand why it requires the fix in the first place, if that makes sense? My understanding is that because the
key
on theEvent
is changing that the old event handler should be unregistered and the new one registered. Is this a bug inkey
on event properties, or is this a case where I semantically wantunique
on the node itself?The text was updated successfully, but these errors were encountered: