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

Unexpected behaviour of andd #28

Closed
timjs opened this issue Aug 24, 2019 · 18 comments
Closed

Unexpected behaviour of andd #28

timjs opened this issue Aug 24, 2019 · 18 comments

Comments

@timjs
Copy link

timjs commented Aug 24, 2019

I'm experimenting with Widget composability and decided to try out the form example given in the documentation. I created a gist containing all the code for reference.

Creating a multi form step-by-step widget using traverse works as expected. However, composing them side-by-side using andd results in surprising behaviour (at least for me), when following these steps:

  • Start a side-by-side composition of the form widget using andd. This results in three forms, laid out on top of each other.
  • Change every input field of the form into something else, for example "1", "2", "3".
  • Submit one of the forms by hitting the "Submit" button.
  • Now there are two forms on the screen, as expected, but the state of these forms returned to their initial value!

I expected each individual form to keep their changed state. Is this expected behaviour or a bug? Should I write other code to make this work as I expect?


Some background: I'm trying to rewrite the edit headings example using widgets instead of signals. Here I ran into the same problem. Probably going to switch to the Haskell version of Concur, because I need some Haskell libs on the backend. I did not try the form example with Haskell yet.

@ajnsit
Copy link
Member

ajnsit commented Aug 24, 2019 via email

@timjs
Copy link
Author

timjs commented Aug 24, 2019

That's fine! Good travels.

@ajnsit
Copy link
Member

ajnsit commented Aug 25, 2019

On second thoughts, this does not seem like a bug.

When you set a “value” attribute on an input, it’s value will be reset on any state change. React provides a “defaultValue” attribute for this very problem. Can you try changing the attributes to “defaultValue”?

@timjs
Copy link
Author

timjs commented Aug 25, 2019

I'll try it out and let you know!

@timjs
Copy link
Author

timjs commented Aug 25, 2019

Works better, but still not as I expect:

  • Change every input field of the form into something else, for example "1", "2", "3".
  • Submit the second one, containing "2".
  • Now there are two forms on the screen, as expected, but their values are respectively "1" and "2", instead of "1" and "3".

@ajnsit
Copy link
Member

ajnsit commented Aug 25, 2019 via email

@timjs
Copy link
Author

timjs commented Aug 25, 2019

So I’ll need to generate an unique key/ID for every form in the list? I hoped I wouldn’t need to do that with Concur, kind of the big selling point when comparing it with TEA. Like in the tree example where you do not need to index of the subtrees.

Could you help me recreating this example using widgets only instead of signals? I've an implementation in this gist, but probably made some kind of mistake as I did in the form example, as state does not get saved correctly.

@timjs
Copy link
Author

timjs commented Aug 25, 2019

Should I add the key to every element? Adding it only to the div results in saving the values of the input fields, but all checkbox are cleared on a submit.

@ajnsit
Copy link
Member

ajnsit commented Aug 25, 2019 via email

@timjs
Copy link
Author

timjs commented Aug 25, 2019

Obviously! Thanks :-)

@ajnsit
Copy link
Member

ajnsit commented Aug 25, 2019 via email

@timjs
Copy link
Author

timjs commented Aug 25, 2019

So should I use a similar to trick with keys with the tree widget example? Or am I doing something else wrong?

PS Thanks for responding so quickly to my questions! No need to respond immediately if you're trying to enjoy your Sunday however ;-)

@ajnsit
Copy link
Member

ajnsit commented Aug 26, 2019

Could you help me recreating this example using widgets only instead of signals? I've an implementation in this gist, but probably made some kind of mistake as I did in the form example, as state does not get saved correctly.

Well you can't just andd the children together as then the widget won't save the state until all the children have finished. I created a combinator called displayList which supports widgets which can be deleted and passes any modifications to the list on to the parent. The code with that combinator is at - ba1a80f#diff-5d9f654f8ead8ee8848e2ba690fba9be

@ajnsit
Copy link
Member

ajnsit commented Aug 26, 2019

@timjs I'm going to close this issue. Please feel free to reopen in case you have more questions or comments!

@ajnsit ajnsit closed this as completed Aug 26, 2019
@timjs
Copy link
Author

timjs commented Aug 27, 2019

Thanks Anupam for helping me out. This is an intuitive solution.

So, if andd does not save the state of the widgets internally, what is the intended use case of it?

@ajnsit
Copy link
Member

ajnsit commented Aug 27, 2019 via email

@timjs
Copy link
Author

timjs commented Aug 28, 2019

Here andd takes an array of widgets, and returns a single widget. Once
you have combined the widgets with andd, there is no internal state of
any internal widget that's visible outside. Only when the entire andd
returns the result are we able to examine the result and possibly save it
ourselves. Monadic sequencing cannot see inside andd since at this level
it's just an opaque single widget.

I totally agree with this way of thinking. It would be odd to have a way to "peak into" the current state of a widget in the array. I expect that, after feeding a list of widgets to andd a step made by one of its elements is remembered.

However, the mistake I made was that every kind of event which would change the view of, for example, an input box would be remembered. But that is not true for basic Dom elements, as you explained. I see now that andd works in the expected way when I crate my own input box widget, which remembers every character entered, like this:

inputbox :: String -> Widget HTML String
inputbox value = do
  result <-
    Html.input
      [ Html.autoFocus true
      , Html._type "text"
      , Html.value value
      , Html.placeholder value
      , Just <$> Html.unsafeTargetValue <$> Html.onInput
      , Nothing <$ Html.onKeyEnter
      ]
  case result of
    Just value' -> inputbox value'
    Nothing -> pure value

@ajnsit
Copy link
Member

ajnsit commented Aug 28, 2019

Glad to hear 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

2 participants