Làm cách nào để tạo một mẫu đặt phòng trong HTML?

Bài viết con này chỉ ra cách xác định một trang/biểu mẫu để tạo các đối tượng Book. Điều này phức tạp hơn một chút so với các trang Author hoặc Genre tương đương vì chúng tôi cần lấy và hiển thị các bản ghi AuthorGenre có sẵn trong biểu mẫu Book của chúng tôi

Mở /bộ điều khiển/bookController. js và thêm dòng sau vào đầu tệp

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

Tìm phương thức bộ điều khiển

// Display book create form on GET.
exports.book_create_get = (req, res, next) => {
  // Get all authors and genres, which we can use for adding to our book.
  async.parallel(
    {
      authors(callback) {
        Author.find(callback);
      },
      genres(callback) {
        Genre.find(callback);
      },
    },
    (err, results) => {
      if (err) {
        return next(err);
      }
      res.render("book_form", {
        title: "Create Book",
        authors: results.authors,
        genres: results.genres,
      });
    }
  );
};
3 đã xuất và thay thế bằng mã sau

// Display book create form on GET.
exports.book_create_get = (req, res, next) => {
  // Get all authors and genres, which we can use for adding to our book.
  async.parallel(
    {
      authors(callback) {
        Author.find(callback);
      },
      genres(callback) {
        Genre.find(callback);
      },
    },
    (err, results) => {
      if (err) {
        return next(err);
      }
      res.render("book_form", {
        title: "Create Book",
        authors: results.authors,
        genres: results.genres,
      });
    }
  );
};

Điều này sử dụng mô-đun async (được mô tả trong Hướng dẫn cấp tốc Phần 5. Hiển thị dữ liệu thư viện) để lấy tất cả các đối tượng AuthorGenre. Sau đó, chúng được chuyển đến chế độ xem

// Display book create form on GET.
exports.book_create_get = (req, res, next) => {
  // Get all authors and genres, which we can use for adding to our book.
  async.parallel(
    {
      authors(callback) {
        Author.find(callback);
      },
      genres(callback) {
        Genre.find(callback);
      },
    },
    (err, results) => {
      if (err) {
        return next(err);
      }
      res.render("book_form", {
        title: "Create Book",
        authors: results.authors,
        genres: results.genres,
      });
    }
  );
};
6 dưới dạng các biến có tên là
// Display book create form on GET.
exports.book_create_get = (req, res, next) => {
  // Get all authors and genres, which we can use for adding to our book.
  async.parallel(
    {
      authors(callback) {
        Author.find(callback);
      },
      genres(callback) {
        Genre.find(callback);
      },
    },
    (err, results) => {
      if (err) {
        return next(err);
      }
      res.render("book_form", {
        title: "Create Book",
        authors: results.authors,
        genres: results.genres,
      });
    }
  );
};
7 và
// Display book create form on GET.
exports.book_create_get = (req, res, next) => {
  // Get all authors and genres, which we can use for adding to our book.
  async.parallel(
    {
      authors(callback) {
        Author.find(callback);
      },
      genres(callback) {
        Genre.find(callback);
      },
    },
    (err, results) => {
      if (err) {
        return next(err);
      }
      res.render("book_form", {
        title: "Create Book",
        authors: results.authors,
        genres: results.genres,
      });
    }
  );
};
8 (cùng với trang
// Display book create form on GET.
exports.book_create_get = (req, res, next) => {
  // Get all authors and genres, which we can use for adding to our book.
  async.parallel(
    {
      authors(callback) {
        Author.find(callback);
      },
      genres(callback) {
        Genre.find(callback);
      },
    },
    (err, results) => {
      if (err) {
        return next(err);
      }
      res.render("book_form", {
        title: "Create Book",
        authors: results.authors,
        genres: results.genres,
      });
    }
  );
};
9)

Tìm phương thức bộ điều khiển

// 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.
  (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.
      async.parallel(
        {
          authors(callback) {
            Author.find(callback);
          },
          genres(callback) {
            Genre.find(callback);
          },
        },
        (err, results) => {
          if (err) {
            return next(err);
          }

          // Mark our selected genres as checked.
          for (const genre of results.genres) {
            if (book.genre.includes(genre._id)) {
              genre.checked = "true";
            }
          }
          res.render("book_form", {
            title: "Create Book",
            authors: results.authors,
            genres: results.genres,
            book,
            errors: errors.array(),
          });
        }
      );
      return;
    }

    // Data from form is valid. Save book.
    book.save((err) => {
      if (err) {
        return next(err);
      }
      // Successful: redirect to new book record.
      res.redirect(book.url);
    });
  },
];
0 đã xuất và thay thế bằng mã sau

// 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.
  (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.
      async.parallel(
        {
          authors(callback) {
            Author.find(callback);
          },
          genres(callback) {
            Genre.find(callback);
          },
        },
        (err, results) => {
          if (err) {
            return next(err);
          }

          // Mark our selected genres as checked.
          for (const genre of results.genres) {
            if (book.genre.includes(genre._id)) {
              genre.checked = "true";
            }
          }
          res.render("book_form", {
            title: "Create Book",
            authors: results.authors,
            genres: results.genres,
            book,
            errors: errors.array(),
          });
        }
      );
      return;
    }

    // Data from form is valid. Save book.
    book.save((err) => {
      if (err) {
        return next(err);
      }
      // Successful: redirect to new book record.
      res.redirect(book.url);
    });
  },
];

Cấu trúc và hành vi của mã này gần giống hệt như để tạo một đối tượng Genre hoặc Author. Trước tiên, chúng tôi xác thực và vệ sinh dữ liệu. Nếu dữ liệu không hợp lệ thì chúng tôi hiển thị lại biểu mẫu cùng với dữ liệu ban đầu được nhập bởi người dùng và danh sách các thông báo lỗi. Nếu dữ liệu hợp lệ, thì chúng tôi sẽ lưu bản ghi Book mới và chuyển hướng người dùng đến trang chi tiết sách

Sự khác biệt chính đối với mã xử lý biểu mẫu khác là cách chúng tôi làm sạch thông tin thể loại. Biểu mẫu trả về một mảng gồm Genre mục (trong khi đối với các trường khác, biểu mẫu trả về một chuỗi). Để xác thực thông tin, trước tiên chúng tôi chuyển đổi yêu cầu thành một mảng (bắt buộc cho bước tiếp theo)

[
  // 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();
  },
  // …
];

Sau đó, chúng tôi sử dụng ký tự đại diện (_______7_______5) trong trình khử trùng để xác thực riêng từng mục trong mảng thể loại. Mã bên dưới cho biết cách thức - điều này có nghĩa là "khử trùng mọi mục bên dưới khóa

// 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.
  (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.
      async.parallel(
        {
          authors(callback) {
            Author.find(callback);
          },
          genres(callback) {
            Genre.find(callback);
          },
        },
        (err, results) => {
          if (err) {
            return next(err);
          }

          // Mark our selected genres as checked.
          for (const genre of results.genres) {
            if (book.genre.includes(genre._id)) {
              genre.checked = "true";
            }
          }
          res.render("book_form", {
            title: "Create Book",
            authors: results.authors,
            genres: results.genres,
            book,
            errors: errors.array(),
          });
        }
      );
      return;
    }

    // Data from form is valid. Save book.
    book.save((err) => {
      if (err) {
        return next(err);
      }
      // Successful: redirect to new book record.
      res.redirect(book.url);
    });
  },
];
6"

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

Sự khác biệt cuối cùng đối với mã xử lý biểu mẫu khác là chúng ta cần chuyển tất cả các thể loại và tác giả hiện có vào biểu mẫu. Để đánh dấu các thể loại đã được người dùng kiểm tra, chúng tôi lặp qua tất cả các thể loại và thêm tham số

// 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.
  (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.
      async.parallel(
        {
          authors(callback) {
            Author.find(callback);
          },
          genres(callback) {
            Genre.find(callback);
          },
        },
        (err, results) => {
          if (err) {
            return next(err);
          }

          // Mark our selected genres as checked.
          for (const genre of results.genres) {
            if (book.genre.includes(genre._id)) {
              genre.checked = "true";
            }
          }
          res.render("book_form", {
            title: "Create Book",
            authors: results.authors,
            genres: results.genres,
            book,
            errors: errors.array(),
          });
        }
      );
      return;
    }

    // Data from form is valid. Save book.
    book.save((err) => {
      if (err) {
        return next(err);
      }
      // Successful: redirect to new book record.
      res.redirect(book.url);
    });
  },
];
7 vào những thể loại có trong dữ liệu bài đăng của chúng tôi (như được sao chép trong đoạn mã bên dưới)

// Mark our selected genres as checked.
for (const genre of results.genres) {
  if (book.genre.includes(genre._id)) {
    // Current genre is selected. Set "checked" flag.
    genre.checked = "true";
  }
}

Tạo /views/book_form. pug và sao chép trong văn bản dưới đây

extends layout

block content
  h1= title

  form(method='POST' action='')
    div.form-group
      label(for='title') Title:
      input#title.form-control(type='text', placeholder='Name of book' name='title' required='true' value=(undefined===book ? '' : book.title) )
    div.form-group
      label(for='author') Author:
      select#author.form-control(type='select', placeholder='Select author' name='author' required='true' )
        - authors.sort(function(a, b) {let textA = a.family_name.toUpperCase(); let textB = b.family_name.toUpperCase(); return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;});
        for author in authors
          if book
            option(value=author._id selected=(author._id.toString()===book.author._id.toString() ? 'selected' : false) ) #{author.name}
          else
            option(value=author._id) #{author.name}
    div.form-group
      label(for='summary') Summary:
      textarea#summary.form-control(type='textarea', placeholder='Summary' name='summary' required='true') #{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='true')
    div.form-group
      label Genre:
      div
        for genre in genres
          div(style='display: inline; padding-right:10px;')
            input.checkbox-input(type='checkbox', name='genre', id=genre._id, value=genre._id, checked=genre.checked )
            label(for=genre._id) #{genre.name}
    button.btn.btn-primary(type='submit') Submit

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

Cấu trúc và hành vi xem gần giống như đối với thể loại_form. mẫu pug

Sự khác biệt chính là cách chúng tôi triển khai các trường loại lựa chọn. AuthorGenre

  • Tập hợp các thể loại được hiển thị dưới dạng các hộp kiểm, sử dụng giá trị
    [
      // 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();
      },
      // …
    ];
    
    0 mà chúng tôi đã đặt trong bộ điều khiển để xác định xem có nên chọn hộp đó hay không
  • Tập hợp các tác giả được hiển thị dưới dạng danh sách thả xuống được sắp xếp theo thứ tự bảng chữ cái lựa chọn duy nhất. Nếu trước đó người dùng đã chọn một tác giả sách (i. e. khi sửa các giá trị trường không hợp lệ sau khi gửi biểu mẫu ban đầu hoặc khi cập nhật chi tiết sách), tác giả sẽ được chọn lại khi biểu mẫu được hiển thị. Ở đây, chúng tôi xác định tác giả nào sẽ chọn bằng cách so sánh id của tùy chọn tác giả hiện tại với giá trị được người dùng nhập trước đó (được chuyển qua biến
    [
      // 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();
      },
      // …
    ];
    
    1). Điều này được nhấn mạnh ở trên

    Ghi chú. Nếu có lỗi trong biểu mẫu đã gửi, thì khi biểu mẫu được hiển thị lại, id của tác giả cuốn sách mới và id tác giả của những cuốn sách hiện có thuộc loại

    [
      // 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();
      },
      // …
    ];
    
    2. Vì vậy, để so sánh chúng, trước tiên chúng ta phải chuyển đổi chúng thành chuỗi

Chạy ứng dụng, mở trình duyệt của bạn đến

[
  // 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();
  },
  // …
];
3, sau đó chọn liên kết Tạo sách mới. Nếu mọi thứ được thiết lập chính xác, trang web của bạn sẽ trông giống như ảnh chụp màn hình sau. Sau khi bạn gửi một cuốn sách hợp lệ, cuốn sách đó sẽ được lưu và bạn sẽ được đưa đến trang chi tiết cuốn sách

Làm cách nào để tạo một hệ thống đặt phòng trong HTML?

.

Một hình thức đặt phòng trên một trang web là gì?

Tổng quan. Mẫu đăng ký cho phép Khách hàng đăng ký Dịch vụ của bạn . Họ điền thông tin, chọn Dịch vụ họ muốn và đặt hàng. Bạn có thể thêm mẫu đặt phòng vào trang web của mình bằng cách. Nhúng Mẫu đăng ký vào một trang trên trang web của bạn.

Những gì nên được trên một hình thức đặt phòng?

Những gì nên được trên một hình thức đặt phòng?