Use backbone to write a book management system, front-end is using jquery + backbone + Boostrap, back-end is Node + Express + mysql

The front-end projects are in the webProject folder

The backend project is in the bookApi folder

Making: github.com/falco-tu/bo…

The interface is as follows:

Database table (ID, ISBN, book_name, book_cover, author)

Back-end Node + Express + mysql section

Create database bookdb, create table book, add field ID, ISBN, book_NAME, book_cover, author, Navicat Premium

Install express

Install Express globally
$ npm install express -g 

# Build project
$ express --view=pug bookApi

# Enter project/package
$ cdBookApi $NPM Install (or NPM I for short)Copy the code

Generate the following directory structure

Because the demand is relatively simple, only add, delete, change and check the interface, so the directory structure is modified. Delete the bin directory and organize app.js as follows

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var cors  = require('cors');
var bodyParser = require('body-parser')

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

// Introduce cORS to solve cross-domain problems
app.use(cors());

// Importing body-parser, we can get the request body from req.body
+ app.use(bodyParser.urlencoded({ extended: false }));
+ app.use(bodyParser.json());

/ / rewrite
+ var http = require('http');
+ var server = http.createServer(app);

app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

// book is the interface address used in this project. Users is automatically generated by Express. It is not used in this project and can be deleted
+ app.use('/book', indexRouter);
app.use('/users', usersRouter);

// Listen on port 3000
+ server.listen('3000');

// Comment out the export app. There is no need to export app
// module.exports = app;
Copy the code

Execution node app. Js, visit http://127.0.0.1:3000/book to see the project has run up

Connect to the database: create a new util folder at the same level as the app.js file, create a new dbconfig.js file under the folder, and import it here

const mysql = require('mysql');

module.exports = {
  // Database configuration
  config: {
    host: 'localhost'.port: '3306'.user: 'root'.password: ' '.// The password is your own
    database: 'bookdb'  // The name of the newly created database library
  },
  // Connect to database, use mysql connection pool connection mode
  sqlConnect: function (sql, sqlArr, callback) {
    let pool = mysql.createPool(this.config);
    pool.getConnection((err, conn) = >{
      if (err){
        console.log('Connection failed');
        return;
      }
      // event-driven callback
      conn.query(sql, sqlArr, callback);
      // Release the connectionconn.release(); }}})Copy the code

Rewrite the index.js file in the routes folder

// routes/index.js
var express = require('express');
var router = express.Router();
// Create a new controllers folder at the app.js level and create a new bookController.js file under that folder
var bookController = require('.. /controllers/bookController');

/* GET home page. */
router.get('/', bookController.getBookList);

router.post('/', bookController.createNewBook);

router.delete('/:id', bookController.deleteBook);

router.put('/:id', bookController.updateBook);

module.exports = router;
Copy the code

Perfect controllers/bookController. Js file

var dbConfig = require('.. /util/dbconfig')

// Get the list
getBookList = (req, res, next) = > {
  var sql = 'select * from book';
  var sqlArr = [];
  var callback = (err, data) = > {
    if (err) {
      console.log('Connection error')}else {
      res.send({
        'list': data
      })
    }
  }
  dbConfig.sqlConnect(sql, sqlArr, callback)
}

// Create a book
createNewBook = (req, res, next) = > {
  let {isbn, book_name, book_cover, author} = req.body;
  var sql = 'insert into book(isbn, book_name, book_cover, author) value(? ,? ,? ,?) ';
  var sqlArr = [isbn, book_name, book_cover, author];
  var callback = (err, data) = > {
    if (err) {
      console.log('Connection error')}else {
      res.send({
        id: data.insertId,
        isbn, book_name, book_cover, author
      })
    }
  }
  dbConfig.sqlConnect(sql, sqlArr, callback)
}

// Delete books
deleteBook = (req, res, next) = > {
  let {id} = req.params;
  var sql = 'delete from book where id=? ';
  var sqlArr = [id];
  var callback = (err, data) = > {
    if (err) {
      console.log('Connection error')}else {
      res.send({
        'status': 'OK'
      })
    }
  }
  dbConfig.sqlConnect(sql, sqlArr, callback)
}

// Modify the book
updateBook = (req, res, next) = > {
  let {isbn, book_name, book_cover, author} = req.body;
  let {id} = req.params;
  var sql = `update book set isbn=? , book_name=? , book_cover=? , author=? where id=${id}`;
  var sqlArr = [isbn, book_name, book_cover, author];
  var callback = (err, data) = > {
    if (err) {
      console.log('Connection error')}else {
      res.send({
        'status': 'OK'
      })
    }
  }
  dbConfig.sqlConnect(sql, sqlArr, callback)
};

module.exports = {
  getBookList,
  createNewBook,
  deleteBook,
  updateBook
};
Copy the code

That’s where the back end is, and then the front end

Front-end jquery + Backbone + Boostrap part

Directory structure:

Entry file index.html

<! doctypehtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="Width =device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <script src="js/lib/underscore.js"></script>
  <script src="js/lib/jquery.js"></script>
  <script src="js/lib/backbone.js"></script>
  <link rel="stylesheet" href="css/normalize.css">
  <link rel="stylesheet" href="css/bootstrap.min.css">
  <link rel="stylesheet" href="css/main.css">
  <title>Document</title>
</head>
<body>
<header>
  <span class="app-title">Library management system</span>
</header>

<! -- Book List page -->
<div id="bookListBox">
  <div class="btn-wrap">
    <span class="list-title">List of books</span>
    <a href="#create" type="button" class="btn btn-primary">The new books</a>
  </div>

  <div class="row" id="bookListContent">
    <! Here get the data render for the book list -->
  </div>
</div>

<! -- Add books page -->
<div id="createBook">
  <h3>The new books</h3>
  <form id="createBookForm">

  </form>
</div>

<! Edit the book page -->
<div id="editBook">
  <h3>Edit books</h3>
  <form id="editBookForm">

  </form>
</div>

<! -- Book List/Book Template -->
<script type="text/template" id="bookItemTemplate">
  <div class="col-sm-3 col-md-3">
    <div class="thumbnail" id="bookItem">
      <img src="<%= book_cover %>" class="book-cover">
      <div class="caption">
        <h4><%= book_name %></h4>
        <p><%= author %></p>
        <p><a href="#edit/<%= id %>" class="btn btn-primary" role="button">Modify the</a> <button class="btn btn-danger" id="btn-delete">delete</button></p>
      </div>
    </div>
  </div>
</script>

<! Edit book form -->
<script type="text/template" id="bookForm">
  <div class="form-group">
    <h4>ISBN:</h4>
    <input type="text" name="isbn" class="form-control" placeholder="ISBN" id="edit-isbn">
  </div>
  <div class="form-group">
    <h4>Title:</h4>
    <input type="text" name="book_name" class="form-control" placeholder="Title" id="edit-book-name">
  </div>
  <div class="form-group">
    <h4>The author:</h4>
    <input type="text" name="author" class="form-control" placeholder="The author" id="edit-author">
  </div>
  <div class="form-group">
    <h4>Cover:</h4>
    <input type="text" name="book_cover" class="form-control" placeholder="Cover" id="edit-cover">
  </div>
  <button id="btn-edit-save" class="btn btn-default">submit</button>
</script>

<script src="js/app/main.js"></script>
</body>
</html>
Copy the code

Style file CSS /main.css

body{
  background-color: #eee;
}

header{
  position: relative;
  width: 100%;
  height: 60px;
  z-index: 100;
  font-size: 18px;
  background: #fff;
  -webkit-box-shadow: 0 0 8px 0 rgba(0.0.0.1);
  box-shadow: 0 0 8px 0 rgba(0.0.0.1);
  padding: 0 140px 0 20px;
}

header .app-title{
  line-height: 60px;
  font-size: 20px;
}

#bookListBox.#createBook.#editBook{
  width: 90vw;
  min-height: 82vh;
  padding: 20px;
  margin: 40px auto;
  background-color: white;
}

#bookListBox .btn-wrap{
  display: flex;
  justify-content: space-between;
  margin-bottom: 20px;
}

#bookListBox .btn-wrap .list-title{
  font-size: 20px;
}

.thumbnail .book-cover{
  width: 100%;
  height: 170px;
  object-fit: cover;
}

#createBook h3.#editBook h3{
  margin-bottom: 20px;
}

.form-control{
  width: 40%;
}
Copy the code

The UI interface is complete, the interface + logic part is in js/app/main.js

Control page presentation through routing

// js/app/main.js

/ * * * * * * * * * * * * * * * * * * * base class * * * * * * * * * * * * * * * * * * * /
let BookPage = Backbone.View.extend({
  hide: function () {
    this.$el.hide()
  },
  show: function () {
    this.$el.show()
  }
});

/****************** main ********************/

// Book list page
let BookListPage = BookPage.extend({
  el: '#bookListBox',})// Add a book page
let CreateBookPage = BookPage.extend({
  el: '#createBook',})// Modify the books page
let EditBookPage = BookPage.extend({
  el: '#editBook',})let AppRouter = Backbone.Router.extend({
  initialize: function () {
    this.bookListPage = new BookListPage();
    this.createBookPage = new CreateBookPage();
    this.editBookPage = new EditBookPage();
  },
  routes: {
    'create': 'createBook'.'edit/:id': 'editBook'.' ': 'bookList',},bookList: function () {
    this.editBookPage.hide();
    this.createBookPage.hide();
    this.bookListPage.show();
  },
  createBook: function () {
    this.bookListPage.hide();
    this.editBookPage.hide();
    this.createBookPage.show();
  },
  editBook: function (id) {
    this.bookListPage.hide();
    this.createBookPage.hide();
    this.editBookPage.show(); }})// Create a routing instance
let app = new AppRouter();

// When all Routers are created and set, call backbone.history.start () to monitor hashchange events and assign routes
Backbone.history.start()
Copy the code

With the routing complete, start writing the data rendering section of the first page book list page

// js/app/main.js

/ * * * * * * * * * * * * * * * * * * * base class * * * * * * * * * * * * * * * * * * * /
let BookPage = Backbone.View.extend({
  hide: function () {
    this.$el.hide()
  },
  show: function () {
    this.$el.show()
  }
});

+let BaseModel = Backbone.Model.extend({
+  api: ' ',
+  // Set the default URL function that generates model ID-based URLs by specifying urlRoot
+  urlRoot: function () {+return 'http://127.0.0.1:3000/' + this.api; + +}}); +let BaseCollection = Backbone.Collection.extend({
+  // Sets the URL property (or function) to specify the server location for the collection
+  url: function () {+return 'http://127.0.0.1:3000/' + this.model.prototype.api; + +}Parse is called each time fetch is called to pull the collection's model data from the server
+  parse: function (res, options) {+return res.list; List: [{}, {}, {}]+ +}})/****************** main ********************/

+let BookModel = BaseModel.extend({
+  api: 'book', + +})let BookCollection = BaseCollection.extend({
+  model: BookModel,
+})

+let BookItemView = Backbone.View.extend({
+  // Template render using underscore
+  _template: _.template($('#bookItemTemplate').html()),
+  // Listen for the Model change and Destroy events and execute the corresponding methods
+  initialize: function () {+this.listenTo(this.model, 'destroy'.this.remove);
+    this.listenTo(this.model, 'change'.this.render);
+  },
+  events: {
+    'click #btn-delete': 'handleDelete'
+  },
+  render: function () {+let json = this.model.toJSON();
+    this.$el.html(this._template(json));
+    return this;
+  },
+  handleDelete: function (e) {
+    e.preventDefault();
+    this.model.destroy(); + +}}); +let BookCollectionView = Backbone.View.extend({
+  subView: BookItemView,
+  initialize: function () {+this.listenTo(this.collection, 'reset'.this.render);
+    this.listenTo(this.collection, 'add'.this.addOneBook);
+    this._views = []
+  },
+  createSubView: function (model) {+let viewClass = this.subView || Backbone.View;
+    let v = new viewClass({model: model}); // Create subclasses of each book and bind model
+    this._views.push(v);
+    returnv; + +}// Add each book to the book List view
+  addOneBook: function (model) {+this.$el.append(this.createSubView(model).render().$el)
+  },
+  // Clear the data in views and iterate over the collection of books
+  render: function () {
+    _.each(this._views, function (itemView) { + itemView.remove().off(); +}); +this._views = [];
+    if (!this.collection) return this;
+    this.collection.each((model) = >{+this.addOne(model); +}); +}, +})// Book list page
let BookListPage = BookPage.extend({
  el: '#bookListBox',
+ // Instance initialization, request book list via GET, reset collection and render view
+ initialize: function () {+this.bookCollection = new BookCollection();
+   this.bookCollectionView = new BookCollectionView({
+     collection: this.bookCollection,
+     el: '#bookListContent'+ +})this.bookCollection.fetch({reset: true}); +}})// Add a book page
let CreateBookPage = BookPage.extend({
  el: '#createBook',})// Modify the books page
let EditBookPage = BookPage.extend({
  el: '#editBook',})let AppRouter = Backbone.Router.extend({
  initialize: function () {
    this.bookListPage = new BookListPage();
    this.createBookPage = new CreateBookPage();
    this.editBookPage = new EditBookPage();
  },
  routes: {
    'create': 'createBook'.'edit/:id': 'editBook'.' ': 'bookList',},bookList: function () {
    this.editBookPage.hide();
    this.createBookPage.hide();
    this.bookListPage.show();
  },
  createBook: function () {
    this.bookListPage.hide();
    this.editBookPage.hide();
    this.createBookPage.show();
  },
  editBook: function (id) {
    this.bookListPage.hide();
    this.createBookPage.hide();
    this.editBookPage.show(); }})// Create a routing instance
let app = new AppRouter();

// When all Routers are created and set, call backbone.history.start () to monitor hashchange events and assign routes
Backbone.history.start()
Copy the code

List display page completed, continue to complete the new book page

// js/app/main.js

/ * * * * * * * * * * * * * * * * * * * base class * * * * * * * * * * * * * * * * * * * /
let BookPage = Backbone.View.extend({
  hide: function () {
    this.$el.hide()
  },
  show: function () {
    this.$el.show()
  }
});

let BaseModel = Backbone.Model.extend({
  api: ' '.// Set the default URL function that generates model ID-based URLs by specifying urlRoot
  urlRoot: function () {
    return 'http://127.0.0.1:3000/' + this.api; }});let BaseCollection = Backbone.Collection.extend({
  // Sets the URL property (or function) to specify the server location for the collection
  url: function () {
    return 'http://127.0.0.1:3000/' + this.model.prototype.api;
  },
  Parse is called each time fetch is called to pull the collection's model data from the server
  parse: function (res, options) {
    return res.list; List: [{}, {}, {}]}})/****************** main ********************/

let BookModel = BaseModel.extend({
  api: 'book',})let BookCollection = BaseCollection.extend({
  model: BookModel,
})

let BookItemView = Backbone.View.extend({
  // Template render using underscore
  _template: _.template($('#bookItemTemplate').html()),
  // Listen for the Model change and Destroy events and execute the corresponding methods
  initialize: function () { 
    this.listenTo(this.model, 'destroy'.this.remove);
    this.listenTo(this.model, 'change'.this.render);
  },
  events: {
    'click #btn-delete': 'handleDelete'
  },
  render: function () {
    let json = this.model.toJSON();
    this.$el.html(this._template(json));
    return this;
  },
  handleDelete: function (e) {
    e.preventDefault();
    this.model.destroy(); }});let BookCollectionView = Backbone.View.extend({
  subView: BookItemView,
  initialize: function () {
    this.listenTo(this.collection, 'reset'.this.render);
    this.listenTo(this.collection, 'add'.this.addOneBook);
    this._views = []
  },
  createSubView: function (model) {
    let viewClass = this.subView || Backbone.View;
    let v = new viewClass({model: model}); // Create subclasses of each book and bind model
    this._views.push(v);
    return v;
  },
  // Add each book to the book List view
  addOneBook: function (model) {
    this.$el.append(this.createSubView(model).render().$el)
  },
  // Clear the data in views and iterate over the collection of books
  render: function () {
    _.each(this._views, function (itemView) {
      itemView.remove().off();
    });
    this._views = [];
    if (!this.collection) return this;
    this.collection.each((model) = > {
      this.addOne(model); }); }})// Book list page
let BookListPage = BookPage.extend({
  el: '#bookListBox'.// Instance initialization, request book list via GET, reset collection and render view
  initialize: function () {
    this.bookCollection = new BookCollection();
    this.bookCollectionView = new BookCollectionView({
      collection: this.bookCollection,
      el: '#bookListContent'
    })
    this.bookCollection.fetch({reset: true}); }})// Common form components
+let BookFormPage = BookPage.extend({
+  template: _.template($('#bookForm').html()),
+  _initialize: function (options) {+this.router = options.router;
+    this.collection = options.collection || [];
+    this.model = options.model || {};
+    this.$el.html(this.template({}))
+  },
+  events: {
+    'click #btn-edit-save': 'handleEdit',
+  },
+  handleEdit: function (e) {
+    e.preventDefault();
+    let bookInfo = this.$el.serializeArray();
+    let data = {};
+    bookInfo.forEach(item= > {
+      data[item.name] = item.value
+    })
+    let currentRoute = Backbone.history.getFragment();
+    if (currentRoute === 'create') {  / / new
+      let newBook = new BookModel(data)
+      // Use the create method of the collection to add the data to the database and return the data to the front page
+      this.collection.create(newBook, {wait: true})
+      this.router.navigate(' ', {trigger: true}) +} +} +})// Add a book page
let CreateBookPage = BookPage.extend({
  el: '#createBook',
+ initialize: function (options) {+this.render(options)
+ },
+ render: function (options) {+// Mount the form to the node with id createBookForm
+   let formPage = new BookFormPage({
+     el: '#createBookForm'
+   })
+   formPage._initialize(options)
+ },
})

// Modify the books page
let EditBookPage = BookPage.extend({
  el: '#editBook',})let AppRouter = Backbone.Router.extend({
  initialize: function () {
    this.bookListPage = new BookListPage();
    this.createBookPage = new CreateBookPage({
+     router: this,
+     collection: this.bookListPage.bookCollection
    });
    this.editBookPage = new EditBookPage();
  },
  routes: {
    'create': 'createBook'.'edit/:id': 'editBook'.' ': 'bookList',},bookList: function () {
    this.editBookPage.hide();
    this.createBookPage.hide();
    this.bookListPage.show();
  },
  createBook: function () {
    this.bookListPage.hide();
    this.editBookPage.hide();
    this.createBookPage.show();
  },
  editBook: function (id) {
    this.bookListPage.hide();
    this.createBookPage.hide();
    this.editBookPage.show(); }})// Create a routing instance
let app = new AppRouter();

// When all Routers are created and set, call backbone.history.start () to monitor hashchange events and assign routes
Backbone.history.start()
Copy the code

The following is the section on modifying the book page

// js/app/main.js

/ * * * * * * * * * * * * * * * * * * * base class * * * * * * * * * * * * * * * * * * * /
let BookPage = Backbone.View.extend({
  hide: function () {
    this.$el.hide()
  },
  show: function () {
    this.$el.show()
  }
});

let BaseModel = Backbone.Model.extend({
  api: ' '.// Set the default URL function that generates model ID-based URLs by specifying urlRoot
  urlRoot: function () {
    return 'http://127.0.0.1:3000/' + this.api; }});let BaseCollection = Backbone.Collection.extend({
  // Sets the URL property (or function) to specify the server location for the collection
  url: function () {
    return 'http://127.0.0.1:3000/' + this.model.prototype.api;
  },
  Parse is called each time fetch is called to pull the collection's model data from the server
  parse: function (res, options) {
    return res.list; List: [{}, {}, {}]}})/****************** main ********************/

let BookModel = BaseModel.extend({
  api: 'book',})let BookCollection = BaseCollection.extend({
  model: BookModel,
})

let BookItemView = Backbone.View.extend({
  // Template render using underscore
  _template: _.template($('#bookItemTemplate').html()),
  // Listen for the Model change and Destroy events and execute the corresponding methods
  initialize: function () { 
    this.listenTo(this.model, 'destroy'.this.remove);
    this.listenTo(this.model, 'change'.this.render);
  },
  events: {
    'click #btn-delete': 'handleDelete'
  },
  render: function () {
    let json = this.model.toJSON();
    this.$el.html(this._template(json));
    return this;
  },
  handleDelete: function (e) {
    e.preventDefault();
    this.model.destroy(); }});let BookCollectionView = Backbone.View.extend({
  subView: BookItemView,
  initialize: function () {
    this.listenTo(this.collection, 'reset'.this.render);
    this.listenTo(this.collection, 'add'.this.addOneBook);
    this._views = []
  },
  createSubView: function (model) {
    let viewClass = this.subView || Backbone.View;
    let v = new viewClass({model: model}); // Create subclasses of each book and bind model
    this._views.push(v);
    return v;
  },
  // Add each book to the book List view
  addOneBook: function (model) {
    this.$el.append(this.createSubView(model).render().$el)
  },
  // Clear the data in views and iterate over the collection of books
  render: function () {
    _.each(this._views, function (itemView) {
      itemView.remove().off();
    });
    this._views = [];
    if (!this.collection) return this;
    this.collection.each((model) = > {
      this.addOne(model); }); }})// Book list page
let BookListPage = BookPage.extend({
  el: '#bookListBox'.// Instance initialization, request book list via GET, reset collection and render view
  initialize: function () {
    this.bookCollection = new BookCollection();
    this.bookCollectionView = new BookCollectionView({
      collection: this.bookCollection,
      el: '#bookListContent'
    })
    this.bookCollection.fetch({reset: true}); }})// Common form components
let BookFormPage = BookPage.extend({
  template: _.template($('#bookForm').html()),
  _initialize: function (options) {
    this.router = options.router;
    this.collection = options.collection || [];
    this.model = options.model || {};
    this.$el.html(this.template({}))
  },
  events: {
    'click #btn-edit-save': 'handleEdit',},handleEdit: function (e) {
    e.preventDefault();
    let bookInfo = this.$el.serializeArray();
    let data = {};
    bookInfo.forEach(item= > {
      data[item.name] = item.value
    })
    let currentRoute = Backbone.history.getFragment();
+   let [editRoute, id] = currentRoute.split('/')
    if (currentRoute === 'create') {  / / new
      let newBook = new BookModel(data)
      // Use the create method of the collection to add the data to the database and return the data to the front page
      this.collection.create(newBook, {wait: true})
      this.router.navigate(' ', {trigger: true+}})else if (editRoute === 'edit' && Number(id) === this.model.id) {  / / modify
+     this.model.set(data);
+     this.model.save();
+     this.router.navigate(' ', {trigger: true}}}})// Add a book page
let CreateBookPage = BookPage.extend({
  el: '#createBook'.initialize: function (options) {
    this.render(options)
  },
  render: function (options) {
    // Mount the form to the node with id createBookForm
    let formPage = new BookFormPage({
      el: '#createBookForm'
    })
    formPage._initialize(options)
  },
})

// Modify the books page
let EditBookPage = BookPage.extend({
  el: '#editBook',
+ initialize: function (options) {+this.router = options.router;
+ },
+ show: function (book) {+if (book) {
+     this.model = book;
+     this.render()
+   }
+   this.$el.show();
+ },
+ render: function () {+let formPage = new BookFormPage({
+     el: '#editBookForm'
+   })
+   formPage._initialize({router: this.router, model: this.model})
+   let json = this.model.toJSON();
+   let editBookForm = $('#editBookForm');
+   editBookForm.find('#edit-isbn').val(json.isbn);
+   editBookForm.find('#edit-book-name').val(json.book_name);
+   editBookForm.find('#edit-author').val(json.author);
+   editBookForm.find('#edit-cover').val(json.book_cover); +}})let AppRouter = Backbone.Router.extend({
  initialize: function () {
    this.bookListPage = new BookListPage();
    this.createBookPage = new CreateBookPage({
      router: this.collection: this.bookListPage.bookCollection
    });
    this.editBookPage = new EditBookPage({
+     router: this
    });
  },
  routes: {
    'create': 'createBook'.'edit/:id': 'editBook'.' ': 'bookList',},bookList: function () {
    this.editBookPage.hide();
    this.createBookPage.hide();
    this.bookListPage.show();
  },
  createBook: function () {
    this.bookListPage.hide();
    this.editBookPage.hide();
    this.createBookPage.show();
  },
  editBook: function (id) {
    this.bookListPage.hide();
    this.createBookPage.hide();
+   let book = this.bookListPage.bookCollection.find(function (model) {+return model.id === Number(id); + +})this.editBookPage.show(book); }})// Create a routing instance
let app = new AppRouter();

// When all Routers are created and set, call backbone.history.start () to monitor hashchange events and assign routes
Backbone.history.start()
Copy the code