sequelize 创建表_使用Sequelize创建AngularJS应用程序-第2部分

sequelize 创建表

This is the second part of a three-part series on building an angularJS application with Sequelize broken down as follows.

这是一个由三部分组成的系列文章的第二部分,该系列文章使用Sequelize分解了以下内容,从而构建了angularJS应用程序。

了解我们的前端结构 ( Understanding Our Frontend Structure )

Just like we did in the server directory , we will need to set up a few things for our frontend.

就像我们在服务器目录中所做的一样,我们需要为前端设置一些设置。

Our images, stylesheets, scripts and jade files will be in the app directory. We will then add gulp tasks to compile and minify the files to a public directory which will serve our application on the browser.

我们的图像,样式表,脚本和Jade文件将位于app目录中。 然后,我们将添加gulp任务以将文件编译并缩小到一个公共目录,该目录将在浏览器中为我们的应用程序提供服务。

├── index.js
├── gulpfile.js
├── package.json
├── bower.json
├── .bowerrc
├── .sequelizerc
├── app/
    ├── images/
    ├── js/
        ├── controllers/
        ├── directives/
        ├── filters/
        ├── services/
    ├── styles/
    ├── views/
    ├── app.js
    ├── index.jade
├── public
    ├── images/
    ├── js/
        ├── index.js
    ├── css/
        ├── app.css
    ├── views/
    ├── index.html
├── server
    ├── ...

将路由重构为路由文件 ( Refactor Routes To Routes File )

Currently, we have clogged up our /index.js with routes to our API. Let's refactor the routes into a routes file.

目前,我们已经使用到API的路由来阻塞/index.js 。 让我们将路由重构到路由文件中。

server/routes/index.js

服务器/路由/index.js

var authors = require('../controllers/authors'),
  books = require('../controllers/books');

module.exports = function (router) {
  router.get('/authors', authors.index);
  router.get('/authors/:id', authors.show);
  router.post('/authors', authors.create);
  router.put('/authors', authors.update);
  router.delete('/authors/:id', authors.delete);

  router.get('/books', books.index);
  router.get('/books/:id', books.show);
  router.post('/books', books.create);
  router.put('/books/:id', books.update);
  router.delete('/books/:id', books.delete);

  return router
};

Our index.js file is now much cleaner and does not handle any routes logic.

现在,我们的index.js文件更加整洁,并且不处理任何路由逻辑。

index.js

index.js

var express = require('express'),
  routes = require('./server/routes')
  bodyParser = require('body-parser');

var app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(process.cwd() + '/public'));

//App routes
app.use(routes(express.Router()));

app.get('/*', function (req, res) {
  res.sendFile('index.html', {
    root: './public'
  });
});

app.set('port', process.env.PORT || 8000);
app.listen(app.get('port'), function () {
  console.log("Magic happens on port", app.get('port'));
});

设置前端 ( Setting Up The Front End )

In this section, we will accomplish the following.

在本节中,我们将完成以下任务。

  • Add an entry index.jade and include head and footer layouts.

    添加一个条目index.jade,包括页脚的布局。
  • Add gulp tasks to automate the frontend workflow we discussed above.

    添加gulp任务以自动化我们上面讨论的前端工作流。
  • Update .bowerrc file to automatically inject installed packages to our html layout.

    更新.bowerrc文件,以自动将已安装的软件包注入我们的html布局。

添加index.jade (Add index.jade)

Being a Single Page Application (SPA), Bookmark will be served from a single entry file /public/index.html . Let's go ahead and setup the corresponding app/index.jade.

作为单页应用程序 (SPA),将从单个条目文件/public/index.html提供书签 。 让我们继续并设置相应的app / index.jade

/app/index.jade

/app/index.jade

doctype html
html(lang="en")
  head
    title bookmark app
    include views/layouts/head
  body(layout="row" ng-app="Bookmark")
    include views/layouts/footer

/app/views/layouts/head.jade

/app/views/layouts/head.jade

meta(charset="utf-8")
meta(http-equiv="X-UA-Compatible" content="IE=edge")
meta(name="description" content="")
meta(name='HandheldFriendly' content='True')
meta(name='MobileOptimized' content='320')
meta(name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no')

base(href="/")

// CDN provided
link(rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:400,100,100italic,300,300italic,400italic,500,500italic,700,700italic,900,900italic" type="text/css")
link(rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" type="text/css")

// bower:css
// endbower

// inject:css
// endinject

/app/views/layouts/footer.jade

/app/views/layouts/footer.jade

// bower:js
// endbower

// inject:js
// endinject

We will be using wiredep and gulp-inject packages to inject the included files in the right order of dependencies automatically as they are installed as is demonstrated in this short video.

我们将使用wiredepwiredep gulp-inject软件包在安装时自动按照正确的依赖性顺序注入包含的文件,如本短片所示。

添加Gulp任务 (Adding The Gulp Tasks)

Adding gulp tasks is a very crucial point in our application development process. Without our gulpfile, all the code we write is never compiled into our public directory which serves our application on the user's browsers.

在我们的应用程序开发过程中,添加gulp任务是非常关键的一点。 没有gulpfile,我们编写的所有代码都不会编译到我们的公共目录中,该目录在用户的浏览器上为我们的应用程序提供服务。

Go ahead and install the packages below as dev dependencies and update your gulpfile.

继续并安装以下软件包作为dev依赖项并更新gulpfile。

npm install --save-dev gulp gulp-jade gulp-less wiredep gulp-inject gulp-concat gulp-uglify gulp-bower gulp-nodemon gulp-plumber gulp-cssmin

This maybe overwhelming if you are not familiar with gulp tasks, take some time to read through automating tasks with gulp.

如果您不熟悉gulp任务,这可能会令人不知所措,请花一些时间阅读使用gulp自动化任务

/gulpfile.js

/gulpfile.js

var gulp = require ( 'gulp' ) ,
  jade = require ( 'gulp-jade' ) ,
  less = require ( 'gulp-less' ) ,
  wiredep = require ( 'wiredep' ) . stream ,
  gulpinject = require ( 'gulp-inject' )
  concat = require ( 'gulp-concat' ) ,
  uglify = require ( 'gulp-uglify' ) ,
  bower = require ( 'gulp-bower' ) ,
  nodemon = require ( 'gulp-nodemon' ) ,
  plumber = require ( 'gulp-plumber' ) ,
  cssmin = require ( 'gulp-cssmin' ) ,
  mocha = require ( 'gulp-mocha' ) ,
  istanbul = require ( 'gulp-istanbul' ) ,
  karma = require ( 'karma' ) . Server ,
  path = require ( 'path' ) ;

//Paths to watch for changes using the watch task.
var paths = {
  jade : 'app/**/*.jade' ,
  index : 'public/index.html' ,
  images : [ 'app/images/**/*' ] ,
  scripts : {
    js : './public/js/index.js' ,
    css : './public/css/*.css'
  } ,
  compileScripts : {
    js : [ 'app/app.js' , 'app/js/**/*.js' ] ,
    css : 'app/styles/*.+(less|css)'
  } ,
  serverTests : [
    'test/server/**/*.js'
  ] ,
  serverScripts : [
    'server/controllers/*.js'
  ]
} ;

//Compile Jade files to html and save them into the public directory.
gulp . task ( 'jade:compile' , function ( ) {
  gulp . src ( paths . jade )
    . pipe ( jade ( {
      pretty : true
    } ) )
    . pipe ( gulp . dest ( './public' ) ) ;
} ) ;

/ / Concatinate js into index . js , minify and save in public / js .
gulp . task ( 'js:minify' , function ( ) {
  gulp . src ( paths . compileScripts . js )
    . pipe ( concat ( 'index.js' ) )
    . pipe ( uglify ( ) )
    . pipe ( gulp . dest ( './public/js/' ) ) ;
} ) ;

/ / Concatinate custom css into styles . css , minify and save in public / css .
gulp . task ( 'css:minify' , function ( ) {
  gulp . src ( paths . compileScripts . css )
    . pipe ( less ( {
      paths : [ path . join ( __dirname , 'styles' ) ]
    } ) )
    . pipe ( concat ( 'styles.css' ) )
    . pipe ( cssmin ( ) )
    . pipe ( plumber ( ) )
    . pipe ( gulp . dest ( './public/css' ) ) ;
} ) ;

/ / Copy the images folder from app to public recursively
gulp . task ( 'copy:images' , function ( ) {
  gulp . src ( paths . images )
    . pipe ( gulp . dest ( './public/images' ) ) ;
} ) ;

/ / Run bower install .
gulp . task ( 'bower:run' , function ( ) {
  bower ( ) ;
} ) ;

/ / Inject bower scripts and custom scripts into / public / index . html .
gulp . task ( 'scripts:inject' , [ 'jade:compile' ] , function ( ) {
  gulp . src ( paths . index )
    . pipe ( wiredep ( ) )
    . pipe ( gulpinject ( gulp . src ( paths . scripts . js ) , { relative : true } ) )
    . pipe ( gulpinject ( gulp . src ( paths . scripts . css ) , { relative : true } ) )
    . pipe ( gulp . dest ( './public/' ) ) ;
} ) ;

/ / Rn nodemon .
gulp . task ( 'nodemon:run' , function ( ) {
  nodemon ( {
    script : 'index.js' ,
    ext : 'js html' ,
    ignore : [ 'public/**' , 'app/**' , 'node_modules/**' ]
  } ) ;
} ) ;

gulp . task ( 'test:client' , function ( done ) {
  new karma ( {
    configFile : __dirname + '/karma.conf.js'
  } , done ) . start ( ) ;
} ) ;

//Run the server tests and generate coverage reports
gulp . task ( 'test:server' , [ 'test:server:coverage' ] , function ( done ) {
  gulp . src ( paths . serverTests )
    . pipe ( mocha ( ) )
    . pipe ( istanbul . writeReports ( {
      dir : './coverage/server' ,
      reporters : [ 'lcov' , 'json' , 'text' , 'text-summary' ]
    } ) ) ;
} ) ;

gulp . task ( 'test:server:coverage' , function ( ) {
  gulp . src ( paths . serverScripts )
    . pipe ( istanbul ( ) )
    . pipe ( istanbul . hookRequire ( ) ) ;
} ) ;

/ / Watch for changes in files .
gulp . task ( 'watch' , function ( ) {
  gulp . watch ( paths . jade , [ 'jade:compile' ] ) ;
  gulp . watch ( paths . compileScripts . js , [ 'js:minify' ] ) ;
  gulp . watch ( paths . compileScripts . css , [ 'css:minify' ] ) ;
  gulp . watch ( paths . index , [ 'scripts:inject' ] ) ;
  gulp . watch ( paths . images , [ 'copy:images' ] )
} ) ;

/ / Default task .
gulp . task ( 'default' , [ 'bower:run' , 'jade:compile' , 'js:minify' , 'css:minify' , 'scripts:inject' , 'copy:images' ] ) ;

/ / Dev environment task .
gulp . task ( 'dev' , [ 'nodemon:run' , 'bower:run' , 'jade:compile' , 'js:minify' , 'css:minify' , 'scripts:inject' , 'watch' , 'copy:images' ] ) ;

更新.bowerrc (Update .bowerrc)

Set the default directory where bower components will be installed and run the inject gulp task after bower components are installed.

设置将安装Bower组件的默认目录,并在安装Bower组件后运行Inject gulp任务。

{
  "directory" : "public/lib" ,
  "scripts" : {
    "postinstall" : "node_modules/.bin/gulp scripts:inject"
  }
}

初始化和主题化我们的书签应用程序 ( Initializing And Theming Our Bookmark Application )

We will use Angular material's mdThemingProvider and mdIconProvider services to theme our application and set a placeholder svg icon for our authors respectively.

我们将使用Angular材质的mdThemingProvidermdIconProvider服务为应用程序设置主题,并分别为作者设置一个占位符svg图标。

/app/app.js

/app/app.js

angular . module ( 'Bookmark.controllers' , [ ] ) ;
angular . module ( 'Bookmark.services' , [ ] ) ;

//Inject dependencies to the Bookmark module.
var Bookmark = angular . module ( 'Bookmark' , [
  'ngMaterial' ,
  'ngMdIcons' ,
  'Bookmark.controllers' ,
  'Bookmark.services'
] ) ;

Bookmark
  . config ( [ '$mdThemingProvider' , function ( $mdThemingProvider ) {
    //Set default theme
    $mdThemingProvider . theme ( 'default' )
      . primaryPalette ( 'blue' )
      . accentPalette ( 'red' ) ;
  } ] )
  . config ( [ '$mdIconProvider' , function ( $mdIconProvider ) {
    //Placeholder icon for author profile.
    $mdIconProvider
      . icon ( 'author' , './images/svg/person.svg' ) ;
  } ] ) ;

主控制器和烤面包服务 ( Main Controller And Toast Service )

The main controller handles all requests in our main page when the application is loaded. Besides fetching all authors from the server, it also triggers our dialogs to add, edit or delete books and authors.

加载应用程序后,主控制器处理我们主页中的所有请求。 除了从服务器获取所有作者外,它还触发我们的对话框来添加,编辑或删除书籍和作者。

/app/js/controllers/main.js

/app/js/controllers/main.js

angular . module ( 'Bookmark.controllers' )
. controller ( 'MainCtrl' , [ '$rootScope' , '$scope' , '$mdSidenav' , '$mdDialog' , 'Authors' , 'Books' , 'Toast' ,
function ( $rootScope , $scope , $mdSidenav , $mdDialog , Authors , Books , Toast ) {
  //Fetch all authors
  Authors . all ( )
    . then ( function ( authors ) {
      $rootScope . authors = authors ;
      $rootScope . selectedAuthor = authors [ 0 ] ;
    } ) ;

  //set an author as selected
  $scope . selectAuthor = function ( author ) {
    $rootScope . selectedAuthor = author ;
  } ;

  //toggle the visibility of the Sidenav
  $scope . toggleSidenav = function ( ) {
    $mdSidenav ( 'left' ) . toggle ( ) ;
  } ;

  //Dialog to create new author
  $scope . newAuthorDialog = function ( ev ) {
    $mdDialog . show ( {
      templateUrl : 'views/dialogs/new-author.html' ,
      controller : 'AuthorDialogCtrl' ,
      parent : angular . element ( document . body ) ,
      targetEvent : ev ,
      clickOutsideToClose : true ,
      fullscreen : true
    } ) ;
  } ;

  //Show An author's profile
  $scope . showAuthorProfile = function ( ev ) {
    $mdDialog . show ( {
      templateUrl : 'views/dialogs/author-profile.html' ,
      controller : 'AuthorDialogCtrl' ,
      parent : angular . element ( document . body ) ,
      targetEvent : ev ,
      clickOutsideToClose : true ,
      fullscreen : true
    } ) ;
  } ;

  //Dialog to create new book
  $scope . newBookDialog = function ( ev ) {
    $mdDialog . show ( {
      templateUrl : 'views/dialogs/new-book.html' ,
      controller : 'BookDialogCtrl' ,
      locals : {
        bookDetails : null
      } ,
      parent : angular . element ( document . body ) ,
      targetEvent : ev ,
      clickOutsideToClose : true ,
      fullscreen : true
    } ) ;
  } ;

  //Delete an existing book
  $scope . deleteBook = function ( ev , book ) {
    var deleteBook = $mdDialog . confirm ( )
      . title ( 'Delete ' + book . name + '?' )
      . textContent ( book . name + ' will be wiped off the face of the earth.' )
      . ariaLabel ( 'Delete book' )
      . ok ( 'Yes! do it!' )
      . cancel ( 'No' ) ;

    $mdDialog . show ( deleteBook )
      . then ( function ( ) {
        Books . delete ( book . id )
          . then ( function ( ) {
            $scope . selectedAuthor . Books = $scope . selectedAuthor . Books . filter ( function ( i ) {
              return i . id !== book . id ;
            } ) ;
            Toast . show ( book . name + ' has been deleted.' , 'top right' , 3000 ) ;
          } )
          . catch ( function ( error ) {
            Toast . show ( 'Error deleting ' + book . name + '. Please try again.' , 'top right' , 3000 ) ;
          } ) ;

      } ) ;
  } ;

  //Show modal to edit an existing book's details
  $scope . editBook = function ( ev , book ) {
    $mdDialog . show ( {
      templateUrl : 'views/dialogs/edit-book.html' ,
      controller : 'BookDialogCtrl' ,
      locals : {
        bookDetails : book
      } ,
      parent : angular . element ( document . body ) ,
      targetEvent : ev ,
      clickOutsideToClose : true ,
      fullscreen : true
    } ) ;
  } ;
} ] ) ;

The toast service simply displays an angular toast notification on actions such as adding, editing or deleting authors and books.

祝酒服务仅在添加,编辑或删除作者和书籍等操作上显示有角度的祝酒通知。

app/js/services/toast.js

app / js / services / toast.js

angular . module ( 'Bookmark.services' )
  . factory ( 'Toast' , [ '$mdToast' , function ( $mdToast ) {
    return {
      show : function ( text , position , delay ) {
        $mdToast . show (
          $mdToast . simple ( )
            . textContent ( text )
            . position ( position )
            . hideDelay ( delay )
          ) ;
      }
    } ;
  } ] ) ;

作者控制器和服务 ( Author Controller And Service )

The Author dialog controller has one function that makes a request to the new method in the Author service which creates a new author in our database.

Author对话框控制器具有一个功能,该功能向Author服务中的new方法发出请求,该服务在我们的数据库中创建一个新作者。

We then use the toast service defined earlier to show a success or error message.

然后,我们使用先前定义的Toast服务显示成功或错误消息。

app/js/controllers/author-dialog.js

app / js / controllers / author-dialog.js

angular . module ( 'Bookmark.controllers' )
  . controller ( 'AuthorDialogCtrl' , [ '$rootScope' , '$scope' , '$mdDialog' , 'Toast' , 'Authors' ,
  function ( $rootScope , $scope , $mdDialog , Toast , Authors ) {
    //Save a new author
    $scope . saveAuthor = function ( author ) {
      Authors
        . new ( author )
        . then ( function ( newAuthor ) {
          newAuthor . Books = [ ] ;
          $rootScope . authors . push ( newAuthor ) ;
          Toast . show ( 'Author successfully created' , 'top right' , 3000 ) ;
          $mdDialog . cancel ( ) ;
        } )
        . catch ( function ( ) {
          Toast . show ( 'Error creating author' , 'top right' , 3000 ) ;
        } ) ;
    } ;
  } ] ) ;

app/js/services/authors.js

app / js / services / authors.js

angular . module ( 'Bookmark.services' )
  . factory ( 'Authors' , [ '$http' , '$q' , function ( $http , $q ) {
    return {
      all : function ( ) {
        var deferred = $q . defer ( ) ;
        $http
          . get ( '/authors' )
          . then ( function ( response ) {
            deferred . resolve ( response . data ) ;
          } )
          . catch ( function ( error ) {
            deferred . reject ( error ) ;
          } ) ;
          return deferred . promise ;
      } ,

      //add new author
      new : function ( author ) {
        var deferred = $q . defer ( ) ;
        $http
          . post ( '/authors' , author )
          . then ( function ( response ) {
            deferred . resolve ( response . data ) ;
          } )
          . catch ( function ( error ) {
            deferred . reject ( error ) ;
          } ) ;
        return deferred . promise ;
      }
    } ;
  } ] ) ;

图书管理员和服务 ( Books Controller And Service )

The books controller has two methods saveBook which creates a new book and updateBook which edits an existing book.

书籍控制器有两种方法saveBook创建新书籍,而updateBook编辑现有书籍。

app/js/controllers/book-dialog.js

app / js / controllers / book-dialog.js

angular . module ( 'Bookmark.controllers' )
  . controller ( 'BookDialogCtrl' , [ '$rootScope' , '$scope' , '$mdDialog' , 'Toast' , 'Books' , 'bookDetails' ,
  function ( $rootScope , $scope , $mdDialog , Toast , Books , bookDetails ) {
    $scope . book = bookDetails ;
    if ( $scope . book ) {
      $scope . book . publication_date = new Date ( $scope . book . publication_date ) ;
    }
    //create a new book
    $scope . saveBook = function ( book ) {
      book [ 'author_id' ] = $rootScope . selectedAuthor . id ;
      Books
        . new ( book )
        . then ( function ( newBook ) {
          Toast . show ( 'Book successfully created' , 'top right' , 3000 ) ;
          $rootScope . selectedAuthor . Books . push ( newBook ) ;
          $mdDialog . cancel ( ) ;
        } )
        . catch ( function ( ) {
          Toast . show ( 'Error creating book' , 'top right' , 3000 ) ;
        } ) ;
    } ;

    //Update a book's details
    $scope . updateBook = function ( book ) {
      Books
        . update ( book )
        . then ( function ( ) {
          Toast . show ( 'Book successfully updated' , 'top right' , 3000 ) ;
          $mdDialog . cancel ( ) ;
        } )
        . catch ( function ( ) {
          Toast . show ( 'Error updating book' , 'top right' , 300 ) ;
        } ) ;
    } ;
  } ] ) ;

The Books service has 3 methods new, delete and update which serves BookDialogCtrl and mainCtrl

图书服务具有newdeleteupdate 3种方法,分别用于BookDialogCtrlmainCtrl

app/js/services/books.js

app / js / services / books.js

angular . module ( 'Bookmark.services' )
  . factory ( 'Books' , [ '$http' , '$q' , function ( $http , $q ) {

    return {
      new : function ( book ) {
        var deferred = $q . defer ( ) ;
        $http
          . post ( '/books' , book )
          . then ( function ( response ) {
            deferred . resolve ( response . data ) ;
          } )
          . catch ( function ( error ) {
            deferred . reject ( error ) ;
          } ) ;
        return deferred . promise ;
      } ,
      delete : function ( bookId ) {
        var deffered = $q . defer ( ) ;
        $http
          . delete ( '/books/' + bookId )
          . then ( function ( response ) {
            deffered . resolve ( response . data ) ;
          } )
          . catch ( function ( error ) {
            deffered . reject ( error ) ;
          } ) ;
        return deffered . promise ;
      } ,
      update : function ( book ) {
        var deferred = $q . defer ( ) ;
        $http
          . put ( '/books/' + book . id , book )
          . then ( function ( response ) {
            deferred . resolve ( response . data ) ;
          } )
          . catch ( function ( error ) {
            deferred . reject ( error ) ;
          } ) ;
        return deferred . promise ;
      }
    } ;
  } ] ) ;

设计应用程序布局 ( Designing The Application Layout )

Sidenav和导航布局 (Sidenav and navigation layouts)

The sidenav contains a clickable list of all the authors in the Bookmark application. /app/index.jade

sidenav包含“书签”应用程序中所有作者的可单击列表。 /app/index.jade

doctype html
html(lang="en")
  head
    title bookmark App
    include views/layouts/head
  body(layout="row" ng-app="Bookmark" ng-controller="MainCtrl")

    //Sidenav
    md-sidenav.md-whiteframe-z2(md-component-id="left" md-is-locked-open="$mdMedia('gt-sm')")
      md-toolbar
        h1 Authors
      md-content
        md-list
           //Loop through the authors list
          md-list-item(ng-repeat="author in authors")
            md-button(ng-click="selectAuthor(author)")
              md-icon.author_avatar(md-svg-icon="author")
              span(ng-class="{selected: author === selectedAuthor}") {{author.name}}
      div.new_author
        md-button(aria-label="new_author" class="md-fab md-raised md-primary md-mini")
          ng-md-icon(icon="add")
            md-tooltip(direction="top") Add new author

    //Main toolbar
    div(layout="column" flex)
      md-toolbar(layout="row")
        div.md-toolbar-tools
          md-button.md-button-icon(hide-gt-sm aria-label="Menu" ng-click="toggleSidenav()")
            ng-md-icon.authors(icon="view_module")
          h1 Bookmark

      //Main content
    include views/layouts/footer

I will be using Angular material icons so make sure you go ahead and bower install the icons package bower install --save angular-material-icons.

我将使用Angular material图标,因此请确保您继续并bower安装图标包bower install --save angular-material-icons

If you run gulp dev on your terminal now, we should now have this simple layout.

如果您现在在终端上运行gulp dev ,我们现在应该具有这种简单的布局。

书签导航和工具栏

主要内容布局 (Main content layout)

The main content section holds the bullk of our application.

主要内容部分包含了我们的应用程序。

/app/index.jade

/app/index.jade

//Main content
      md-content.md-default-theme
        div.md-padding
          h2(ng-show="selectedAuthor.Books.length") Books by {{selectedAuthor.name}}
          div.author_actions
            md-button.author_profile(aria-label="new_book" class="md-fab md-raised md-primary md-mini")
              ng-md-icon(icon="person")
                md-tooltip(direction="bottom") View {{selectedAuthor.name}}'s profile
            md-button.new_book(aria-label="new_book" class="md-fab md-raised md-primary md-mini")
              ng-md-icon(icon="my_library_add")
                md-tooltip(direction="bottom") Add new book by {{selectedAuthor.name}}
        md-content.md-padding(layout="column")
          md-card(ng-repeat="book in selectedAuthor.Books")
            div(layout="row" layout-align="end")
              div.books_menu
                  md-button(aria-label="edit" class="md-fab md-raised md-mini")
                    ng-md-icon(icon="edit")
                    md-tooltip(direction="bottom") edit book details
                  md-button(aria-label="delete" class="md-fab md-raised md-mini")
                    ng-md-icon(icon="delete")
                    md-tooltip(direction="bottom") delete book details
            md-card-title
              md-card-title-text
                span.md-headline {{book.name}}
                span.md-subhead Publication date: {{ book.publication_date | date: mediumDate}}
            md-card-content
              div.md-subhead {{book.description}}
              md-chips
                md-chip ISBN Number: {{ book.isbn}}

While we are yet to wire up the functions of most of the buttons, run gulp dev to view the updated layout.

当我们尚未连接大多数按钮的功能时,请运行gulp dev来查看更新的布局。

书签应用程序的主要内容布局

创建作者并添加新书 ( Creating An Author and Adding New Books )

With the layout looking arguably swanky, let's dive into the meat of our application. In this section, we will manage to create a new author from a form and by extension, adding a new book to an author's profile.

布局看起来可以说是时髦的,让我们深入研究应用程序的内容。 在本节中,我们将设法通过表单并通过扩展来创建新作者,并将新书添加到作者的个人资料中。

To get started, add a click event to the new author button.

首先,将click事件添加到新的author按钮

/app/index.jade

/app/index.jade

div.new_author
        //Show dialog to create new author on click.
        md-button(aria-label="new_author" class="md-fab md-raised md-primary md-mini" ng-click="newAuthorDialog($event)")
          ng-md-icon(icon="add")
            md-tooltip(direction="top") Add new author

The newAuthorDialog method in our mainCtrl pops up a dialog box that will contain our new author form. Read more about all the possible $mdDialog options in the official angular material documentation.

newAuthorDialog中的newAuthorDialog方法mainCtrl弹出一个对话框,其中将包含我们的新作者表单。 在官方的角度材料文档中阅读有关所有可能的$mdDialog选项的更多信息。

To display the dialog that creates a new author, add the new-author template.

要显示创建新作者的对话框,请添加新作者模板。

/app/views/dialogs/new-author.jade

/app/views/dialogs/new-author.jade

md-dialog(aria-label="New Author" flex="50")
  md-toolbar
    .md-toolbar-tools
      h2 Create New Author
  form(name="authorForm" ng-submit="saveAuthor(author)" novalidate)
    md-dialog-content.md-padding
      md-input-container.md-block
        label Name
        input(ng-model="author.name" type="text" name="author.name" required)
      md-input-container.md-block
        label Biography
        textarea(ng-model="author.bio" rows="5" name="author.bio" required)
    md-dialog-actions
      md-button(aria-label="Save Author" type="submit" ng-disabled="authorForm.$invalid") Save

To display the dialog to create a new book, add the new-book template.

要显示创建新书的对话框,请添加新书模板。

** app/views/dialogs/new-book.jade**

**应用程序/视图/对话框/新书.jade **

md-dialog(aria-label="New Book" flex="50")
  md-toolbar
    .md-toolbar-tools
      h2 Add New Book
  form(name="bookForm" ng-submit="saveBook(book)" novalidate)
    md-dialog-content.md-padding
      div(layout="row")
        md-input-container(flex)
          label Name
          input(ng-model="book.name" type="text" name="book.name" required)
        md-input-container(flex)
          label Publication Date
          md-datepicker(ng-model="book.publication_date" type="text" name="book.publication_date" required)
      md-input-container.md-block
        label ISBN number
        input(ng-model="book.isbn" type="text" name="book.isbn" required)
      md-input-container.md-block
        label Description
        textarea(ng-model="book.description" rows="5" name="book.description" required)
    md-dialog-actions
      md-button(aria-label="Save Book" type="submit" ng-disabled="bookForm.$invalid") Add Book

On clicking the submit, the saveAuthor method in AuthorDialogCtrl is called and the newly added details are passed to it which in turns calls the new method in our Authors service.

单击提交后,将saveAuthor中的saveAuthor方法, AuthorDialogCtrl新添加的详细信息传递给它,这AuthorDialogCtrlAuthors服务中调用new方法。

Thanks to Angular's two way data binding , the author is automatically visible to our sidenav when we push the author details to the authors variable in rootScope.

多亏了Angular的双向数据绑定,当我们将作者详细信息推送到rootScope中的authors变量时,作者对我们的sidenav自动可见。

查看作者的个人资料 ( Viewing An Author's Profile )

Just like we did while creating a new author, add a new event handler to pop the dialog containing the author's profile.

就像我们创建新作者时所做的一样,添加新的事件处理程序以弹出包含作者个人资料的对话框。

/app/index.jade

/app/index.jade

div.author_actions
            md-button.author_profile(aria-label="view_profile" class="md-fab md-raised md-primary md-mini" ng-click="showAuthorProfile($event)")
              ng-md-icon(icon="person")
                md-tooltip(direction="bottom") View {{selectedAuthor.name}}'s profile

To display the dialog that shows an author's profile, add the author-profile template.

要显示显示作者个人资料的对话框,请添加作者个人资料模板。

** app/views/dialogs/author-profile.jade**

**应用程序/视图/对话框/作者个人资料.jade **

md-dialog(aria-label="Author Profile" flex="50")
  md-toolbar
    .md-toolbar-tools
      h2 {{$root.selectedAuthor.name}}'s profile
  md-dialog-content.md-padding
    md-list
      md-list-item
        div.md-list-item-text
          h3 Biography
          p {{$root.selectedAuthor.bio}}
      md-divider
      md-list-item
        div.md-list-item-text
          h3 Books on Bookmark
          p {{$root.selectedAuthor.Books.length}}

On clicking the view profile button, the User's profile will be displayed as shown below.

单击查看配置文件按钮后,将显示用户的配置文件,如下所示。

Run gulp dev on your terminal to try this out.

在您的终端上运行gulp dev进行尝试。

查看作者资料

更新和删除现有书籍 ( Updating And Deleting An Existing Book )

To edit and delete an book, add click events to the edit and delete button for each book.

要编辑和删除一本书,请将点击事件添加到每本书的“编辑和删除”按钮中。

/app/index.jade

/app/index.jade

//Edit and Delete Books
div.books_menu
  md-button(aria-label="edit" class="md-fab md-raised md-mini" ng-click="editBook($event, book)")
    ng-md-icon(icon="edit")
    md-tooltip(direction="bottom") edit book details
  md-button(aria-label="delete" class="md-fab md-raised md-mini" ng-click="deleteBook($event, book)")
     ng-md-icon(icon="delete")
     md-tooltip(direction="bottom") delete book

We already have the deleteBook method defined in MainCtrl which presents the user with a confirmation dialog to either accept or cancel the delete request.

我们已经在MainCtrl中定义了deleteBook方法,该方法向用户显示一个确认对话框,以接受或取消删除请求。

To show the dialog with the edit book form, let's add the edit-book dialog template.

要显示带有编辑书形式的对话框,让我们添加编辑书对话框模板。

/app/views/dialogs/edit-book.jade

/app/views/dialogs/edit-book.jade

md-dialog(aria-label="Edit Book" flex="50")
  md-toolbar
    .md-toolbar-tools
      h2 Edit {{book.name}} {{book.publication_date | date: 'm/d/yyyy'}}
  form(name="bookForm" ng-submit="updateBook(book)" novalidate)
    md-dialog-content.md-padding
      div(layout="row")
        md-input-container(flex)
          label Name
          input(ng-model="book.name" type="text" name="book.name" required)
        md-input-container(flex)
          label Publication Date
          md-datepicker(ng-model="book.publication_date" type="text" name="book.publication_date" required)
      md-input-container.md-block
        label ISBN number
        input(ng-model="book.isbn" type="text" name="book.isbn" required)
      md-input-container.md-block
        label Description
        textarea(ng-model="book.description" rows="5" name="book.description" required)
    md-dialog-actions
      md-button(aria-label="Save Book" type="submit" ng-disabled="bookForm.$invalid") Update Book

At this point, our Bookmark application performs the basic CRUD operations for the authors and the books.

此时,我们的Bookmark应用程序将为作者和书籍执行基本的CRUD操作。

结论 ( Conclusion )

In this section, we managed to:

在本节中,我们设法:

  • Setup the frontend for our Bookmark application.

    为我们的书签应用程序设置前端。
  • Theme and define our app layout

    设置主题并定义我们的应用布局
  • Create, view, update and delete book details.

    创建,查看,更新和删除书籍详细信息。

Just like we did in the first part of this series, you may also challenge yourself to edit and delete an author's details.

就像我们在本系列第一部分中所做的一样,您可能还会挑战自己编辑和删除作者的详细信息。

In the last part of the series, we will right tests for our app and deploy it to Heroku.

在本系列的最后一部分,我们将对应用进行正确的测试并将其部署到Heroku。

翻译自: https://scotch.io/tutorials/creating-an-angularjs-application-with-sequelize-part-2

sequelize 创建表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值