angular-drupal
angular-drupal copied to clipboard
Add function for 'attached files' targeted action on node resource
Hi,
I needed to use the 'attach files to node resource' targeted action provided by services but didn't find that capability in this module. I got something working & thought I'd share it.
Here's the code for the Angular Drupal module:
// Attach file(s) to node
this.file_attach = function(nid, data) {
var options = {
method: 'POST',
url: this.restPath + '/node/' + nid + '/attach_file',
transformRequest: angular.identity,
headers: {'Content-Type': undefined, 'Accept': 'application/json'},
data: data,
};
return this.token().then(function(token) {
options.headers['X-CSRF-Token'] = token;
return $http(options).then(function(result) {
if (result.status == 200) { return result.data; }
});
});
};
Setting Content-Type: undefined, & transformRequest: angular.identity are essential to making the browser send the data with the proper Content-Type: multipart/form-data & correct boundaries.
Since this targeted action (for some obscure reason) requires multipart/form-data Content-Type POSTs rather than a more REST API/Angular friendly JSON, it requires some fiddling. In my Angular controller I created a FormData() object that gets passed in above as the parameter 'data'. To wit:
$scope.sendFile = function(nid) {
var data = {
'files[anything1]': $scope.loadedImage,
'field_values[anything1][alt]': $scope.imageAlt,
'field_values[anything1][title]': $scope.imageAlt,
field_name: 'field_i4l_page_images',
};
var fd = new FormData();
angular.forEach(data, function(value, key) {
fd.append(key, value);
});
drupal.file_attach(nid, fd)
.catch(function(response) {
toaster.pop('error', 'Could not save the file.', response.statusText);
// Or some other error handling.
})
.then(function(data) {
console.log(data);
// Or some other cool action
});
}
According to comments in Services code: 'The name="files[anything]" format is required to use file_save_upload().'
In my example above, $scope.loadedImage is the ng-model set on my file element. According to this article, ng-model doesn’t work on inputs with type=“file”, so I used the custom directive described there to make it work:
.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
&
<input type="file" file-model="loadedImage"/>
Hope this helps, & feel free to include it in Angular Drupal! :camel:
@rhclayto This looks great, thank you. I'd recommend creating a Pull Request for this, and then your code can be merged in and yourself given credit for the contributions.
I'm new to Github so I'll spend a little time learning about pull requests then do it! Thanks.
Okay, I made a pull request. I hope everything's copacetic. Github's tools seems pretty cool.