Angular & Loopback multiform POST не работает, почему?

У меня есть бэкэнд API с обратной связью со службой хранения, в которой хранятся изображения и данные формы, которые я отправляю. Тестирование API само по себе, все работает, поэтому очевидно, что в моей логике в моем контроллере чего-то не хватает. Я использую angular-file-upload и код из этого https://github.com/strongloop/loopback-component-storage/tree/master/example-2.0

Итак, я в основном пытаюсь опубликовать форму, которая сначала помещает изображение в контейнер на сервере API, а затем, когда я нажимаю кнопку отправки, я пытаюсь вытащить имя изображения из объекта, созданного загрузчиком, и опубликовать его вместе с другими входами формы. .

Когда я отправляю форму, на консоли появляется сообщение об ошибке Network 422 в свойстве Image - не может быть пустым. БД принимает строку для этого свойства.

Контроллер

app.controller('exampleCtrl', function($scope, $http, $resource, clientsUrl, $fileUploader, $window) {

//Code for uploading files to API - NEED TO WORK ON IT
'use strict';

// create a uploader with options
var uploader = $scope.uploader = $fileUploader.create({
  scope: $scope,                          // to automatically update the html. Default: $rootScope
  url: 'http://www.example.com:3000/api/containers/container1/upload',
  formData: [
    { key: 'value' }
  ],
  filters: [
    function (item) {                    // first user filter
      console.info('filter1');
      return true;
    }
  ]
});

// ADDING FILTERS

uploader.filters.push(function (item) { // second user filter
  console.info('filter2');
  return true;
});

// REGISTER HANDLERS

uploader.bind('afteraddingfile', function (event, item) {
  console.info('After adding a file', item);
});

uploader.bind('whenaddingfilefailed', function (event, item) {
  console.info('When adding a file failed', item);
});

uploader.bind('afteraddingall', function (event, items) {
  console.info('After adding all files', items);
});

uploader.bind('beforeupload', function (event, item) {
  console.info('Before upload', item);
});

uploader.bind('progress', function (event, item, progress) {
  console.info('Progress: ' + progress, item);
});

uploader.bind('success', function (event, xhr, item, response) {
  console.info('Success', xhr, item, response);
  $scope.$broadcast('uploadCompleted', item);
});

uploader.bind('cancel', function (event, xhr, item) {
  console.info('Cancel', xhr, item);
});

uploader.bind('error', function (event, xhr, item, response) {
  console.info('Error', xhr, item, response);
});

uploader.bind('complete', function (event, xhr, item, response) {
  console.info('Complete', xhr, item, response);
});

uploader.bind('progressall', function (event, progress) {
  console.info('Total progress: ' + progress);
});

uploader.bind('completeall', function (event, items) {
  console.info('Complete all', items);
});


$scope.load = function () {
  $http.get('http://www.example.com:3000/api/containers/container1/files').success(function (data) {
    console.log(data);
    $scope.files = data;
  });
};

$scope.delete = function (index, id) {
  $http.delete('http://www.example.com:3000/api/containers/container1/files/' + encodeURIComponent(id)).success(function (data, status, headers) {
    $scope.files.splice(index, 1);
  });
};

$scope.$on('uploadCompleted', function(event) {
  console.log('uploadCompleted event received');
  $scope.load();
});


    $scope.clientsItemsResource = $resource(clientsUrl + ":id", {id: "@id"},
            { create : { method: "POST"}, save: { method: "PUT"}}
        );

//Creates prototype for setting image on scope
function SetImageScope($scope, $window){
    $scope.image = 'Superhero';

    SetImageScope.prototype.$scope = $scope;
};

    //Sets the newClientsItem
    SetImageScope.prototype.setFile = function(element) {
        var $scope = this.$scope;
        $scope.$apply(function(){
            $scope.newClientsItem = element.files[0];
        });
    };

    $scope.createClientsItem = function (clientsItem) {

        //creates the new item
  new $scope.clientsItemsResource(clientsItem).$create().then(function (newClientsItem) {
     $scope.clientsItems.push(newClientsItem);
   });
};
});

HTML

<div ng-controller="exampleCtrl" ng-file-drop="ng-file-drop" class="container">
<div class="row-fluid">
<div class="col-md-12"><br/></div>
<form>
  <div class="form-group">
    <label>Title</label>
    <input type="text" ng-model="newClientsItem.title" required="required" class="form-control"/><br/>
    <label>Link</label>
    <input type="url" ng-model="newClientsItem.link" required="required" class="form-control"/><br/>
    <label>Image</label>
    <input ng-file-select="ng-file-select" type="file" onchange="SetImageScope.prototype.setFile(this)" class="btn btn-primary"/>
    <table class="table">
      <thead>
        <tr>
          <th width="50%">Image</th>
          <th ng-show="uploader.isHTML5">Size</th>
          <th ng-show="uploader.isHTML5">Progress</th>
          <th>Status</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat="item in uploader.queue">
          <td><strong>{{ item.file.name }}</strong></td>
          <td ng-show="uploader.isHTML5" nowrap="">
            {{
            item.file.size/1024/1024|number:2 }} MB
          </td>
          <td ng-show="uploader.isHTML5">
            <div style="margin-bottom: 0;" class="progress">
              <div role="progressbar" ng-style="{ &quot;width&quot;: item.progress + &quot;%&quot; }" class="progress-bar"></div>
            </div>
          </td>
          <td class="text-center"><span ng-show="item.isSuccess"><i class="glyphicon glyphicon-ok"></i></span><span ng-show="item.isCancel"><i class="glyphicon glyphicon-ban-circle"></i></span><span ng-show="item.isError"><i class="glyphicon glyphicon-remove"></i></span></td>
          <td nowrap="">
            <button type="button" ng-click="item.upload()" ng-disabled="item.isReady || item.isUploading || item.isSuccess" class="btn btn-success btn-xs"><span class="glyphicon glyphicon-upload"></span>Upload</button>
            <button type="button" ng-click="item.cancel()" ng-disabled="!item.isUploading" class="btn btn-warning btn-xs"><span class="glyphicon glyphicon-ban-circle"></span>Cancel</button>
            <button type="button" ng-click="item.remove()" class="btn btn-danger btn-xs"><span class="glyphicon glyphicon-trash"></span>Remove</button>
          </td>
        </tr>
      </tbody>
    </table><a ng-click="createClientsItem(newClientsItem)" class="btn btn-default btn-lg">Ajouter</a>
  </div>
</form>


person Emmanuel Henri    schedule 21.12.2014    source источник
comment
Когда у меня возникла ваша проблема, мне помогла эта статья: uncorkedstudios.com/blog/ < / а>   -  person simeg    schedule 21.12.2014
comment
спасибо за совет, и я на самом деле читал эту статью, пока создавал все это ... но в моей логике чего-то не хватает, чего я не вижу после того, как некоторое время работал над этим кодом. Вы видите что-нибудь, чего я не вижу?   -  person Emmanuel Henri    schedule 21.12.2014
comment
Возможно отсутствие headers и transformRequest. Трудно сказать, так как я думаю, что вы используете совсем другой подход, чем в статье. Вы уверены, что БД принимает простую строку, а не файл (содержащий что-то еще)?   -  person simeg    schedule 21.12.2014
comment
Да, я уверен, поскольку оба элемента загружены в разные области API. Мне кажется, что в моем коде чего-то не хватает, я извлекаю имя, сгенерированное из объекта изображения (вокруг функции SetImageScope), а затем назначаю его объекту newClientsItem, сгенерированному из формы.   -  person Emmanuel Henri    schedule 21.12.2014


Ответы (2)


Код состояния 422 означает, что проверка модели не прошла. Попробуйте проверить отправленные данные на стороне клиента и сервера. Отладка с помощью хуков модели и Loopback debug strings должны помочь.

person IvanZh    schedule 21.12.2014
comment
Спасибо, и я знаю, что это отправленные данные. Посмотрите на код из SetImageScope до конца, я знаю, что он есть, но просто не вижу его, так как я работаю над этим некоторое время. API обратной петли и БД принимают свойство {image: STRING} ... вы можете найти мою ошибку? - person Emmanuel Henri; 22.12.2014
comment
Я просмотрел ваш код и не увидел вызова SetImageScope, где вы сохраняете $scope в прототипе и присоединяете свойство image к области видимости. SetImageScope.prototype.setFile видит $scope в этом случае? (Также ваш код немного сложен, и в следующий раз для выполнения некоторых методов области вы можете использовать onchange="angular.element(this).scope().setFile()" для вызова функции $scope.sentFile вместо работы с прототипами.) - person IvanZh; 22.12.2014

Не уверен, что мое решение правильное. Но вы можете их рассмотреть:

  1. Если вы хотите отделить отправку файла от отправки формы, попробуйте переместить тег файла <input> из тега <form>.

  2. В вашем коде нет места для установки типа данных 'multipart' для загрузки. Это может вызвать проблему.

person haotang    schedule 22.12.2014