BookInstance list page - Learn web development

BookInstance list page
======================

Next we'll implement our list of all book copies (`BookInstance`) in the library. This page needs to include the title of the `Book` associated with each `BookInstance` (linked to its detail page) along with other information in the `BookInstance` model, including the status, imprint, and unique id of each copy. The unique id text should be linked to the `BookInstance` detail page.

Controller
----------

The `BookInstance` list controller function needs to get a list of all book instances, populate the associated book information, and then pass the list to the template for rendering.

 Open `/controllers/bookinstanceController.js`.
 Find the exported `bookinstance_list()` controller method and replace it with the following code.

```js
// Display list of all BookInstances.
exports.bookinstance_list = asyncHandler(async (req, res, next) => {
  const allBookInstances = await BookInstance.find().populate("book").exec();

  res.render("bookinstance\_list", {
    title: "Book Instance List",
    bookinstance\_list: allBookInstances,
  });
});
```

 The route handler calls the `find()` function on the `BookInstance` model, and then daisy-chains a call to `populate()` with the `book` field—this will replace the book id stored for each `BookInstance` with a full `Book` document.
 `exec()` is then daisy-chained on the end in order to execute the query and return a promise.

 The route handler uses `await` to wait on the promise, pausing execution until it is settled.
 If the promise is fulfilled, the results of the query are saved to the `allBookInstances` variable, and the route handler continues execution.

The last part of the code calls `render()`, specifying the **bookinstance\_list** (.pug) template and passing values for the `title` and `bookinstance_list` into the template.

View
----

Create **/views/bookinstance\_list.pug** and copy in the text below.

```pug
extends layout

block content
  h1= title

  if bookinstance\_list.length
    ul
      each val in bookinstance\_list
        li
          a(href=val.url) #{val.book.title} : #{val.imprint} -
          if val.status=='Available'
            span.text-success #{val.status}
          else if val.status=='Maintenance'
            span.text-danger #{val.status}
          else
            span.text-warning #{val.status}
          if val.status!='Available'
            span  (Due: #{val.due\_back} )

  else
    p There are no book copies in this library.
```

This view is much the same as all the others. It extends the layout, replacing the *content* block, displays the `title` passed in from the controller, and iterates through all the book copies in `bookinstance_list`. For each copy we display its status (color coded) and if the book is not available, its expected return date. One new feature is introduced—we can use dot notation after a tag to assign a class. So `span.text-success` will be compiled to `<span class="text-success">` (and might also be written in Pug as `span(class="text-success")`.

What does it look like?
-----------------------

Run the application, open your browser to `http://localhost:3000/`, then select the *All book-instances* link. If everything is set up correctly, your site should look something like the following screenshot.

![BookInstance List Page - Express Local Library site](/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_list_page/locallibary_express_bookinstance_list.png)

Next steps
----------

* Return to Express Tutorial Part 5: Displaying library data.
* Proceed to the next subarticle of part 5: Date formatting using luxon.


Book detail page - Learn web development

Book detail page
================

The *Book detail page* needs to display the information for a specific `Book` (identified using its automatically generated `_id` field value), along with information about each associated copy in the library (`BookInstance`). Wherever we display an author, genre, or book instance, these should be linked to the associated detail page for that item.

Controller
----------

Open **/controllers/bookController.js**. Find the exported `book_detail()` controller method and replace it with the following code.

```js
// Display detail page for a specific book.
exports.book_detail = asyncHandler(async (req, res, next) => {
  // Get details of books, book instances for specific book
  const [book, bookInstances] = await Promise.all([
    Book.findById(req.params.id).populate("author").populate("genre").exec(),
    BookInstance.find({ book: req.params.id }).exec(),
  ]);

  if (book === null) {
    // No results.
    const err = new Error("Book not found");
    err.status = 404;
    return next(err);
  }

  res.render("book\_detail", {
    title: book.title,
    book: book,
    book\_instances: bookInstances,
  });
});
```

**Note:** We don't need to require any additional modules in this step, as we already imported the dependencies when we implemented the home page controller.

 The approach is exactly the same as described for the Genre detail page.
 The route controller function uses `Promise.all()` to query the specified `Book` and its associated copies (`BookInstance`) in parallel.
 If no matching book is found an Error object is returned with a "404: Not Found" error.
 If the book is found, then the retrieved database information is rendered using the "book\_detail" template.
 Since the key 'title' is used to give name to the webpage (as defined in the header in 'layout.pug'), this time we are passing `results.book.title` while rendering the webpage.

View
----

Create **/views/book\_detail.pug** and add the text below.

```pug
extends layout

block content
  h1 Title: #{book.title}

  p #[strong Author: ]
    a(href=book.author.url) #{book.author.name}
  p #[strong Summary:] #{book.summary}
  p #[strong ISBN:] #{book.isbn}
  p #[strong Genre: ]
    each val, index in book.genre
      a(href=val.url) #{val.name}
      if index < book.genre.length - 1
        |,

  div(style='margin-left:20px;margin-top:20px')
    h4 Copies

    each val in book\_instances
      hr
      if val.status=='Available'
        p.text-success #{val.status}
      else if val.status=='Maintenance'
        p.text-danger #{val.status}
      else
        p.text-warning #{val.status}
      p #[strong Imprint:] #{val.imprint}
      if val.status!='Available'
        p #[strong Due back:] #{val.due\_back}
      p #[strong Id: ]
        a(href=val.url) #{val.\_id}

    else
      p There are no copies of this book in the library.
```

Almost everything in this template has been demonstrated in previous sections.

**Note:** The list of genres associated with the book is implemented in the template as below. This adds a comma and a non breaking space after every genre associated with the book except for the last one.

```pug
  p #[strong Genre: ]
    each val, index in book.genre
      a(href=val.url) #{val.name}
      if index < book.genre.length - 1
        |,
```

What does it look like?
-----------------------

Run the application and open your browser to `http://localhost:3000/`. Select the *All books* link, then select one of the books. If everything is set up correctly, your page should look something like the following screenshot.

![Book Detail Page - Express Local Library site](/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Book_detail_page/locallibary_express_book_detail.png)

Next steps
----------

* Return to Express Tutorial Part 5: Displaying library data.
* Proceed to the next subarticle of part 5: Author detail page.


Author detail page - Learn web development

Author detail page
==================

The author detail page needs to display the information about the specified `Author`, identified using their (automatically generated) `_id` field value, along with a list of all the `Book` objects associated with that `Author`.

Controller
----------

Open **/controllers/authorController.js**.

Add the following lines to the top of the file to `require()` the `Book` module needed by the author detail page (other modules such as "express-async-handler" should already be present).

```js
const Book = require("../models/book");
```

Find the exported `author_detail()` controller method and replace it with the following code.

```js
// Display detail page for a specific Author.
exports.author_detail = asyncHandler(async (req, res, next) => {
  // Get details of author and all their books (in parallel)
  const [author, allBooksByAuthor] = await Promise.all([
    Author.findById(req.params.id).exec(),
    Book.find({ author: req.params.id }, "title summary").exec(),
  ]);

  if (author === null) {
    // No results.
    const err = new Error("Author not found");
    err.status = 404;
    return next(err);
  }

  res.render("author\_detail", {
    title: "Author Detail",
    author: author,
    author\_books: allBooksByAuthor,
  });
});
```

 The approach is exactly the same as described for the Genre detail page.
 The route controller function uses `Promise.all()` to query the specified `Author` and their associated `Book` instances in parallel.
 If no matching author is found an Error object is sent to the Express error handling middleware.
 If the author is found then the retrieved database information is rendered using the "author\_detail" template.

View
----

Create **/views/author\_detail.pug** and copy in the following text.

```pug
extends layout

block content

  h1 Author: #{author.name}
  p #{author.date\_of\_birth} - #{author.date\_of\_death}

  div(style='margin-left:20px;margin-top:20px')

    h4 Books
    if author\_books.length
      dl
        each book in author\_books
          dt
            a(href=book.url) #{book.title}
          dd #{book.summary}
    else
      p This author has no books.
```

Everything in this template has been demonstrated in previous sections.

What does it look like?
-----------------------

Run the application and open your browser to `http://localhost:3000/`. Select the *All Authors* link, then select one of the authors. If everything is set up correctly, your site should look something like the following screenshot.

![Author Detail Page - Express Local Library site](/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_detail_page/locallibary_express_author_detail.png)

**Note:** The appearance of the author *lifespan* dates is ugly! We'll address that in the final challenge in this article.

Next steps
----------

* Return to Express Tutorial Part 5: Displaying library data.
* Proceed to final subarticle of part 5 : BookInstance detail page and challenge.


Template primer - Learn web development

Template primer
===============

A template is a text file defining the *structure* or layout of an output file, with placeholders used to represent where data will be inserted when the template is rendered (in *Express*, templates are referred to as *views*).

Express template choices
------------------------

Express can be used with many different template rendering engines. In this tutorial we use Pug (formerly known as *Jade*) for our templates. This is the most popular Node template language, and describes itself as a "clean, whitespace-sensitive syntax for writing HTML, heavily influenced by Haml".

Different template languages use different approaches for defining layout and marking placeholders for data—some use HTML to define the layout while others use different markup formats that can be transpiled to HTML. Pug is of the second type; it uses a *representation* of HTML where the first word in any line usually represents an HTML element, and indentation on subsequent lines is used to represent nesting. The result is a page definition that translates directly to HTML, but is more concise and arguably easier to read.

**Note:** The downside of using *Pug* is that it is sensitive to indentation and whitespace (if you add an extra space in the wrong place you may get an unhelpful error code). Once you have your templates in place, however, they are very easy to read and maintain.

Template configuration
----------------------

The *LocalLibrary* was configured to use Pug when we created the skeleton website. You should see the pug module included as a dependency in the website's **package.json** file, and the following configuration settings in the **app.js** file. The settings tell us that we're using pug as the view engine, and that *Express* should search for templates in the **/views** subdirectory.

```js
// View engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "pug");
```

 If you look in the views directory you will see the .pug files for the project's default views.
 These include the view for the home page (**index.pug**) and base template (**layout.pug**) that we will need to replace with our own content.
```

/express-locallibrary-tutorial  //the project root
  /views
    error.pug
    index.pug
    layout.pug
```

Template syntax
---------------

The example template file below shows off many of Pug's most useful features.

The first thing to notice is that the file maps the structure of a typical HTML file, with the first word in (almost) every line being an HTML element, and indentation being used to indicate nested elements. So for example, the `body` element is inside an `html` element, and paragraph elements (`p`) are within the `body` element, etc. Non-nested elements (e.g. individual paragraphs) are on separate lines.

```pug
doctype html
html(lang="en")
  head
    title= title
    script(type='text/javascript').
  body
    h1= title

    p This is a line with #[em some emphasis] and #[strong strong text] markup.
    p This line has un-escaped data: !{'<em> is emphasized</em>'} and escaped data: #{'<em> is not emphasized</em>'}.
      | This line follows on.
    p= 'Evaluated and <em>escaped expression</em>:' + title

    <!-- You can add HTML comments directly -->
    // You can add single line JavaScript comments and they are generated to HTML comments
    //- Introducing a single line JavaScript comment with "//-" ensures the comment isn't rendered to HTML

    p A line with a link
      a(href='/catalog/authors') Some link text
      |  and some extra text.

    #container.col
      if title
        p A variable named "title" exists.
      else
        p A variable named "title" does not exist.
      p.
 Pug is a terse and simple template language with a
 strong focus on performance and powerful features.

    h2 Generate a list

    ul
      each val in [1, 2, 3, 4, 5]
        li= val
```

Element attributes are defined in parentheses after their associated element. Inside the parentheses, the attributes are defined in comma- or whitespace- separated lists of the pairs of attribute names and attribute values, for example:

* `script(type='text/javascript')`, `link(rel='stylesheet', href='/stylesheets/style.css')`
* `meta(name='viewport' content='width=device-width initial-scale=1')`

The values of all attributes are *escaped* (e.g. characters like `>` are converted to their HTML code equivalents like `>`) to prevent JavaScript injection or cross-site scripting attacks.

If a tag is followed by the equals sign, the following text is treated as a JavaScript *expression*. So for example, in the first line below, the content of the `h1` tag will be *variable* `title` (either defined in the file or passed into the template from Express). In the second line the paragraph content is a text string concatenated with the `title` variable. In both cases the default behavior is to *escape* the line.

```pug
h1= title
p= 'Evaluated and <em>escaped expression</em>:' + title
```

If there is no equals symbol after the tag then the content is treated as plain text. Within the plain text you can insert escaped and unescaped data using the `#{}` and `!{}` syntax respectively, as shown below. You can also add raw HTML within the plain text.

```pug
p This is a line with #[em some emphasis] and #[strong strong text] markup.
p This line has an un-escaped string: !{'<em> is emphasized</em>'}, an escaped string: #{'<em> is not emphasized</em>'}, and escaped variables: #{title}.
```

**Note:** You will almost always want to escape data from users (via the **`#{}`** syntax). Data that can be trusted (e.g. generated counts of records, etc.) may be displayed without escaping the values.

You can use the pipe ('**|**') character at the beginning of a line to indicate "plain text". For example, the additional text shown below will be displayed on the same line as the preceding anchor, but will not be linked.

```pug
a(href='http://someurl/') Link text
| Plain text
```

Pug allows you to perform conditional operations using `if`, `else`, `else if` and `unless` — for example:

```pug
if title
  p A variable named "title" exists
else
  p A variable named "title" does not exist
```

You can also perform loop/iteration operations using `each-in` or `while` syntax. In the code fragment below we've looped through an array to display a list of variables (note the use of the 'li=' to evaluate the "val" as a variable below. The value you iterate across can also be passed into the template as a variable!

```pug
ul
  each val in [1, 2, 3, 4, 5]
    li= val
```

The syntax also supports comments (that can be rendered in the output—or not—as you choose), mixins to create reusable blocks of code, case statements, and many other features. For more detailed information see The Pug docs.

Extending templates
-------------------

Across a site, it is usual for all pages to have a common structure, including standard HTML markup for the head, footer, navigation, etc. Rather than forcing developers to duplicate this "boilerplate" in every page, *Pug* allows you to declare a base template and then extend it, replacing just the bits that are different for each specific page.

For example, the base template **layout.pug** created in our skeleton project looks like this:

```pug
doctype html
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
  body
    block content
```

The `block` tag is used to mark up sections of content that may be replaced in a derived template (if the block is not redefined then its implementation in the base class is used).

The default **index.pug** (created for our skeleton project) shows how we override the base template. The `extends` tag identifies the base template to use, and then we use `block section_name` to indicate the new content of the section that we will override.

```pug
extends layout

block content
  h1= title
  p Welcome to #{title}
```

Next steps
----------

* Return to Express Tutorial Part 5: Displaying library data.
* Proceed to the next subarticle of part 5: The LocalLibrary base template.


LocalLibrary base template - Learn web development

LocalLibrary base template
==========================

Now that we understand how to extend templates using Pug, let's start by creating a base template for the project. This will have a sidebar with links for the pages we hope to create across the tutorial articles (e.g. to display and create books, genres, authors, etc.) and a main content area that we'll override in each of our individual pages.

Open **/views/layout.pug** and replace the content with the code below.

```pug
doctype html
html(lang='en')
  head
    title= title
    meta(charset='utf-8')
    meta(name='viewport', content='width=device-width, initial-scale=1')
    link(rel="stylesheet", href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css", integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N", crossorigin="anonymous")
    script(src="https://code.jquery.com/jquery-3.5.1.slim.min.js", integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj", crossorigin="anonymous")
    script(src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.min.js", integrity="sha384-+sLIOodYLS7CIrQpBjl+C7nPvqq+FbNUBDunl/OZv93DB7Ln/533i8e/mZXLi/P+", crossorigin="anonymous")
    link(rel='stylesheet', href='/stylesheets/style.css')
  body
    div(class='container-fluid')
      div(class='row')
        div(class='col-sm-2')
          block sidebar
            ul(class='sidebar-nav')
              li
                a(href='/catalog') Home
              li
                a(href='/catalog/books') All books
              li
                a(href='/catalog/authors') All authors
              li
                a(href='/catalog/genres') All genres
              li
                a(href='/catalog/bookinstances') All book-instances
              li
                hr
              li
                a(href='/catalog/author/create') Create new author
              li
                a(href='/catalog/genre/create') Create new genre
              li
                a(href='/catalog/book/create') Create new book
              li
                a(href='/catalog/bookinstance/create') Create new book instance (copy)

        div(class='col-sm-10')
          block content
```

The template uses (and includes) JavaScript and CSS from Bootstrap to improve the layout and presentation of the HTML page. Using Bootstrap or another client-side web framework is a quick way to create an attractive page that can scale well on different browser sizes, and it also allows us to deal with the page presentation without having to get into any of the details—we just want to focus on the server-side code here!

**Note:** The scripts are loaded cross-origin, so later in the tutorial, when we add security middleware, we will need to explicitly allow these files to be loaded.
 For more information see Deployment > Use Helmet to protect against well known vulnerabilities.

The layout should be fairly obvious if you've read our above Template primer. Note the use of `block content` as a placeholder for where the content for our individual pages will be placed.

The base template also references a local CSS file (**style.css**) that provides a little additional styling. Open **/public/stylesheets/style.css** and replace its content with the following CSS code:

```css
.sidebar-nav {
  margin-top: 20px;
  padding: 0;
  list-style: none;
}
```

Now we have a base template for creating pages with a sidebar. In the next sections we will use it to define the individual pages.

Next steps
----------

* Return to Express Tutorial Part 5: Displaying library data.
* Proceed to the next subarticle of part 5: Home page.


Home page - Learn web development

Home page
=========

The first page we'll create will be the website home page, which is accessible from either the site (`/`) or catalog (`catalog/`) root. This will display some static text describing the site, along with dynamically calculated "counts" of different record types in the database.

We've already created a route for the home page. In order to complete the page we need to update our controller function to fetch "counts" of records from the database, and create a view (template) that we can use to render the page.

**Note:** We'll be using Mongoose for getting database information.
 Before continuing you may wish to re-read the Mongoose primer section on searching for records.

Route
-----

 We created our index page routes in a previous tutorial.
 As a reminder, all the route functions are defined in **/routes/catalog.js**:

```js
// GET catalog home page.
router.get("/", book_controller.index); //This actually maps to /catalog/ because we import the route with a /catalog prefix
```

The book controller index function passed as a parameter (`book_controller.index`) has a "placeholder" implementation defined in **/controllers/bookController.js**:

```js
exports.index = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Site Home Page");
});
```

It is this controller function that we extend to get information from our models and then render it using a template (view).

Controller
----------

The index controller function needs to fetch information about how many `Book`, `BookInstance` (all), `BookInstance` (available), `Author`, and `Genre` records we have in the database, render this data in a template to create an HTML page, and then return it in an HTTP response.

Open **/controllers/bookController.js**. Near the top of the file you should see the exported `index()` function.

```js
const Book = require("../models/book");
const asyncHandler = require("express-async-handler");

exports.index = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Site Home Page");
});
```

 Replace all the code above with the following code fragment.
 The first thing this does is import (`require()`) all the models.
 We need to do this because we'll be using them to get our counts of documents.
 The code also requires "express-async-handler", which provides a wrapper to catch exceptions thrown in route handler functions.

```js
const Book = require("../models/book");
const Author = require("../models/author");
const Genre = require("../models/genre");
const BookInstance = require("../models/bookinstance");

const asyncHandler = require("express-async-handler");

exports.index = asyncHandler(async (req, res, next) => {
  // Get details of books, book instances, authors and genre counts (in parallel)
  const [
    numBooks,
    numBookInstances,
    numAvailableBookInstances,
    numAuthors,
    numGenres,
  ] = await Promise.all([
    Book.countDocuments({}).exec(),
    BookInstance.countDocuments({}).exec(),
    BookInstance.countDocuments({ status: "Available" }).exec(),
    Author.countDocuments({}).exec(),
    Genre.countDocuments({}).exec(),
  ]);

  res.render("index", {
    title: "Local Library Home",
    book\_count: numBooks,
    book\_instance\_count: numBookInstances,
    book\_instance\_available\_count: numAvailableBookInstances,
    author\_count: numAuthors,
    genre\_count: numGenres,
  });
});
```

 We use the `countDocuments()` method to get the number of instances of each model.
 This method is called on a model, with an optional set of conditions to match against, and returns a `Query` object.
 The query can be executed by calling `exec()`, which returns a `Promise` that is either fulfilled with a result, or rejected if there is a database error.

 Because the queries for document counts are independent of each other we use `Promise.all()` to run them in parallel.
 The method returns a new promise that we `await` for completion (execution pauses within *this function* at `await`).
 When all the queries complete, the promise returned by `all()` fulfills, continuing execution of the route handler function, and populating the array with the results of the database queries.

 We then call `res.render()`, specifying a view (template) named '**index**' and objects mapping the results of the database queries to the view template.
 The data is supplied as key-value pairs, and can be accessed in the template using the key.

 Note that the code is very simple because we can assume that the database queries succeed.
 If any of the database operations fail, the exception that is thrown will be caught by `asyncHandler()` and passed to the `next` middleware handler in the chain.

View
----

Open **/views/index.pug** and replace its content with the text below.

```pug
extends layout

block content
  h1= title
  p Welcome to #[em LocalLibrary], a very basic Express website developed as a tutorial example on the Mozilla Developer Network.

  h1 Dynamic content

  p The library has the following record counts:

  ul
    li #[strong Books:] !{book\_count}
    li #[strong Copies:] !{book\_instance\_count}
    li #[strong Copies available:] !{book\_instance\_available\_count}
    li #[strong Authors:] !{author\_count}
    li #[strong Genres:] !{genre\_count}
```

The view is straightforward. We extend the **layout.pug** base template, overriding the `block` named '**content**'. The first `h1` heading will be the escaped text for the `title` variable that was passed into the `render()` function—note the use of the '`h1=`' so that the following text is treated as a JavaScript expression. We then include a paragraph introducing the LocalLibrary.

 Under the *Dynamic content* heading we list the number of copies of each model.
 Note that the template values for the data are the keys that were specified when `render()` was called in the route handler function.

**Note:** We didn't escape the count values (i.e. we used the `!{}` syntax) because the count values are calculated. If the information was supplied by end-users then we'd escape the variable for display.

What does it look like?
-----------------------

At this point we should have created everything needed to display the index page. Run the application and open your browser to `http://localhost:3000/`. If everything is set up correctly, your site should look something like the following screenshot.

![Home page - Express Local Library site](/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Home_page/locallibary_express_home.png)

**Note:** You won't be able to *use* the sidebar links yet because the URLs, views, and templates for those pages haven't been defined. If you try you'll get errors like "NOT IMPLEMENTED: Book list" for example, depending on the link you click on. These string literals (which will be replaced with proper data) were specified in the different controllers that live inside your "controllers" file.

Next steps
----------

* Return to Express Tutorial Part 5: Displaying library data.
* Proceed to the next subarticle of part 5: Book list page.


BookInstance detail page and challenge - Learn web development

BookInstance detail page and challenge
======================================

BookInstance detail page
------------------------

The `BookInstance` detail page needs to display the information for each `BookInstance`, identified using its (automatically generated) `_id` field value. This will include the `Book` name (as a link to the *Book detail page*) along with other information in the record.

### Controller

 Open **/controllers/bookinstanceController.js**.
 Find the exported `bookinstance_detail()` controller method and replace it with the following code.

```js
// Display detail page for a specific BookInstance.
exports.bookinstance_detail = asyncHandler(async (req, res, next) => {
  const bookInstance = await BookInstance.findById(req.params.id)
    .populate("book")
    .exec();

  if (bookInstance === null) {
    // No results.
    const err = new Error("Book copy not found");
    err.status = 404;
    return next(err);
  }

  res.render("bookinstance\_detail", {
    title: "Book:",
    bookinstance: bookInstance,
  });
});
```

 The implementation is very similar to that used for the other model detail pages.
 The route controller function calls `BookInstance.findById()` with the ID of a specific book instance extracted from the URL (using the route), and accessed within the controller via the request parameters: `req.params.id`.
 It then calls `populate()` to get the details of the associated `Book`.
 If a matching `BookInstance` is not found an error is sent to the Express middleware.
 Otherwise the returned data is rendered using the **bookinstance\_detail.pug** view.

### View

Create **/views/bookinstance\_detail.pug** and copy in the content below.

```pug
extends layout

block content

  h1 ID: #{bookinstance.\_id}

  p #[strong Title: ]
    a(href=bookinstance.book.url) #{bookinstance.book.title}
  p #[strong Imprint:] #{bookinstance.imprint}

  p #[strong Status: ]
    if bookinstance.status=='Available'
      span.text-success #{bookinstance.status}
    else if bookinstance.status=='Maintenance'
      span.text-danger #{bookinstance.status}
    else
      span.text-warning #{bookinstance.status}

  if bookinstance.status!='Available'
    p #[strong Due back:] #{bookinstance.due\_back}
```

Everything in this template has been demonstrated in previous sections.

### What does it look like?

Run the application and open your browser to `http://localhost:3000/`. Select the *All book-instances* link, then select one of the items. If everything is set up correctly, your site should look something like the following screenshot.

![BookInstance Detail Page - Express Local Library site](/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_detail_page_and_challenge/locallibary_express_bookinstance_detail.png)

Challenge
---------

Currently most *dates* displayed on the site use the default JavaScript format (e.g. *Tue Oct 06 2020 15:49:58 GMT+1100 (AUS Eastern Daylight Time))*. The challenge for this article is to improve the appearance of the date display for `Author` lifespan information (date of death/birth) and for *BookInstance detail* pages to use the format: Oct 6th, 2016.

**Note:** You can use the same approach as we used for the *Book Instance List* (adding the virtual property for the lifespan to the `Author` model and use luxon to format the date strings).

To complete this challenge, you must:

1. Replace the variable `due_back` with `due_back_formatted` in the *BookInstance detail* page.
2. Update the `Author` model to add a lifespan virtual property. The lifespan should look like: *date\_of\_birth - date\_of\_death*, where both values have the same date format as `BookInstance.due_back_formatted`.
3. Use `Author.lifespan` in all views where you currently explicitly use `date_of_birth` and `date_of_death`.
Next steps
----------

* Return to Express Tutorial Part 5: Displaying library data.


Date formatting using luxon - Learn web development

Date formatting using luxon
===========================

The default rendering of dates from our models is very ugly: *Mon Apr 10 2020 15:49:58 GMT+1100 (AUS Eastern Daylight Time)*. In this section we'll show how you can update the *BookInstance List* page from the previous section to present the `due_date` field in a more friendly format: Apr 10th, 2023.

The approach we will use is to create a virtual property in our `BookInstance` model that returns the formatted date. We'll do the actual formatting using luxon, a powerful, modern, and friendly library for parsing, validating, manipulating, formatting and localising dates.

**Note:** It is possible to use *luxon* to format the strings directly in our Pug templates, or we could format the string in a number of other places. Using a virtual property allows us to get the formatted date in exactly the same way as we get the `due_date` currently.

Install luxon
-------------

Enter the following command in the root of the project:

```bash
npm install luxon
```

Create the virtual property
---------------------------

1. Open **./models/bookinstance.js**.
2. At the top of the page, import *luxon*.

```js
const { DateTime } = require("luxon");
```

Add the virtual property `due_back_formatted` just after the URL property.

```js
BookInstanceSchema.virtual("due\_back\_formatted").get(function () {
  return DateTime.fromJSDate(this.due_back).toLocaleString(DateTime.DATE\_MED);
});
```

**Note:** Luxon can import strings in many formats and export to both predefined and free-form formats. In this case we use `fromJSDate()` to import a JavaScript date string and `toLocaleString()` to output the date in `DATE_MED` format in English: Apr 10th, 2023.
 For information about other formats and date string internationalization see the Luxon documentation on formatting.

Update the view
---------------

Open **/views/bookinstance\_list.pug** and replace `due_back` with `due_back_formatted`.

```pug
      if val.status != 'Available'
        //span (Due: #{val.due\_back} )
        span  (Due: #{val.due\_back\_formatted} )
```

That's it. If you go to *All book-instances* in the sidebar, you should now see all the due dates are far more attractive!

Next steps
----------

* Return to Express Tutorial Part 5: Displaying library data.
* Proceed to the next subarticle of part 5: Author list page and Genre list page challenge.


Genre detail page - Learn web development

Genre detail page
=================

 The genre *detail* page needs to display the information for a particular genre instance, using its automatically generated `_id` field value as the identifier.
 The ID of the required genre record is encoded at the end of the URL and extracted automatically based on the route definition (**/genre/:id**).
 It is then accessed within the controller via the request parameters: `req.params.id`.

The page should display the genre name and a list of all books in the genre with links to each book's details page.

Controller
----------

Open **/controllers/genreController.js** and require the `Book` module at the top of the file (the file should already `require()` the `Genre` module and "express-async-handler").

```js
const Book = require("../models/book");
```

Find the exported `genre_detail()` controller method and replace it with the following code.

```js
// Display detail page for a specific Genre.
exports.genre_detail = asyncHandler(async (req, res, next) => {
  // Get details of genre and all associated books (in parallel)
  const [genre, booksInGenre] = await Promise.all([
    Genre.findById(req.params.id).exec(),
    Book.find({ genre: req.params.id }, "title summary").exec(),
  ]);
  if (genre === null) {
    // No results.
    const err = new Error("Genre not found");
    err.status = 404;
    return next(err);
  }

  res.render("genre\_detail", {
    title: "Genre Detail",
    genre: genre,
    genre\_books: booksInGenre,
  });
});
```

 We first use `Genre.findById()` to get Genre information for a specific ID, and `Book.find()` to get all books records that have that same associated genre ID.
 Because the two requests do not depend on each other, we use `Promise.all()` to run the database queries in parallel (this same approach for running queries in parallel was demonstrated in the home page).

 We `await` on the returned promise, and once it settles we check the results.
 If the genre does not exist in the database (i.e. it may have been deleted) then `findById()` will return successfully with no results.
 In this case we want to display a "not found" page, so we create an `Error` object and pass it to the `next` middleware function in the chain.

**Note:** Errors passed to the `next` middleware function propagate through to our error handling code (this was set up when we generated the app skeleton - for more information see Handling Errors).

 If the `genre` is found, then we call `render()` to display the view.
 The view template is **genre\_detail** (.pug).
 The values for the title, `genre` and `booksInGenre` are passed into the template using the corresponding keys (`title`, `genre` and `genre_books`).

View
----

Create **/views/genre\_detail.pug** and fill it with the text below:

```pug
extends layout

block content

  h1 Genre: #{genre.name}

  div(style='margin-left:20px;margin-top:20px')

    h4 Books
    if genre\_books.length
      dl
        each book in genre\_books
          dt
            a(href=book.url) #{book.title}
          dd #{book.summary}
    else
      p This genre has no books.
```

The view is very similar to all our other templates. The main difference is that we don't use the `title` passed in for the first heading (though it is used in the underlying **layout.pug** template to set the page title).

What does it look like?
-----------------------

Run the application and open your browser to `http://localhost:3000/`. Select the *All genres* link, then select one of the genres (e.g. "Fantasy"). If everything is set up correctly, your page should look something like the following screenshot.

![Genre Detail Page - Express Local Library site](/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Genre_detail_page/locallibary_express_genre_detail.png)

**Note:** You might get an error similar to the one below if `req.params.id` (or any other ID) cannot be cast to a `mongoose.Types.ObjectId()`.

```bash
Cast to ObjectId failed for value " 59347139895ea23f9430ecbb" at path "\_id" for model "Genre"
```

 The most likely cause is that the ID being passed into the mongoose methods is not actually an ID.
 `Mongoose.prototype.isValidObjectId()` can be used to check whether a particular ID is valid.

Next steps
----------

* Return to Express Tutorial Part 5: Displaying library data.
* Proceed to the next subarticle of part 5: Book detail page.


Author list page and Genre list page challenge - Learn web development

Author list page and Genre list page challenge
==============================================

The author list page needs to display a list of all authors in the database, with each author name linked to its associated author detail page. The date of birth and date of death should be listed after the name on the same line.

Controller
----------

The author list controller function needs to get a list of all `Author` instances, and then pass these to the template for rendering.

Open **/controllers/authorController.js**. Find the exported `author_list()` controller method near the top of the file and replace it with the following code.

```js
// Display list of all Authors.
exports.author_list = asyncHandler(async (req, res, next) => {
  const allAuthors = await Author.find().sort({ family\_name: 1 }).exec();
  res.render("author\_list", {
    title: "Author List",
    author\_list: allAuthors,
  });
});
```

 The route controller function follows the same pattern as for the other list pages.
 It defines a query on the `Author` model, using the `find()` function to get all authors, and the `sort()` method to sort them by `family_name` in alphabetic order.
 `exec()` is daisy-chained on the end in order to execute the query and return a promise that the function can `await`.

Once the promise is fulfilled the route handler renders the **author\_list**(.pug) template, passing the page `title` and the list of authors (`allAuthors`) using template keys.

View
----

Create **/views/author\_list.pug** and replace its content with the text below.

```pug
extends layout

block content
  h1= title

  if author\_list.length
    ul
      each author in author\_list
        li
          a(href=author.url) #{author.name}
          |  (#{author.date_of_birth} - #{author.date_of_death})
  else
    p There are no authors.
```

Run the application and open your browser to `http://localhost:3000/`. Then select the *All authors* link. If everything is set up correctly, the page should look something like the following screenshot.

![Author List Page - Express Local Library site](/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page/locallibary_express_author_list.png)

**Note:** The appearance of the author *lifespan* dates is ugly! You can improve this using the same approach as we used for the `BookInstance` list (adding the virtual property for the lifespan to the `Author` model).

However, as the author may not be dead or may have missing birth/death data, in this case we need to ignore missing dates or references to nonexistent properties. One way to deal with this is to return either a formatted date, or a blank string, depending on whether the property is defined. For example:

`return this.date_of_birth ? DateTime.fromJSDate(this.date_of_birth).toLocaleString(DateTime.DATE_MED) : '';`

Genre list page—challenge!
--------------------------

In this section you should implement your own genre list page. The page should display a list of all genres in the database, with each genre linked to its associated detail page. A screenshot of the expected result is shown below.

![Genre List - Express Local Library site](/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page/locallibary_express_genre_list.png)

The genre list controller function needs to get a list of all `Genre` instances, and then pass these to the template for rendering.

1. You will need to edit `genre_list()` in **/controllers/genreController.js**.
2. The implementation is almost exactly the same as the `author_list()` controller.
    * Sort the results by name, in ascending order.
3. The template to be rendered should be named **genre\_list.pug**.
4. The template to be rendered should be passed the variables `title` ('Genre List') and `genre_list` (the list of genres returned from your `Genre.find()` callback).
5. The view should match the screenshot/requirements above (this should have a very similar structure/format to the Author list view, except for the fact that genres do not have dates).
Next steps
----------

Return to Express Tutorial Part 5: Displaying library data.

Proceed to the next subarticle of part 5: Genre detail page.


Book list page - Learn web development

Book list page
==============

Next we'll implement our book list page. This page needs to display a list of all books in the database along with their author, with each book title being a hyperlink to its associated book detail page.

Controller
----------

The book list controller function needs to get a list of all `Book` objects in the database, sort them, and then pass these to the template for rendering.

Open **/controllers/bookController.js**. Find the exported `book_list()` controller method and replace it with the following code.

```js
// Display list of all books.
exports.book_list = asyncHandler(async (req, res, next) => {
  const allBooks = await Book.find({}, "title author")
    .sort({ title: 1 })
    .populate("author")
    .exec();

  res.render("book\_list", { title: "Book List", book\_list: allBooks });
});
```

 The route handler calls the `find()` function on the `Book` model, selecting to return only the `title` and `author` as we don't need the other fields (it will also return the `_id` and virtual fields), and sorting the results by the title alphabetically using the `sort()` method.
 We also call `populate()` on `Book`, specifying the `author` field—this will replace the stored book author id with the full author details.
 `exec()` is then daisy-chained on the end in order to execute the query and return a promise.

 The route handler uses `await` to wait on the promise, pausing execution until it is settled.
 If the promise is fulfilled, the results of the query are saved to the `allBooks` variable and the handler continues execution.

The final part of the route handler calls `render()`, specifying the **book\_list** (.pug) template and passing values for the `title` and `book_list` into the template.

View
----

Create **/views/book\_list.pug** and copy in the text below.

```pug
extends layout

block content
  h1= title
  if book\_list.length
    ul
      each book in book\_list
        li
          a(href=book.url) #{book.title}
          |  (#{book.author.name})

  else
    p There are no books.
```

 The view extends the **layout.pug** base template and overrides the `block` named '**content**'. It displays the `title` we passed in from the controller (via the `render()` method) and iterates through the `book_list` variable using the `each`-`in` syntax. A list item is created for each book displaying the book title as a link to the book's detail page followed by the author name.
 If there are no books in the `book_list` then the `else` clause is executed, and displays the text 'There are no books'.

**Note:** We use `book.url` to provide the link to the detail record for each book (we've implemented this route, but not the page yet). This is a virtual property of the `Book` model which uses the model instance's `_id` field to produce a unique URL path.

Of interest here is that each book is defined as two lines, using the pipe for the second line. This approach is needed because if the author name were on the previous line then it would be part of the hyperlink.

What does it look like?
-----------------------

Run the application (see Testing the routes for the relevant commands) and open your browser to `http://localhost:3000/`. Then select the *All books* link. If everything is set up correctly, your site should look something like the following screenshot.

![Book List Page - Express Local Library site](/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page/new_book_list.png)

Next steps
----------

* Return to Express Tutorial Part 5: Displaying library data.
* Proceed to the next subarticle of part 5: BookInstance list page.


Create Book form - Learn web development

Create Book form
================

This subarticle shows how to define a page/form to create `Book` objects. This is a little more complicated than the equivalent `Author` or `Genre` pages because we need to get and display available `Author` and `Genre` records in our `Book` form.

Import validation and sanitization methods
------------------------------------------

Open **/controllers/bookController.js**, and add the following line at the top of the file (before the route functions):

```js
const { body, validationResult } = require("express-validator");
```

Controller—get route
--------------------

Find the exported `book_create_get()` controller method and replace it with the following code:

```js
// Display book create form on GET.
exports.book_create_get = asyncHandler(async (req, res, next) => {
  // Get all authors and genres, which we can use for adding to our book.
  const [allAuthors, allGenres] = await Promise.all([
    Author.find().sort({ family\_name: 1 }).exec(),
    Genre.find().sort({ name: 1 }).exec(),
  ]);

  res.render("book\_form", {
    title: "Create Book",
    authors: allAuthors,
    genres: allGenres,
  });
});
```

 This uses `await` on the result of `Promise.all()` to get all `Author` and `Genre` objects in parallel (the same approach used in Express Tutorial Part 5: Displaying library data).
 These are then passed to the view **`book_form.pug`** as variables named `authors` and `genres` (along with the page `title`).

Controller—post route
---------------------

Find the exported `book_create_post()` controller method and replace it with the following code.

```js
// Handle book create on POST.
exports.book_create_post = [
  // Convert the genre to an array.
  (req, res, next) => {
    if (!Array.isArray(req.body.genre)) {
      req.body.genre =
        typeof req.body.genre === "undefined" ? [] : [req.body.genre];
    }
    next();
  },

  // Validate and sanitize fields.
  body("title", "Title must not be empty.")
    .trim()
    .isLength({ min: 1 })
    .escape(),
  body("author", "Author must not be empty.")
    .trim()
    .isLength({ min: 1 })
    .escape(),
  body("summary", "Summary must not be empty.")
    .trim()
    .isLength({ min: 1 })
    .escape(),
  body("isbn", "ISBN must not be empty").trim().isLength({ min: 1 }).escape(),
  body("genre.\*").escape(),
  // Process request after validation and sanitization.

  asyncHandler(async (req, res, next) => {
    // Extract the validation errors from a request.
    const errors = validationResult(req);

    // Create a Book object with escaped and trimmed data.
    const book = new Book({
      title: req.body.title,
      author: req.body.author,
      summary: req.body.summary,
      isbn: req.body.isbn,
      genre: req.body.genre,
    });

    if (!errors.isEmpty()) {
      // There are errors. Render form again with sanitized values/error messages.

      // Get all authors and genres for form.
      const [allAuthors, allGenres] = await Promise.all([
        Author.find().sort({ family\_name: 1 }).exec(),
        Genre.find().sort({ name: 1 }).exec(),
      ]);

      // Mark our selected genres as checked.
      for (const genre of allGenres) {
        if (book.genre.includes(genre._id)) {
          genre.checked = "true";
        }
      }
      res.render("book\_form", {
        title: "Create Book",
        authors: allAuthors,
        genres: allGenres,
        book: book,
        errors: errors.array(),
      });
    } else {
      // Data from form is valid. Save book.
      await book.save();
      res.redirect(book.url);
    }
  }),
];
```

The structure and behavior of this code is almost exactly the same as the post route functions for the `Genre` and `Author` forms. First we validate and sanitize the data. If the data is invalid then we re-display the form along with the data that was originally entered by the user and a list of error messages. If the data is valid, we then save the new `Book` record and redirect the user to the book detail page.

 The main difference with respect to the other form handling code is how we sanitize the genre information.
 The form returns an array of `Genre` items (while for other fields it returns a string).
 In order to validate the information we first convert the request to an array (required for the next step).

```js
[
  // Convert the genre to an array.
  (req, res, next) => {
    if (!Array.isArray(req.body.genre)) {
      req.body.genre =
        typeof req.body.genre === "undefined" ? [] : [req.body.genre];
    }
    next();
  },
  // …
];
```

We then use a wildcard (`*`) in the sanitizer to individually validate each of the genre array entries. The code below shows how - this translates to "sanitize every item below key `genre`".

```js
[
  // …
  body("genre.\*").escape(),
  // …
];
```

 The final difference with respect to the other form handling code is that we need to pass in all existing genres and authors to the form.
 In order to mark the genres that were checked by the user we iterate through all the genres and add the `checked="true"` parameter to those that were in our post data (as reproduced in the code fragment below).

```js
// Mark our selected genres as checked.
for (const genre of allGenres) {
  if (book.genre.includes(genre._id)) {
    genre.checked = "true";
  }
}
```

View
----

Create **/views/book\_form.pug** and copy in the text below.

```pug
extends layout

block content
  h1= title

  form(method='POST')
    div.form-group
      label(for='title') Title:
      input#title.form-control(type='text', placeholder='Name of book' name='title' required value=(undefined===book ? '' : book.title) )
    div.form-group
      label(for='author') Author:
      select#author.form-control(name='author' required)
        option(value='') --Please select an author--
        for author in authors
          if book
            if author.\_id.toString()===book.author.\_id.toString()
              option(value=author.\_id selected) #{author.name}
            else
              option(value=author.\_id) #{author.name}
          else
            option(value=author.\_id) #{author.name}
    div.form-group
      label(for='summary') Summary:
      textarea#summary.form-control(placeholder='Summary' name='summary' required)= undefined===book ? '' : book.summary
    div.form-group
      label(for='isbn') ISBN:
      input#isbn.form-control(type='text', placeholder='ISBN13' name='isbn' value=(undefined===book ? '' : book.isbn) required)
    div.form-group
      label Genre:
      div
        for genre in genres
          div(style='display: inline; padding-right:10px;')
            if genre.checked
              input.checkbox-input(type='checkbox', name='genre', id=genre.\_id, value=genre.\_id, checked)
            else
              input.checkbox-input(type='checkbox', name='genre', id=genre.\_id, value=genre.\_id)
            label(for=genre.\_id)  #{genre.name}
    button.btn.btn-primary(type='submit') Submit

  if errors
    ul
      for error in errors
        li!= error.msg
```

The view structure and behavior is almost the same as for the **genre\_form.pug** template.

The main differences are in how we implement the selection-type fields: `Author` and `Genre`.

* The set of genres are displayed as checkboxes, and use the `checked` value we set in the controller to determine whether or not the box should be selected.
* The set of authors are displayed as a single-selection alphabetically ordered drop-down list (the list passed to the template is already sorted, so we don't need to do that in the template).
 If the user has previously selected a book author (i.e. when fixing invalid field values after initial form submission, or when updating book details) the author will be re-selected when the form is displayed. Here we determine what author to select by comparing the id of the current author option with the value previously entered by the user (passed in via the `book` variable).

**Note:** If there is an error in the submitted form, then, when the form is to be re-rendered, the new book author's id and the existing books's authors ids are of type `Schema.Types.ObjectId`. So to compare them we must convert them to strings first.

What does it look like?
-----------------------

Run the application, open your browser to `http://localhost:3000/`, then select the *Create new book* link. If everything is set up correctly, your site should look something like the following screenshot. After you submit a valid book, it should be saved and you'll be taken to the book detail page.

![Screenshot of empty Local library Create Book form on localhost:3000. The page is divided into two columns. The narrow left column has a vertical navigation bar with 10 links separated into two sections by a light-colored horizontal line. The top section link to already created data. The bottom links go to create new data forms. The wide right column has the create book form with a 'Create Book' heading and four input fields labeled 'Title', 'Author', 'Summary', 'ISBN' and 'Genre' followed by four genre checkboxes: fantasy, science fiction, french poetry and action. There is a 'Submit' button at the bottom of the form.](/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_book_form/locallibary_express_book_create_empty.png)

Next steps
----------

Return to Express Tutorial Part 6: Working with forms.

Proceed to the next subarticle of part 6: Create BookInstance form.


Create Author form - Learn web development

Create Author form
==================

This subarticle shows how to define a page for creating `Author` objects.

Import validation and sanitization methods
------------------------------------------

As with the genre form, to use *express-validator* we have to *require* the functions we want to use.

Open **/controllers/authorController.js**, and add the following line at the top of the file (above the route functions):

```js
const { body, validationResult } = require("express-validator");
```

Controller—get route
--------------------

Find the exported `author_create_get()` controller method and replace it with the following code. This renders the **author\_form.pug** view, passing a `title` variable.

```js
// Display Author create form on GET.
exports.author\_create\_get = (req, res, next) => {
  res.render("author\_form", { title: "Create Author" });
};
```

Controller—post route
---------------------

Find the exported `author_create_post()` controller method, and replace it with the following code.

```js
// Handle Author create on POST.
exports.author_create_post = [
  // Validate and sanitize fields.
  body("first\_name")
    .trim()
    .isLength({ min: 1 })
    .escape()
    .withMessage("First name must be specified.")
    .isAlphanumeric()
    .withMessage("First name has non-alphanumeric characters."),
  body("family\_name")
    .trim()
    .isLength({ min: 1 })
    .escape()
    .withMessage("Family name must be specified.")
    .isAlphanumeric()
    .withMessage("Family name has non-alphanumeric characters."),
  body("date\_of\_birth", "Invalid date of birth")
    .optional({ values: "falsy" })
    .isISO8601()
    .toDate(),
  body("date\_of\_death", "Invalid date of death")
    .optional({ values: "falsy" })
    .isISO8601()
    .toDate(),

  // Process request after validation and sanitization.
  asyncHandler(async (req, res, next) => {
    // Extract the validation errors from a request.
    const errors = validationResult(req);

    // Create Author object with escaped and trimmed data
    const author = new Author({
      first\_name: req.body.first_name,
      family\_name: req.body.family_name,
      date\_of\_birth: req.body.date_of_birth,
      date\_of\_death: req.body.date_of_death,
    });

    if (!errors.isEmpty()) {
      // There are errors. Render form again with sanitized values/errors messages.
      res.render("author\_form", {
        title: "Create Author",
        author: author,
        errors: errors.array(),
      });
      return;
    } else {
      // Data from form is valid.

      // Save author.
      await author.save();
      // Redirect to new author record.
      res.redirect(author.url);
    }
  }),
];
```

**Warning:** Never validate *names* using `isAlphanumeric()` (as we have done above) as there are many names that use other character sets.
 We do it here in order to demonstrate how the validator is used, and how it can be daisy-chained with other validators and error reporting.

The structure and behavior of this code is almost exactly the same as for creating a `Genre` object. First we validate and sanitize the data. If the data is invalid then we re-display the form along with the data that was originally entered by the user and a list of error messages. If the data is valid then we save the new author record and redirect the user to the author detail page.

Unlike with the `Genre` post handler, we don't check whether the `Author` object already exists before saving it. Arguably we should, though as it is now we can have multiple authors with the same name.

The validation code demonstrates several new features:

* We can daisy chain validators, using `withMessage()` to specify the error message to display if the previous validation method fails.
 This makes it very easy to provide specific error messages without lots of code duplication.

```js
[
  // Validate and sanitize fields.
  body("first\_name")
    .trim()
    .isLength({ min: 1 })
    .escape()
    .withMessage("First name must be specified.")
    .isAlphanumeric()
    .withMessage("First name has non-alphanumeric characters."),
  // …
];
```

* We can use the `optional()` function to run a subsequent validation only if a field has been entered (this allows us to validate optional fields).
 For example, below we check that the optional date of birth is an ISO8601-compliant date (the `{ values: "falsy" }` object passed means that we'll accept either an empty string or `null` as an empty value).

```js
[
  body("date\_of\_birth", "Invalid date of birth")
    .optional({ values: "falsy" })
    .isISO8601()
    .toDate(),
];
```

* Parameters are received from the request as strings. We can use `toDate()` (or `toBoolean()`) to cast these to the proper JavaScript types (as shown at the end of the validator chain above).
View
----

Create **/views/author\_form.pug** and copy in the text below.

```pug
extends layout

block content
  h1=title

  form(method='POST')
    div.form-group
      label(for='first\_name') First Name:
      input#first\_name.form-control(type='text', placeholder='First name (Christian)' name='first_name' required value=(undefined===author ? '' : author.first_name) )
      label(for='family\_name') Family Name:
      input#family\_name.form-control(type='text', placeholder='Family name (Surname)' name='family_name' required value=(undefined===author ? '' : author.family_name))
    div.form-group
      label(for='date\_of\_birth') Date of birth:
      input#date\_of\_birth.form-control(type='date' name='date\_of\_birth' value=(undefined===author ? '' : author.date\_of\_birth) )
    button.btn.btn-primary(type='submit') Submit

  if errors
    ul
      for error in errors
        li!= error.msg
```

The structure and behavior for this view is exactly the same as for the **genre\_form.pug** template, so we won't describe it again.

**Note:** Some browsers don't support the input `type="date"`, so you won't get the datepicker widget or the default `dd/mm/yyyy` placeholder, but will instead get an empty plain text field. One workaround is to explicitly add the attribute `placeholder='dd/mm/yyyy'` so that on less capable browsers you will still get information about the desired text format.

### Challenge: Adding the date of death

The template above is missing a field for entering the `date_of_death`. Create the field following the same pattern as the date of birth form group!

What does it look like?
-----------------------

Run the application, open your browser to `http://localhost:3000/`, then select the *Create new author* link. If everything is set up correctly, your site should look something like the following screenshot. After you enter a value, it should be saved and you'll be taken to the author detail page.

![Author Create Page - Express Local Library site](/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_author_form/locallibary_express_author_create_empty.png)

**Note:** If you experiment with various input formats for the dates, you may find that the format `yyyy-mm-dd` misbehaves. This is because JavaScript treats date strings as including the time of 0 hours, but additionally treats date strings in that format (the ISO 8601 standard) as including the time 0 hours UTC, rather than the local time. If your time zone is west of UTC, the date display, being local, will be one day before the date you entered. This is one of several complexities (such as multi-word family names and multi-author books) that we are not addressing here.

Next steps
----------

* Return to Express Tutorial Part 6: Working with forms.
* Proceed to the next subarticle of part 6: Create Book form.


Update Book form - Learn web development

Update Book form
================

This final subarticle shows how to define a page to update `Book` objects. Form handling when updating a book is much like that for creating a book, except that you must populate the form in the `GET` route with values from the database.

Controller—get route
--------------------

Open **/controllers/bookController.js**. Find the exported `book_update_get()` controller method and replace it with the following code.

```js
// Display book update form on GET.
exports.book_update_get = asyncHandler(async (req, res, next) => {
  // Get book, authors and genres for form.
  const [book, allAuthors, allGenres] = await Promise.all([
    Book.findById(req.params.id).populate("author").exec(),
    Author.find().sort({ family\_name: 1 }).exec(),
    Genre.find().sort({ name: 1 }).exec(),
  ]);

  if (book === null) {
    // No results.
    const err = new Error("Book not found");
    err.status = 404;
    return next(err);
  }

  // Mark our selected genres as checked.
  allGenres.forEach((genre) => {
    if (book.genre.includes(genre._id)) genre.checked = "true";
  });

  res.render("book\_form", {
    title: "Update Book",
    authors: allAuthors,
    genres: allGenres,
    book: book,
  });
});
```

 The controller gets the id of the `Book` to be updated from the URL parameter (`req.params.id`).
 It `awaits` on the promise returned by `Promise.all()` to get the specified `Book` record (populating its genre and author fields) and all the `Author` and `Genre` records.

When the operations complete the function checks whether any books were found, and if none were found sends an error "Book not found" to the error handling middleware.

**Note:** Not finding any book results is **not an error** for a search — but it is for this application because we know there must be a matching book record! The code above compares for (`book===null`) in the callback, but it could equally well have daisy chained the method orFail() to the query.

We then mark the currently selected genres as checked and then render the **book\_form.pug** view, passing variables for `title`, book, all `authors`, and all `genres`.

Controller—post route
---------------------

Find the exported `book_update_post()` controller method, and replace it with the following code.

```js
// Handle book update on POST.
exports.book_update_post = [
  // Convert the genre to an array.
  (req, res, next) => {
    if (!Array.isArray(req.body.genre)) {
      req.body.genre =
        typeof req.body.genre === "undefined" ? [] : [req.body.genre];
    }
    next();
  },

  // Validate and sanitize fields.
  body("title", "Title must not be empty.")
    .trim()
    .isLength({ min: 1 })
    .escape(),
  body("author", "Author must not be empty.")
    .trim()
    .isLength({ min: 1 })
    .escape(),
  body("summary", "Summary must not be empty.")
    .trim()
    .isLength({ min: 1 })
    .escape(),
  body("isbn", "ISBN must not be empty").trim().isLength({ min: 1 }).escape(),
  body("genre.\*").escape(),

  // Process request after validation and sanitization.
  asyncHandler(async (req, res, next) => {
    // Extract the validation errors from a request.
    const errors = validationResult(req);

    // Create a Book object with escaped/trimmed data and old id.
    const book = new Book({
      title: req.body.title,
      author: req.body.author,
      summary: req.body.summary,
      isbn: req.body.isbn,
      genre: typeof req.body.genre === "undefined" ? [] : req.body.genre,
      \_id: req.params.id, // This is required, or a new ID will be assigned!
    });

    if (!errors.isEmpty()) {
      // There are errors. Render form again with sanitized values/error messages.

      // Get all authors and genres for form
      const [allAuthors, allGenres] = await Promise.all([
        Author.find().sort({ family\_name: 1 }).exec(),
        Genre.find().sort({ name: 1 }).exec(),
      ]);

      // Mark our selected genres as checked.
      for (const genre of allGenres) {
        if (book.genre.indexOf(genre._id) > -1) {
          genre.checked = "true";
        }
      }
      res.render("book\_form", {
        title: "Update Book",
        authors: allAuthors,
        genres: allGenres,
        book: book,
        errors: errors.array(),
      });
      return;
    } else {
      // Data from form is valid. Update the record.
      const updatedBook = await Book.findByIdAndUpdate(req.params.id, book, {});
      // Redirect to book detail page.
      res.redirect(updatedBook.url);
    }
  }),
];
```

 This is very similar to the post route used when creating a `Book`.
 First we validate and sanitize the book data from the form and use it to create a new `Book` object (setting its `_id` value to the id of the object to update). If there are errors when we validate the data then we re-render the form, additionally displaying the data entered by the user, the errors, and lists of genres and authors. If there are no errors then we call `Book.findByIdAndUpdate()` to update the `Book` document, and then redirect to its detail page.

View
----

There is no need to change the view for the form (**/views/book\_form.pug**) as the same template works for both creating and updating the book.

Add an update button
--------------------

Open the **book\_detail.pug** view and make sure there are links for both deleting and updating books at the bottom of the page, as shown below.

```pug
  hr
  p
    a(href=book.url+'/delete') Delete Book
  p
    a(href=book.url+'/update') Update Book
```

You should now be able to update books from the *Book detail* page.

What does it look like?
-----------------------

Run the application, open your browser to `http://localhost:3000/`, select the *All books* link, then select a particular book. Finally select the *Update Book* link.

The form should look just like the *Create book* page, only with a title of 'Update book', and pre-populated with record values.

![The update book section of the Local library application. The left column has a vertical navigation bar. The right column has a form to update the book with an heading that reads 'Update book'. There are five input fields labelled Title, Author, Summary, ISBN, Genre. Genre is a checkbox option field. There is a button labelled 'Submit' at the end.](/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Update_Book_form/locallibary_express_book_update_noerrors.png)

**Note:** The other pages for updating objects can be implemented in much the same way. We've left that as a challenge.

Next steps
----------

* Return to Express Tutorial Part 6: Working with forms.


Create genre form - Learn web development

Create genre form
=================

This sub article shows how we define our page to create `Genre` objects (this is a good place to start because the `Genre` has only one field, its `name`, and no dependencies). Like any other pages, we need to set up routes, controllers, and views.

Import validation and sanitization methods
------------------------------------------

To use the *express-validator* in our controllers we have to *require* the functions we want to use from the `'express-validator'` module.

Open **/controllers/genreController.js**, and add the following line at the top of the file, before any route handler functions:

```js
const { body, validationResult } = require("express-validator");
```

**Note:** This syntax allows us to use `body` and `validationResult` as the associated middleware functions, as you will see in the post route section below. It is equivalent to:

```js
const validator = require("express-validator");
const body = validator.body;
const validationResult = validator.validationResult;
```

Controller—get route
--------------------

 Find the exported `genre_create_get()` controller method and replace it with the following code.
 This renders the **genre\_form.pug** view, passing a title variable.

```js
// Display Genre create form on GET.
exports.genre\_create\_get = (req, res, next) => {
  res.render("genre\_form", { title: "Create Genre" });
};
```

 Note that this replaces the placeholder asynchronous handler that we added in the Express Tutorial Part 4: Routes and controllers with a "normal" express route handler function.
 We don't need the `asyncHandler()` wrapper for this route, because it doesn't contain any code that can throw an exception.

Controller—post route
---------------------

Find the exported `genre_create_post()` controller method and replace it with the following code.

```js
// Handle Genre create on POST.
exports.genre_create_post = [
  // Validate and sanitize the name field.
  body("name", "Genre name must contain at least 3 characters")
    .trim()
    .isLength({ min: 3 })
    .escape(),

  // Process request after validation and sanitization.
  asyncHandler(async (req, res, next) => {
    // Extract the validation errors from a request.
    const errors = validationResult(req);

    // Create a genre object with escaped and trimmed data.
    const genre = new Genre({ name: req.body.name });

    if (!errors.isEmpty()) {
      // There are errors. Render the form again with sanitized values/error messages.
      res.render("genre\_form", {
        title: "Create Genre",
        genre: genre,
        errors: errors.array(),
      });
      return;
    } else {
      // Data from form is valid.
      // Check if Genre with same name already exists.
      const genreExists = await Genre.findOne({ name: req.body.name }).exec();
      if (genreExists) {
        // Genre exists, redirect to its detail page.
        res.redirect(genreExists.url);
      } else {
        await genre.save();
        // New genre saved. Redirect to genre detail page.
        res.redirect(genre.url);
      }
    }
  }),
];
```

 The first thing to note is that instead of being a single middleware function (with arguments `(req, res, next)`) the controller specifies an *array* of middleware functions.
 The array is passed to the router function and each method is called in order.

**Note:** This approach is needed, because the validators are middleware functions.

The first method in the array defines a body validator (`body()`) that validates and sanitizes the field. This uses `trim()` to remove any trailing/leading whitespace, checks that the *name* field is not empty, and then uses `escape()` to remove any dangerous HTML characters).

```js
[
  // Validate that the name field is not empty.
  body("name", "Genre name must contain at least 3 characters")
    .trim()
    .isLength({ min: 3 })
    .escape(),
  // …
];
```

After specifying the validators we create a middleware function to extract any validation errors. We use `isEmpty()` to check whether there are any errors in the validation result. If there are then we render the form again, passing in our sanitized genre object and the array of error messages (`errors.array()`).

```js
// Process request after validation and sanitization.
asyncHandler(async (req, res, next) => {
  // Extract the validation errors from a request.
  const errors = validationResult(req);

  // Create a genre object with escaped and trimmed data.
  const genre = new Genre({ name: req.body.name });

  if (!errors.isEmpty()) {
    // There are errors. Render the form again with sanitized values/error messages.
    res.render("genre\_form", {
      title: "Create Genre",
      genre: genre,
      errors: errors.array(),
    });
    return;
  } else {
    // Data from form is valid.
    // …
  }
});
```

 If the genre name data is valid then we perform a case-insensitive search to see if a `Genre` with the same name already exists (as we don't want to create duplicate or near duplicate records that vary only in letter case, such as: "Fantasy", "fantasy", "FaNtAsY", and so on).
 To ignore letter case and accents when searching we chain the `collation()` method, specifying the locale of 'en' and strength of 2 (for more information see the MongoDB Collation topic).

 If a `Genre` with a matching name already exists we redirect to its detail page.
 If not, we save the new `Genre` and redirect to its detail page.
 Note that here we `await` on the result of the database query, following the same pattern as in other route handlers.

```js
// Check if Genre with same name already exists.
const genreExists = await Genre.findOne({ name: req.body.name })
  .collation({ locale: "en", strength: 2 })
  .exec();
if (genreExists) {
  // Genre exists, redirect to its detail page.
  res.redirect(genreExists.url);
} else {
  await genre.save();
  // New genre saved. Redirect to genre detail page.
  res.redirect(genre.url);
}
```

This same pattern is used in all our post controllers: we run validators (with sanitizers), then check for errors and either re-render the form with error information or save the data.

View
----

 The same view is rendered in both the `GET` and `POST` controllers/routes when we create a new `Genre` (and later on it is also used when we *update* a `Genre`). In the `GET` case the form is empty, and we just pass a title variable. In the `POST` case the user has previously entered invalid data—in the `genre` variable we pass back a sanitized version of the entered data and in the `errors` variable we pass back an array of error messages.
 The code below shows the controller code for rendering the template in both cases.

```js
// Render the GET route
res.render("genre\_form", { title: "Create Genre" });

// Render the POST route
res.render("genre\_form", {
  title: "Create Genre",
  genre,
  errors: errors.array(),
});
```

Create **/views/genre\_form.pug** and copy in the text below.

```pug
extends layout

block content

  h1 #{title}

  form(method='POST')
    div.form-group
      label(for='name') Genre:
      input#name.form-control(type='text', placeholder='Fantasy, Poetry etc.' name='name' required value=(undefined===genre ? '' : genre.name) )
    button.btn.btn-primary(type='submit') Submit

  if errors
    ul
      for error in errors
        li!= error.msg
```

Much of this template will be familiar from our previous tutorials. First, we extend the **layout.pug** base template and override the `block` named '**content**'. We then have a heading with the `title` we passed in from the controller (via the `render()` method).

Next, we have the pug code for our HTML form that uses `method="POST"` to send the data to the server, and because the `action` is an empty string, will send the data to the same URL as the page.

The form defines a single required field of type "text" called "name". The default *value* of the field depends on whether the `genre` variable is defined. If called from the `GET` route it will be empty as this is a new form. If called from a `POST` route it will contain the (invalid) value originally entered by the user.

The last part of the page is the error code. This prints a list of errors, if the error variable has been defined (in other words, this section will not appear when the template is rendered on the `GET` route).

**Note:** This is just one way to render the errors. You can also get the names of the affected fields from the error variable, and use these to control where the error messages are rendered, whether to apply custom CSS, etc.

What does it look like?
-----------------------

Run the application, open your browser to `http://localhost:3000/`, then select the *Create new genre* link. If everything is set up correctly, your site should look something like the following screenshot. After you enter a value, it should be saved and you'll be taken to the genre detail page.

![Genre Create Page - Express Local Library site](/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_genre_form/locallibary_express_genre_create_empty.png)

The only error we validate against server-side is that the genre field must have at least three characters. The screenshot below shows what the error list would look like if you supply a genre with only one or two characters (highlighted in yellow).

![The Create Genre section of the Local library application. The left column has a vertical navigation bar. The right section is the create a new Genre from with a heading that reads 'Create Genre'. There is one input field labeled 'Genre'. There is a submit button at the bottom. There is an error message that reads 'Genre name required' directly below the Submit button. The error message was highlighted by the author of this article. There is no visual indication in the form that the genre is required nor that the error message only appears on error.](/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_genre_form/locallibary_express_genre_create_error.png)

**Note:** Our validation uses `trim()` to ensure that whitespace is not accepted as a genre name. We also validate that the field is not empty on the client side by adding the boolean attribute `required` to the field definition in the form:

```pug
input#name.form-control(type='text', placeholder='Fantasy, Poetry etc.' name='name' required value=(undefined===genre ? '' : genre.name) )
```

Next steps
----------

1. Return to Express Tutorial Part 6: Working with forms.
2. Proceed to the next sub article of part 6: Create Author form.


Delete Author form - Learn web development

Delete Author form
==================

This subarticle shows how to define a page to delete `Author` objects.

 As discussed in the form design section, our strategy will be to only allow deletion of objects that are not referenced by other objects (in this case that means we won't allow an `Author` to be deleted if it is referenced by a `Book`).
 In terms of implementation this means that the form needs to confirm that there are no associated books before the author is deleted.
 If there are associated books, it should display them, and state that they must be deleted before the `Author` object can be deleted.

Controller—get route
--------------------

Open **/controllers/authorController.js**. Find the exported `author_delete_get()` controller method and replace it with the following code.

```js
// Display Author delete form on GET.
exports.author_delete_get = asyncHandler(async (req, res, next) => {
  // Get details of author and all their books (in parallel)
  const [author, allBooksByAuthor] = await Promise.all([
    Author.findById(req.params.id).exec(),
    Book.find({ author: req.params.id }, "title summary").exec(),
  ]);

  if (author === null) {
    // No results.
    res.redirect("/catalog/authors");
  }

  res.render("author\_delete", {
    title: "Delete Author",
    author: author,
    author\_books: allBooksByAuthor,
  });
});
```

 The controller gets the id of the `Author` instance to be deleted from the URL parameter (`req.params.id`).
 It uses `await` on the promise returned by `Promise.all()` to asynchronously wait on the specified author record and all associated books (in parallel).
 When both operations have completed it renders the **author\_delete.pug** view, passing variables for the `title`, `author`, and `author_books`.

**Note:** If `findById()` returns no results the author is not in the database.
 In this case there is nothing to delete, so we immediately redirect to the list of all authors.

```js
if (author === null) {
  // No results.
  res.redirect("/catalog/authors");
}
```

Controller—post route
---------------------

Find the exported `author_delete_post()` controller method, and replace it with the following code.

```js
// Handle Author delete on POST.
exports.author_delete_post = asyncHandler(async (req, res, next) => {
  // Get details of author and all their books (in parallel)
  const [author, allBooksByAuthor] = await Promise.all([
    Author.findById(req.params.id).exec(),
    Book.find({ author: req.params.id }, "title summary").exec(),
  ]);

  if (allBooksByAuthor.length > 0) {
    // Author has books. Render in same way as for GET route.
    res.render("author\_delete", {
      title: "Delete Author",
      author: author,
      author\_books: allBooksByAuthor,
    });
    return;
  } else {
    // Author has no books. Delete object and redirect to the list of authors.
    await Author.findByIdAndDelete(req.body.authorid);
    res.redirect("/catalog/authors");
  }
});
```

 First we validate that an id has been provided (this is sent via the form body parameters, rather than using the version in the URL).
 Then we get the author and their associated books in the same way as for the `GET` route.
 If there are no books then we delete the author object and redirect to the list of all authors.
 If there are still books then we just re-render the form, passing in the author and list of books to be deleted.

**Note:** We could check if the call to `findById()` returns any result, and if not, immediately render the list of all authors.
 We've left the code as it is above for brevity (it will still return the list of authors if the id is not found, but this will happen after `findByIdAndDelete()`).

View
----

Create **/views/author\_delete.pug** and copy in the text below.

```pug
extends layout

block content

  h1 #{title}: #{author.name}
  p= author.lifespan

  if author\_books.length

    p #[strong Delete the following books before attempting to delete this author.]
    div(style='margin-left:20px;margin-top:20px')
      h4 Books
      dl
        each book in author\_books
          dt
            a(href=book.url) #{book.title}
          dd #{book.summary}

  else
    p Do you really want to delete this Author?

    form(method='POST')
      div.form-group
        input#authorid.form-control(type='hidden', name='authorid', value=author.\_id )

      button.btn.btn-primary(type='submit') Delete
```

 The view extends the layout template, overriding the block named `content`. At the top it displays the author details.
 It then includes a conditional statement based on the number of **`author_books`** (the `if` and `else` clauses).

* If there *are* books associated with the author then the page lists the books and states that these must be deleted before this `Author` may be deleted.
* If there *are no* books then the page displays a confirmation prompt.
* If the **Delete** button is clicked then the author id is sent to the server in a `POST` request and that author's record will be deleted.
Add a delete control
--------------------

Next we will add a **Delete** control to the *Author detail* view (the detail page is a good place from which to delete a record).

**Note:** In a full implementation the control would be made visible only to authorized users.
 However at this point we haven't got an authorization system in place!

Open the **author\_detail.pug** view and add the following lines at the bottom.

```pug
hr
p
  a(href=author.url+'/delete') Delete author
```

The control should now appear as a link, as shown below on the *Author detail* page.

![The Author details section of the Local library application. The left column has a vertical navigation bar. The right section contains the author details with a heading that has the Author's name followed by the life dates of the author and lists the books written by the author below it. There is a button labelled 'Delete Author' at the bottom.](/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Delete_author_form/locallibary_express_author_detail_delete.png)

What does it look like?
-----------------------

 Run the application and open your browser to `http://localhost:3000/`.
 Then select the *All authors* link, and then select a particular author. Finally select the *Delete author* link.

 If the author has no books, you'll be presented with a page like this.
 After pressing delete, the server will delete the author and redirect to the author list.

![The Delete Author section of the Local library application of an author who does not have any books. The left column has a vertical navigation bar. The right section contains the author's name and life dates. There is the question "Do you really want to delete this author" with a button labeled 'Delete'.](/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Delete_author_form/locallibary_express_author_delete_nobooks.png)

 If the author does have books, then you'll be presented with a view like the following.
 You can then delete the books from their detail pages (once that code is implemented!).

![The Delete Author section of the Local library application of an author who does have books under his name. The section contains the author's name and life dates of the author. There is a statement that reads "Delete the following books before attempting to delete this author" followed by the author's books. The list includes the titles of each book, as links, followed by a brief description in plain text.](/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Delete_author_form/locallibary_express_author_delete_withbooks.png)

**Note:** The other pages for deleting objects can be implemented in much the same way.
 We've left that as a challenge.

Next steps
----------

* Return to Express Tutorial Part 6: Working with forms.
* Proceed to the final subarticle of part 6: Update Book form.


Create BookInstance form - Learn web development

Create BookInstance form
========================

 This subarticle shows how to define a page/form to create `BookInstance` objects.
 This is very much like the form we used to create `Book` objects.

Import validation and sanitization methods
------------------------------------------

Open **/controllers/bookinstanceController.js**, and add the following lines at the top of the file:

```js
const { body, validationResult } = require("express-validator");
```

Controller—get route
--------------------

At the top of the file, require the *Book* module (needed because each `BookInstance` is associated with a particular `Book`).

```js
const Book = require("../models/book");
```

Find the exported `bookinstance_create_get()` controller method and replace it with the following code.

```js
// Display BookInstance create form on GET.
exports.bookinstance_create_get = asyncHandler(async (req, res, next) => {
  const allBooks = await Book.find({}, "title").sort({ title: 1 }).exec();

  res.render("bookinstance\_form", {
    title: "Create BookInstance",
    book\_list: allBooks,
  });
});
```

 The controller gets a sorted list of all books (`allBooks`) and passes it via `book_list` to the view **`bookinstance_form.pug`** (along with a `title`).
 Note that no book has been selected when we first display this form, so we don't pass the `selected_book` variable to `render()`.
 Because of this, `selected_book` will have a value of `undefined` in the template.

Controller—post route
---------------------

Find the exported `bookinstance_create_post()` controller method and replace it with the following code.

```js
// Handle BookInstance create on POST.
exports.bookinstance_create_post = [
  // Validate and sanitize fields.
  body("book", "Book must be specified").trim().isLength({ min: 1 }).escape(),
  body("imprint", "Imprint must be specified")
    .trim()
    .isLength({ min: 1 })
    .escape(),
  body("status").escape(),
  body("due\_back", "Invalid date")
    .optional({ values: "falsy" })
    .isISO8601()
    .toDate(),

  // Process request after validation and sanitization.
  asyncHandler(async (req, res, next) => {
    // Extract the validation errors from a request.
    const errors = validationResult(req);

    // Create a BookInstance object with escaped and trimmed data.
    const bookInstance = new BookInstance({
      book: req.body.book,
      imprint: req.body.imprint,
      status: req.body.status,
      due\_back: req.body.due_back,
    });

    if (!errors.isEmpty()) {
      // There are errors.
      // Render form again with sanitized values and error messages.
      const allBooks = await Book.find({}, "title").sort({ title: 1 }).exec();

      res.render("bookinstance\_form", {
        title: "Create BookInstance",
        book\_list: allBooks,
        selected\_book: bookInstance.book._id,
        errors: errors.array(),
        bookinstance: bookInstance,
      });
      return;
    } else {
      // Data from form is valid
      await bookInstance.save();
      res.redirect(bookInstance.url);
    }
  }),
];
```

 The structure and behavior of this code is the same as for creating our other objects.
 First we validate and sanitize the data. If the data is invalid, we then re-display the form along with the data that was originally entered by the user and a list of error messages.
 If the data is valid, we save the new `BookInstance` record and redirect the user to the detail page.

View
----

Create **/views/bookinstance\_form.pug** and copy in the text below.

```pug
extends layout

block content
  h1=title

  form(method='POST')
    div.form-group
      label(for='book') Book:
      select#book.form-control(name='book' required)
        option(value='') --Please select a book--
        for book in book\_list
          if selected\_book==book.\_id.toString()
            option(value=book.\_id, selected) #{book.title}
          else
            option(value=book.\_id) #{book.title}

    div.form-group
      label(for='imprint') Imprint:
      input#imprint.form-control(type='text' placeholder='Publisher and date information' name='imprint' required value=(undefined===bookinstance ? '' : bookinstance.imprint) )
    div.form-group
      label(for='due\_back') Date when book available:
      input#due\_back.form-control(type='date' name='due\_back' value=(undefined===bookinstance ? '' : bookinstance.due\_back\_yyyy\_mm\_dd))

    div.form-group
      label(for='status') Status:
      select#status.form-control(name='status' required)
        option(value='') --Please select a status--
        each val in ['Maintenance', 'Available', 'Loaned', 'Reserved']
          if undefined===bookinstance || bookinstance.status!=val
            option(value=val)= val
          else
            option(value=val selected)= val

    button.btn.btn-primary(type='submit') Submit

  if errors
    ul
      for error in errors
        li!= error.msg
```

**Note:** The above template hard-codes the *Status* values (Maintenance, Available, etc.) and does not "remember" the user's entered values.
 Should you so wish, consider reimplementing the list, passing in option data from the controller and setting the selected value when the form is re-displayed.

 The view structure and behavior is almost the same as for the **book\_form.pug** template, so we won't go over it in detail.
 The one thing to note is the line where we set the "due back" date to `bookinstance.due_back_yyyy_mm_dd` if we are populating the date input for an existing instance.

```pug
input#due\_back.form-control(type='date', name='due\_back' value=(undefined===bookinstance ? '' : bookinstance.due\_back\_yyyy\_mm\_dd))
```

 The date value has to be set in the format `YYYY-MM-DD` because this is expected by `<input>` elements with `type="date"`, however the date is not stored in this format so we have to convert it before setting the value in the control.
 The `due_back_yyyy_mm_dd()` method is added to the `BookInstance` model in the next section.

Model—virtual `due_back_yyyy_mm_dd()` method
--------------------------------------------

 Open the file where you defined the `BookInstanceSchema` model (**models/bookinstance.js**).
 Add the `due_back_yyyy_mm_dd()` virtual function shown below (after the `due_back_formatted()` virtual function):

```js
BookInstanceSchema.virtual("due\_back\_yyyy\_mm\_dd").get(function () {
  return DateTime.fromJSDate(this.due_back).toISODate(); // format 'YYYY-MM-DD'
});
```

What does it look like?
-----------------------

 Run the application and open your browser to `http://localhost:3000/`.
 Then select the *Create new book instance (copy)* link. If everything is set up correctly, your site should look something like the following screenshot. After you submit a valid `BookInstance`, it should be saved and you'll be taken to the detail page.

![Create BookInstance of the Local library application screenshot from localhost:3000. The page is divided into two columns. The narrow left column has a vertical navigation bar with 10 links separated into two sections by a light-colored horizontal line. The top section link to already created data. The bottom links go to create new data forms. The wide right column has the create book instance form with a 'Create BookInstance' heading and four input fields labeled 'Book', 'Imprint', 'Date when book available' and 'Status'. The form is filled. There is a 'Submit' button at the bottom of the form.](/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_BookInstance_form/locallibary_express_bookinstance_create_empty.png)

Next steps
----------

* Return to Express Tutorial Part 6: Working with forms.
* Proceed to the next subarticle of part 6: Delete Author form.