Skip to content
This repository has been archived by the owner on Nov 14, 2017. It is now read-only.

1.6-form proposal #19

Closed
robmcm opened this issue May 16, 2016 · 13 comments
Closed

1.6-form proposal #19

robmcm opened this issue May 16, 2016 · 13 comments

Comments

@robmcm
Copy link

robmcm commented May 16, 2016

I would like to see a form example involving dynamically loaded/populated form fields. Such as a list of area codes that update based on selected country or state, or a list of street names that update based on postal (zip) code.

Ideally these filtered values would be fetched asynchronously from the server which would add additional complexity to the form. I would be very interested to see how you would tackle this in cycle.js

Thanks

@ivan-kleshnin
Copy link
Owner

ivan-kleshnin commented May 16, 2016

@robmcm hi. Thanks for your interest.

Such as a list of area codes that update based on selected country or state, or a list of street names that update based on postal (zip) code.

It's totally solvable with current architecture as we keep all form elements in state and can describe any dependency between them. Like "passwordAgain should be equal to password" or those you've described. It may be interesting / educational to add such example in 1.6, of course. I'll consider this.

Ideally these filtered values would be fetched asynchronously from the server which would add additional complexity to the form. I would be very interested to see how you would tackle this in cycle.js

This is different. I didn't approach data load architecture in CycleJS because I believe it's the hardest part (from my experience). I decided to inspect available solutions like GraphQL / Relay / PouchDB / ... first to see what they propose. By now, I've kinda finished with them (no general solution available). So I'm going to build over my React-Ultimate experience.

Before staring to mess with "data-load" I'd like to be ensured in the exact dataflow architecture (CRUD vs CRUD.alt). Also see my last comment in cyclejs/cyclejs#259.

You should also inspect https://github.com/cyclejs/examples

@robmcm
Copy link
Author

robmcm commented May 16, 2016

I decided to inspect available solutions like GraphQL / Relay / PouchDB / ...

I'm not too interested in the actual loading from an async resource, but more the fact that the form needs to be asynchronously updated based on a change in source data. This could be modeled in the example by just ticking a stream that switches between two different hard coded data sources (perhaps for suggested usernames?).

What I am trying to understand is how cycle.js would dynamically update the data backing a form. This raises issues such as updating the options in form elements, or having to change values based on the selected option no longer being available. All of the examples I have found so far have been based around hard coded form options, I am concerned that in order to implement dynamic backing data you would need to model it quite differently.

@ivan-kleshnin
Copy link
Owner

Sorry. I'm not sure I follow your explanation 😞

@robmcm
Copy link
Author

robmcm commented May 16, 2016

Sorry let me try again :)

I am interested in seeing how to model the following using cycle.js

Summary: Form elements with dynamic options.
Example: List of available usernames.

This perhaps isn't the best use case, but I wanted something that fitted with your example (as user sign up form).

Lets say that a list of usernames shows in a tag and by default it's empty/disabled. When the user enters their email address and name it should round trip to the server and requests a list of suggested usernames. For simplicity this part can be mocked by providing a utility method that returns a ticking stream with an array of suggested usernames. The user needs to select one of the suggested usernames, but the form needs to handle the use case of the selected value being removed from the list of options, presumable deselecting the value, and invalidating the form. Hopefully that is easier to understand :)

@ivan-kleshnin
Copy link
Owner

ivan-kleshnin commented May 16, 2016

What you've described is a highly specific business logic which one needs to completely understand before implementing. I don't understand, for example, why user should select from some predefined usernames. Usually, a list of possible usernames is proposed when inputted one is occupied. But even then they are just propositions and displayed as messages (not in the select field).

I'd like to avoid such specialized examples in the repo. They are hard to implement and support.
If you can boild down this to something more basic – I'm open to discussion.

@robmcm
Copy link
Author

robmcm commented May 16, 2016

It's not the best example, but I wanted to suggest something the fitted with the context of a user sign up form.

A better example would be entering your address. A common pattern on websites in the UK (not sure if this translates to other countries) is where the user must enter a postal code, and then a list of valid property numbers/names is displayed. Due to the vast number of address' in the country this needs to be loaded via the server once a post code is entered. Initially the selection control isn't shown and doesn't have any data. (https://craftyclicks.co.uk/paf-database-products/free-postcode-lookup-demos/)

Another example that touches on the idea of "dynamic backing data" is a reservation booking site, where you show the user a list of cinema/plane seats. These could be booked by someone else at any time so the system would need to be able to remove them as options from the form based on streaming data from the server. It would also have to handle the situation where you previously selected something that is no longer a valid option.

@ivan-kleshnin
Copy link
Owner

Thanks. I believe the hardest part in what you've decribed is what I called "data load question" in the beginning. It's not about fetching process, it's about dataflow and state structure. I need to think which example I'd like to use to try this out.

@robmcm
Copy link
Author

robmcm commented May 16, 2016

The data load question is a topic on it's own, not specific to a form. I would create a separate line of examples for that if I were you.

"Separation of tutorial concerns" if you will ;)

@ivan-kleshnin
Copy link
Owner

ivan-kleshnin commented May 16, 2016

Sure. But in tasks you mentioned backend and backend roundtrips were key factors (IMO).
If we exclude them – what's left?
And I'm not going to stuff all this into 1.6 (only your first proposition).

@robmcm
Copy link
Author

robmcm commented May 16, 2016

what's left

The task of updating selected form values and form options based on an external/async change.

I imagine you would have to combineLatest with the data stream and rebuild the form with the new data, but you would also need to update the currently selected option based on some prior business logic, perhaps even default a selected value in the form?

@ivan-kleshnin
Copy link
Owner

ivan-kleshnin commented May 17, 2016

Can we have async source without backend? – Yes.
Is there something special about it? – No. Most of RxJS stuff behaves in async mode.

As we keep user input in state, combining it with server or other "external" source is not a problem.
But how – it heavily depends on exact logic.

For things you describe, I mostly use scan, combineLatest, withLatestFrom, sample, filter and map. And also debounce to suppress glitches. This should be enough for all cases I can imagine.
I'm afraid your question a.t.m. is too broad and there is no precise answer except "it depends".

@robmcm
Copy link
Author

robmcm commented May 17, 2016

Would be great to see some examples of combining that state and your usages of sample.

Thanks for your feedback!

@ivan-kleshnin
Copy link
Owner

You're welcome! Feel free to ask or share your concerns.

sample and withLatestFrom are almost the same. The difference is in argument order, availability of sampling data to a merging function and possibility to capture n data streams for the latter.

// D - data stream
// S - sampling stream
// R - resulting stream

D.sample(S) 

  D: d1--d2--d3--d4--> 
  S: s1------s2------>
  R: d1------d3------>

S.withLatestFrom(D)

  S: s1------------s2----------->
  D: d1-------d2---d3------d4--->
  R: [s1, d1]------[s2, d3]----->

S.withLatestFrom(D, (s, d) => ...)

  S: s1------------s1---------->
  D: d1-------d2---d3------d4-->
  R: *-------------*----------->

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

No branches or pull requests

2 participants