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

Auto data session 4 #340

Merged
merged 13 commits into from
Apr 4, 2017
Merged

Auto data session 4 #340

merged 13 commits into from
Apr 4, 2017

Conversation

joelanman
Copy link
Contributor

@joelanman joelanman commented Jan 11, 2017

this updates #214 Auto data session 3 so it can be merged - copied from that PR:

This version of automatically storing and showing data across pages does not rely on macros, but instead using the checked function directly (see examples below). I'm not sure it's as user-friendly as the version with macros, but it may take a while to finalise our approach to macros.

Usage

This will make the kit automatically store all data from forms, for use later in your prototype.

For example if you have an input like this:

<input name="first-name">

You can put this on the next page, or any other page:

<p>Hello {{data['first-name']}}</p>

Population

To populate a text field with the value a user entered is simple:

<input name="first-name" value="{{data['first-name']}}">

To set radios or checkboxes use this:

{{ checked(name, value) }}

Using the name and value of the input. For example:

<input type="radio" name="over-18" value="Yes" {{checked("over-18", "Yes")}}>

<input type="checkbox" name="send-spam" value="No" {{checked("send-spam", "No")}}>

Dealing with checkboxes

This adds javascript so that when a user submits a form, the script looks for checkboxes in that form. For any checkbox, or group of checkboxes with the same name attribute, it adds a hidden input of the same name, with value "_unchecked". If the server only receives "_unchecked", it clears any data associated with that name.

@joelanman
Copy link
Contributor Author

Important note - this only works with POST. Do we want it on GET too?

@joelanman
Copy link
Contributor Author

Problem: HTML allows hyphens in the name attribute, but a hyphen cannot exist in a variable name in javascript, and therefore Nunjucks.

Solutions:

  1. Convention - say that hyphens are not allowed in the name attribute in prototypes
  2. Change the output syntax from
{{ date-of-birth }} // this is invalid for hyphenated names

to

{{ data['date-of-birth'] }} // this is valid for all names

@charlesrt
Copy link

In the example the checkbox data passes when only one is checked.

If two are checked, the value passed is empty "".

If all three are checked, only the first value is passed.

@joelanman
Copy link
Contributor Author

@charlesrt thanks, that sounds well broken, investigating..

@chrisadesign
Copy link
Contributor

Using this, it's awesome. Please merge :)

@joelanman
Copy link
Contributor Author

@charlesrt I think thats fixed now - I wasn't checking if "_unchecked" was being submitted, and instead just removing elements of arrays - this is now behind a proper if statement. Oops

@joelanman
Copy link
Contributor Author

I've changed the way you display data

Old

{{name}}

New

{{data['name']}}

This means hyphenated names work, where they were broken before.

I think this PR is ready to go, it's worth waiting for #365 as there's a Check your answers page in this PR that should use the new code.

Copy link
Contributor

@edwardhorsford edwardhorsford left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a load of stylistic and small points.

I'm in the process of recreating an existing prototype to test functionality - will add another comment tomorrow.

Other things:

  • I don't think it's clear how you pre-fill answers - this could be explicitly called out.
  • Should we mention to use on server side?
  • Should we mention how to not store data?

For those three, I wonder if the guide should have a final tutorial page that does goes over these items?

<fieldset>

<legend class="visuallyhidden">
Which of these applies to your vehicle? (Select all that apply)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think '(Select all that apply)' should be on a new line in regular body copy style.

<div class="form-group">
<fieldset>

<label class="form-label" for="registration-number">Vehicle registration number</label>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest this be form-label-bold - better matches our other examples, and helps it stand out on this page.

<p class="heading-medium">
What type of vehicle do you have?
</p>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could add a paragraph here that describes that these radios have name="vehicle-type", and that this will be used later. Matches better to the check your answers page that uses the value.

Which of these applies to your vehicle? (Select all that apply)
</legend>

<p class="heading-medium">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think this should be an h1, and probably placed outside of the fieldset.

<p class="heading-medium">
Which of these applies to your vehicle? (Select all that apply)
</p>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could add a paragraph here that describes that these checkboxes have name="vehicle-features", and that this will be used later. Matches better to the check your answers page that uses the value.

server.js Outdated
app.use(utils.forceHttps)
}

console.log({'autodata': useAutoStoreData})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intentionally here? It outputs before the normal welcome messages.

server.js Outdated

console.log({'autodata': useAutoStoreData})

if (useAutoStoreData === 'true') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should convert useAutoStoreData to boolean as we do with useDocumentation on line 30? We're not very consistent, so if you don't want to do now, that's fine.

server.js Outdated
app.use(function (req, res, next) {
// add nunjucks function to get values, needs to be here as they need access to req.session

nunjucksAppEnv.addGlobal('checked', function (name, value) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be pulled out as a function so it doesn't get duplicated for both apps?

server.js Outdated
next()
})

documentationApp.use(function (req, res, next) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this check if documentationApp exists?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

documentationApp currently always exists - its declared at the top of the file, we might want to change that

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The app exists, but routes aren't set up for it.

Later in server.js we use if (useDocumentation) {} - do you think something similar would be appropriate here?

I don't have a strong preference here - if you think it's not needed that's fine.

<fieldset>

<label class="form-label" for="registration-number">Vehicle registration number</label>
<input class="form-control" id="registration-number" name="vehicle-registration" type="text" value="{{vehicleRegistration}}">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the id match the name?

@edwardhorsford
Copy link
Contributor

I've recreated an existing prototype, and all looks good! Have successfully tested:

  • Storing, retrieving, transforming data.
  • Prefilling answers, inc radios and checkboxes.
  • That submitting no checked items works.
  • Clearing data
  • Using _thing to not store data

Some further comments:

  • Seems to inconsistently use data['thing'] and data["thing"]
  • The checked function could have a comment to say what it's doing.

I'm not confident enough to read the javascript in server.js, server.js and auto-store-data.js. Perhaps @NickColley or @tvararu could spare 15 minutes to check those files.

server.js Outdated
return inArray ? 'checked' : ''
} else {
return value === storedValue ? 'checked' : ''
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to refactor the 2 ternaries here you can try this:

var isChecked = false
if (Array.isArray(storedValue)) {
  isChecked = storedValue.indexOf(value) !== -1
} else {
  isChecked = value === storedValue
}
return isChecked ? 'checked' : ''

Or terser:

var isChecked = Array.isArray(storedValue)
  ? storedValue.indexOf(value) !== -1
  : value === storedValue

return isChecked ? 'checked' : ''

(Just a thought, feel free to ignore)

Copy link
Contributor Author

@joelanman joelanman Apr 3, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, I had another bash taking your first as a base, and ended up with this:

      var checked = ''

      // if data is an array, check it exists in the array
      if (Array.isArray(storedValue)) {
        if (storedValue.indexOf(value) !== -1){
          checked = 'checked'
        }
      } else {
        // the data is just a simple value, check it matches
        if (storedValue === value){
          checked = 'checked'
        }
      }
      return checked

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trying to avoid ternaries since they can be hard to read


exports.autoStoreData = function (req, res, next) {
if (!req.session.data) {
req.session.data = {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use this common pattern too:

req.session.data = req.session.data || {}

@joelanman joelanman force-pushed the auto-data-session-4 branch 2 times, most recently from 6bfd69d to 6ba6583 Compare April 3, 2017 14:48
@joelanman
Copy link
Contributor Author

Note this now supports both POST and GET

@joelanman joelanman force-pushed the auto-data-session-4 branch 3 times, most recently from 8f96526 to b155c61 Compare April 3, 2017 15:42
</p>

<p>
The code for the example is in this folder in the prototype kit:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest this be pulled out in to a section like the other examples below.

@joelanman joelanman force-pushed the auto-data-session-4 branch 2 times, most recently from c67f8ec to 610e42d Compare April 3, 2017 15:45
</pre>

<h3 class="heading-small">
Setting inputs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This heading feels jargony. What about something like "Pre-filling answers"

@edwardhorsford
Copy link
Contributor

I think this is 👍 to merge.

Amazing work. Thanks so much @joelanman for this. It's a massive improvement to the kit.

@joelanman joelanman merged commit 867b9ca into master Apr 4, 2017
@joelanman joelanman deleted the auto-data-session-4 branch April 4, 2017 16:40
@joelanman joelanman mentioned this pull request Apr 5, 2017
@timpaul
Copy link
Contributor

timpaul commented Apr 5, 2017

AMAZING WORK JOE

And Ed. And everyone. But mainly Joe.

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

Successfully merging this pull request may close these issues.

6 participants