Skip to content

Commit

Permalink
Allow nested objects in session
Browse files Browse the repository at this point in the history
E.g.

<input name="example1[name]" value="Hello 123">
<input name="example2[name]" value="Hello 456">
<input name="example3[name]" value="Hello 789">
  • Loading branch information
colinrotherham committed Aug 21, 2018
1 parent 4ce83be commit 08ed1a6
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 9 deletions.
63 changes: 61 additions & 2 deletions docs/documentation/session.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,71 @@ The easiest way to clear session data is to use 'Incognito mode' for each user,

In a route function, refer to `req.session`.

For example you might have `req.session.over18` or `req.session.firstName`.
### Accessing fields from the session

For example, when submitting the following (simplified) HTML:

```html
<input name="firstName" value="Sarah">
<input name="lastName" value="Philips">
```

You'll have a `req.session.data` object in your route function:

```js
{
firstName: 'Sarah',
lastName: 'Philips'
}
```

These two field values can be accessed in JavaScript as:

```js
req.session.data.firstName
req.session.data.lastName
```

### Accessing nested fields from the session

Session data can also be nested for easy grouping. For example answers from multiple family members:

```html
<input name="claimant[firstName]" value="Sarah">
<input name="claimant[lastName]" value="Philips">

<input name="partner[firstName]" value="Michael">
<input name="partner[lastName]" value="Philips">
```

You'll have a nested `req.session.data` object in your route function:

```js
{
claimant: {
firstName: 'Sarah',
lastName: 'Philips'
},
partner: {
firstName: 'Michael',
lastName: 'Philips'
}
}
```

These four field values can be accessed in your route function as:

```js
req.session.data.claimant.firstName
req.session.data.claimant.lastName
req.session.data.partner.firstName
req.session.data.partner.lastName
```

You can see a full example here:

[https://github.com/expressjs/session#example](https://github.com/expressjs/session#example)

You can read more about Express Session here:

[https://github.com/expressjs/session](https://github.com/expressjs/session)
[https://github.com/expressjs/session](https://github.com/expressjs/session)
46 changes: 45 additions & 1 deletion docs/views/examples/pass-data/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,60 @@ <h3 class="govuk-heading-s">
}
]
}) }}
{% endraw %}<code></pre>

<h3 class="govuk-heading-s">
Using the data in Nunjucks macros (nested fields)
</h3>

<p>Example using the 'checked' function in a checkbox component macro (nested fields for multiple vehicles):</p>

<pre class="app-code"><code>{% raw %}
{{ govukCheckboxes({
name: "vehicle1[vehicle-features]"
fieldset: {
legend: {
text: "Which of these applies to your vehicle?"
}
},
hint: {
text: "Select all that apply"
},
items: [
{
value: "Heated seats",
text: "Heated seats",
id: "vehicle1-vehicle-features-heated-seats",
checked: checked("vehicle1.vehicle-features", "Heated seats")
},
{
value: "GPS",
text: "GPS",
id: "vehicle1-vehicle-features-gps",
checked: checked("vehicle1.vehicle-features", "GPS")
},
{
value: "Radio",
text: "Radio",
id: "vehicle1-vehicle-features-radio",
checked: checked("vehicle1.vehicle-features", "Radio")
}
]
}) }}
{% endraw %}<code></pre>

<h3 class="govuk-heading-s">
Using the data on the server
</h3>

<p>You can access the data on the server in a route, for example for an input with name="first-name":</p>
<p>You can access the data on the server in a route function, for example for an input with name="first-name":</p>

<pre class="app-code"><code>var firstName = req.session.data['first-name']</code></pre>

<p>
<a href="/docs/examples/pass-data">More information on passing data from page to page here.</a>
</p>

<h3 class="govuk-heading-s">
Ignoring inputs
</h3>
Expand Down
22 changes: 16 additions & 6 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const fs = require('fs')
// NPM dependencies
const basicAuth = require('basic-auth')
const marked = require('marked')
const Notation = require('notation')
const path = require('path')
const portScanner = require('portscanner')
const prompt = require('prompt')
Expand Down Expand Up @@ -34,7 +35,8 @@ exports.addCheckedFunction = function (env) {
return ''
}

var storedValue = this.ctx.data[name]
var storedData = new Notation(this.ctx.data)
var storedValue = storedData.get(name)

// Check the requested data exists
if (storedValue === undefined) {
Expand Down Expand Up @@ -243,7 +245,7 @@ exports.matchMdRoutes = function (req, res) {
}

// Store data from POST body or GET query in session
var storeData = function (input, store) {
var storeData = function (input, data) {
for (var i in input) {
// any input where the name starts with _ is ignored
if (i.indexOf('_') === 0) {
Expand All @@ -254,7 +256,7 @@ var storeData = function (input, store) {

// Delete values when users unselect checkboxes
if (val === '_unchecked' || val === ['_unchecked']) {
delete store.data[i]
delete data[i]
continue
}

Expand All @@ -264,9 +266,17 @@ var storeData = function (input, store) {
if (index !== -1) {
val.splice(index, 1)
}
} else if (typeof val === 'object') {
// Store nested objects that aren't arrays
if (typeof data[i] !== 'object') {
data[i] = {}
}

// Add nested values
return storeData(val, data[i])
}

store.data[i] = val
data[i] = val
}
}

Expand All @@ -289,8 +299,8 @@ exports.autoStoreData = function (req, res, next) {

req.session.data = Object.assign({}, sessionDataDefaults, req.session.data)

storeData(req.body, req.session)
storeData(req.query, req.session)
storeData(req.body, req.session.data)
storeData(req.query, req.session.data)

// Send session data to all views

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"gulp-util": "^3.0.7",
"marked": "^0.4.0",
"minimist": "1.2.0",
"notation": "^1.3.6",
"notifications-node-client": "^4.1.0",
"nunjucks": "^3.1.3",
"portscanner": "^2.1.1",
Expand Down

0 comments on commit 08ed1a6

Please sign in to comment.