【问题标题】:Adding a picture to the MEAN.JS sample with Angular-file-upload使用 Angular-file-upload 将图片添加到 MEAN.JS 示例
【发布时间】:2015-03-17 17:46:54
【问题描述】:

我正在使用 MEAN.JS (https://github.com/meanjs/mean) 和 angular-file-upload (https://github.com/danialfarid/angular-file-upload)。

MEAN.JS 提供的“文章”示例包含名为“标题”和“内容”的两个字段。我想修改它并添加一个允许用户上传图片的“图片”字段。

我知道我必须修改 MEAN.JS 中的 3 个文件:

~myproject/app/models/article.server.model.js 
~myproject/public/modules/articles/controllers/articles.client.controller.js
~myproject/public/modules/articles/views/create-article.client.view.html

但是,我无法成功修改它们。

【问题讨论】:

  • 到目前为止,您尝试对这些文件进行哪些更改?虽然您已经识别出它们是件好事,但如果我们不知道您尝试了什么,那就没有什么可做的了。

标签: meanjs angular-file-upload


【解决方案1】:

感谢 Charlie Tupman 最后一个非常有效的解决方案。

我只是添加依赖项:

...
multiparty = require('multiparty'),
uuid = require('uuid'),
...

在导出函数之前并更改了两行以改进行为:

...
var destPath = './public/uploads/' + fileName;

article.image = '/uploads/' + fileName;
...

解决方法:

exports.createWithUpload = function(req, res) {

    var form = new multiparty.Form();
    form.parse(req, function(err, fields, files) {

        var file = req.files.file;
        console.log(file.name);
        console.log(file.type);
        console.log(file.path);
        console.log(req.body.article);

        var art = JSON.parse(req.body.article);
        var article = new Article(art);
        article.user = req.user;
        var tmpPath = file.path;
        var extIndex = tmpPath.lastIndexOf('.');
        var extension = (extIndex < 0) ? '' : tmpPath.substr(extIndex);
        var fileName = uuid.v4() + extension;
        var destPath = './public/uploads/' + fileName;

        article.image = '/uploads/' + fileName;

        var is = fs.createReadStream(tmpPath);
        var os = fs.createWriteStream(destPath);

        if(is.pipe(os)) {
            fs.unlink(tmpPath, function (err) { //To unlink the file from temp path after copy
                if (err) {
                    console.log(err);
                }
            });
            article.save(function(err) {
                if (err) {
                    return res.status(400).send({
                        message: errorHandler.getErrorMessage(err)
                    });
                } else {
                    res.jsonp(article);
                }
            });
        } else
            return res.json('File not uploaded');
    });

};

【讨论】:

    【解决方案2】:

    @john prunell 非常感谢你,我终于弄明白了(花了我一个多星期,但我现在对堆栈感到更舒服了)我已经分叉了它以将文件上传到文件夹:

    'exports.createWithUpload =     function(req, res) {
    
    var form = new multiparty.Form();
    form.parse(req, function(err, fields, files) {
    
     var file = req.files.file;
     console.log(file.name);
     console.log(file.type);
     console.log(file.path);
     console.log(req.body.article);
    
    var art = JSON.parse(req.body.article);
    var article = new Article(art);
    article.user = req.user;
    var tmpPath = file.path;
    var extIndex = tmpPath.lastIndexOf('.');
    var extension = (extIndex < 0) ? '' : tmpPath.substr(extIndex);
    var fileName = uuid.v4() + extension;
    var destPath = './uploads/' + fileName;
    
    article.image = fileName;
    
    var is = fs.createReadStream(tmpPath);
    var os = fs.createWriteStream(destPath);
    
    if(is.pipe(os)) {
        fs.unlink(tmpPath, function (err) { //To unlink the file from temp path after copy
            if (err) {
                console.log(err);
            }
        });
        article.save(function(err) {
        if (err) {
            return res.status(400).send({
                message: errorHandler.getErrorMessage(err)
            });
        } else {
            res.jsonp(article);
        }
    });
    }else
        return res.json('File not uploaded');
    });
    
    };
    

    我现在想做的是派生您的解决方案,以允许以相同的方式上传多个图像,如果您对如何做到这一点有任何见解,那将是惊人的,我会告诉您我的进展情况。

    【讨论】:

      【解决方案3】:

      我的解决方案在客户端使用angular-file-upload,并使用connect-multiparty处理文件上传。

      图像直接存储在数据库中,这限制了它们的大小。我没有包含检查图像大小所需的代码。

      设置

       bower install ng-file-upload --save
       bower install ng-file-upload-shim --save 
      
       npm i connect-multiparty
       npm update
      

      all.js 添加角度文件上传脚本

                  ...
                  'public/lib/ng-file-upload/FileAPI.min.js', 
                  'public/lib/ng-file-upload/angular-file-upload-shim.min.js',
                  'public/lib/angular/angular.js', 
                  'public/lib/ng-file-upload/angular-file-upload.min.js',
                  ...
      

      config.js 注入 angular-file-upload 依赖

      ...
      var applicationModuleVendorDependencies = ['ngResource', 'ngAnimate', 'ui.router', 'ui.bootstrap', 'ui.utils', 'angularFileUpload'];
      ...
      

      article.client.controller.js 使用 angular-file-upload 依赖

      angular.module('articles').controller('ArticlesController', ['$scope', '$timeout',  '$upload', '$stateParams', '$location', 'Authentication', 'Articles',
      function($scope, $timeout, $upload, $stateParams, $location, Authentication, Articles) {
          $scope.fileReaderSupported = window.FileReader !== null;
      
      
      
          // Create new Article
                  $scope.create = function(picFile) {
                console.log('create');
                            console.log(picFile);
              var article = new Articles({
                  title: this.title,
                  content: this.content,
                  image: null
              });
      
               console.log(article);
               $upload.upload({
                  url: '/articleupload', 
                  method: 'POST', 
                  headers: {'Content-Type': 'multipart/form-data'},
                  fields: {article: article},
                  file: picFile,               
              }).success(function (response, status) {
                    $location.path('articles/' + response._id);
      
                  $scope.title = '';
                  $scope.content = '';
              }).error(function (err) {
                      $scope.error = err.data.message;
              });
      
          };
      
          $scope.doTimeout = function(file) {
               console.log('do timeout');
              $timeout( function() {
                      var fileReader = new FileReader();
                      fileReader.readAsDataURL(file);
                   console.log('read');
                      fileReader.onload = function(e) {
                          $timeout(function() {
                              file.dataUrl = e.target.result;
                               console.log('set url');
                          });
                      };
                  });
          };
      
      
          $scope.generateThumb = function(file) {
              console.log('generate Thumb');
          if (file) {
              console.log('not null');
               console.log(file);
              if ($scope.fileReaderSupported && file.type.indexOf('image') > -1) {
                  $scope.doTimeout(file);
                }
            }
         };
      }
      

      create-article.client.view.html 更新创建视图以处理文件选择和上传

      <section data-ng-controller="ArticlesController">
      <div class="page-header">
          <h1>New Article</h1>
      </div>
      <div class="col-md-12">
          <form name="articleForm" class="form-horizontal" data-ng-submit="create(picFile)" novalidate>
              <fieldset>
                  <div class="form-group" ng-class="{ 'has-error':   articleForm.title.$dirty && articleForm.title.$invalid }">
                      <label class="control-label" for="title">Title</label>
                      <div class="controls">
                          <input name="title" type="text" data-ng-model="title" id="title" class="form-control" placeholder="Title" required>
                      </div>
                  </div>
                  <div class="form-group">
                      <label class="control-label" for="content">Content</label>
                      <div class="controls">
                          <textarea name="content" data-ng-model="content" id="content" class="form-control" cols="30" rows="10" placeholder="Content"></textarea>
                      </div>
                  </div>
                  <div class="form-group">
                      <label class="control-label" for="articleimage">Article Picture</label>
                      <div class="controls">
                           <input id="articleimage" type="file" ng-file-select="" ng-model="picFile" name="file" accept="image/*" ng-file-change="generateThumb(picFile[0], $files)" required="">
                          <br/>
                          <img ng-show="picFile[0].dataUrl != null" ng-src="{{picFile[0].dataUrl}}" class="img-thumbnail" height="50" width="100">
                          <span class="progress" ng-show="picFile[0].progress >= 0">      
                              <div style="width:{{picFile[0].progress}}%" ng-bind="picFile[0].progress + '%'" class="ng-binding"></div>
                          </span> 
                          <span ng-show="picFile[0].result">Upload Successful</span>
                      </div>
                  </div>
                  <div class="form-group">
                      <input type="submit" class="btn btn-default" ng-disabled="!articleForm.$valid" ng-click="uploadPic(picFile)">
                  </div> 
                  <div data-ng-show="error" class="text-danger">
                      <strong data-ng-bind="error"></strong>
                  </div>
              </fieldset>
          </form>
      </div>
      </section>
      

      view-article.client.view.html 更新列表视图以包含图像

      <img ng-src="data:image/jpeg;base64,{{article.image}}" id="photo-id" width="200" height="200"/>
      

      list-articles.client.view.html 更新视图以包含 imgae

      <img ng-src="data:image/jpeg;base64,{{article.image}}" id="photo-id" width="40" height="40"/>
      

      article.server.model.js 将图像添加到数据库模型

      ...
      image: {
          type: String,
          default: ''
      },
      ...
      

      article.server.routes.js 添加新的上传路由使用 connect-multiparty

      ...
      multiparty = require('connect-multiparty'),
      multipartyMiddleware = multiparty(),
      ...
      app.route('/articleupload')
          .post(users.requiresLogin, multipartyMiddleware, articles.createWithUpload);
      ...
      

      article.server.controller.js 处理上传的新路由需要 fs

      ...
      fs = require('fs'),
      ...
      /**
       * Create a article with Upload
       */
      exports.createWithUpload = function(req, res) {
       var file = req.files.file;
       console.log(file.name);
       console.log(file.type);
       console.log(file.path);
       console.log(req.body.article);
      
      var art = JSON.parse(req.body.article);
      var article = new Article(art);
      article.user = req.user;
      
      fs.readFile(file.path, function (err,original_data) {
       if (err) {
            return res.status(400).send({
                  message: errorHandler.getErrorMessage(err)
              });
        } 
          // save image in db as base64 encoded - this limits the image size
          // to there should be size checks here and in client
        var base64Image = original_data.toString('base64');
        fs.unlink(file.path, function (err) {
            if (err)
            { 
                console.log('failed to delete ' + file.path);
            }
            else{
              console.log('successfully deleted ' + file.path);
            }
        });
        article.image = base64Image;
      
        article.save(function(err) {
          if (err) {
              return res.status(400).send({
                  message: errorHandler.getErrorMessage(err)
              });
          } else {
              res.json(article);
          }
        });
      });
      };
      ...
      

      【讨论】:

      • 我无法让它工作,你有没有将文件存储到服务器而不是数据库的解决方案?
      • 出了什么问题,提供错误信息和代码,我也许可以提供帮助。
      • 请在@john purnell 下方查看我的解决方案
      • 对不起,查理,我现在很刻薄,所以只是一个快速的回答。参见 angular-file-upload doco 例如Upload multiple files: Only for HTML5 FormData browsers (not IE8-9) if you pass an array of files to file option it will upload all of them together in one request. Non-html5 browsers due to flash limitation will still upload array of files one by one in a separate request. You should iterate over files and send them one by one if you want cross browser solution.
      • Prunell,谢谢约翰,我会调查一下,让你知道我的进展情况。
      【解决方案4】:

      我在 MEAN.js 中的工作解决方案

      服务器模型:

      image:{ 
          type: String, 
          default: ''
      },
      

      服务器控制器:

      var item = new Item(JSON.parse(req.body.item));
      item.user = req.user;
      if(req.files.file)
          item.image=req.files.file.name;
      else
          item.image='default.jpg';
      
      //item.image=
      item.save(function(err) {
          if (err) {
              return res.status(400).send({
                  message: errorHandler.getErrorMessage(err)
              });
          } else {
              res.jsonp(item);
          }
      });
      

      服务器路由:(需要 multer:“npm install multer --save”)

      var multer  = require('multer');
      app.use(multer({ dest: './public/uploads/'}));
      

      前端角度控制器:

          $scope.image='';
      
          $scope.uploadImage = function(e){
              console.log(e.target.files[0]);
              $scope.image=e.target.files[0];
      
          };
      
      
      
          // Create new Item
          $scope.create = function() {
              // Create new Item object
              var item = new Items ({
                  name: this.name,
                  bought: this.bought,
                  number: this.number,
                  description: this.description,
                  warranty: this.warranty,
                  notes: this.notes
      
      
              });
      
              ItemsService.saveItem(item,$scope.image);
      
          };
      

      发送请求的服务:

      .factory('ItemsService', ['$http','$rootScope', function($http, $rootScope) 
      {
          var service={};
      
          service.saveItem = function(item, image)
          {
      
              var fd = new FormData();
              fd.append('file', image);
              fd.append('item', JSON.stringify(item));
              $http.post('items/', fd, {
                  transformRequest: angular.identity,
                  headers: {'Content-Type': undefined}
              })
              .success(function(){
                  console.log('success add new item');
              })
              .error(function(e){
                  console.log('error add new item', e);
              });
      
      
          };
      
          return service;
      
      }
      
      ]);
      

      html 视图:

                 <div class="form-group">
                      <label class="control-label" for="name">Image</label>
                      <div class="controls">
                          <input type="file"  data-ng-model="image" id="image" my-file-upload="uploadImage" required>
                           {{selectedFile.name}}
                      </div>
                  </div>
      

      【讨论】:

      • 您好,我已尝试实施您的解决方案,但是我的模块控制器中出现“未定义 ItemsService”错误。你知道我做错了什么吗?
      • 我以几种不同的方式将工厂添加到我的客户服务中,但我得到'ItemsService 未定义:public\modules\testcruds\controllers\testcruds.client.controller。 ItemsService.saveItem(testcrud,$scope.image); 'ItemsService' 未定义。
      • 确保您在控制器依赖项中注入了服务:~ angular.module(...).controller('...',['dependencies'
      • 我逐字执行,但是在浏览器中选择图像时没有触发$scope.uploadImage = function(e),我看不到我缺少什么?
      猜你喜欢
      • 2018-02-11
      • 2016-03-08
      • 2018-02-06
      • 2014-12-11
      • 1970-01-01
      • 2013-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多