goodeggs / angular-cached-resource

An AngularJS module to interact with RESTful resources, even when browser is offline
MIT License
216 stars 29 forks source link

Use transformRequest to update/upload files within the resource #67

Closed giorni closed 9 years ago

giorni commented 9 years ago

Trying to upload some images with the resource, using directives to set the proper FormData and binding the files to the cachedResource object. The problem is, cachedResource write the JSON as string to the cache and then uses/parses the cached value to do the real request, not the initial object, it loses the File and FileList object properties, returning simple Objects that can't be parsed properly for a multipart/form-data.

I tried to create and Object by hand back from the values, no success.

I am trying to find some light, since I don't want to fallback to direct http request or the core $resource.

Code examples:

    function transformRequest (data, headers) {
      if (data === undefined) {
        return data
      }

      var fd = new FormData();

      angular.forEach(data, function(value, key) {
        if (value instanceof FileList) {
          angular.forEach(value, function(file, index) {
            fd.append(key + '_' + index, file);
          })
        } else if (value instanceof Array || value instanceof Object) {
          fd.append(key, JSON.stringify(value))
        } else {
          fd.append(key, value);
        }
      });

      return fd;
    }

    var User = $cachedResource('user', path, { id: '@_id' }, {
      update: {
        method:'PUT',
        transformRequest: transformRequest,
        headers: { 'Content-Type': undefined }
      }
    })

The directive that sets that binds the FileList to the user object:

angular.module('constructApp')
  .directive('filesModel', function ($parse) {
    return {
      restrict: 'A',
      link: function(scope, element, attrs){
        var model = $parse(attrs.filesModel)
          , modelSetter = model.assign

        element.bind('change', function(){
          scope.$apply(function(){
            modelSetter(scope, element[0].files)
          })
        })
      }
    }
  })
<form  name="form" novalidate ng-submit="saveUser()">

  <span class="profile-user">Edit Profile</span>

  <div class="from-group">
    <input type="file" files-model="user.files" class="from-control">
  </div>

  <div class="form-group double-input">
    <input type="text" ng-model="user.name" class="form-control" required>
  </div>

  <div class="text-right">
    <button class="btn btn-border" type="submit" ng-disabled="form.$invalid">Save</button>
  </div>

</form>
giorni commented 9 years ago

Right now I am saving a an array of key pointers to IndexedDB files entry, cachedResources serializes it, and then at the transformRequest I get it back and add to the FormData object.