Моя модель AngularJS имеет два свойства: файловый объект vm.profile.file
и текстовое значение, содержащее ссылку на загруженный на сервер файл vm.profile.resume
. vm.profile.file
проверяется по мере необходимости с ограниченным размером. Тем не менее, когда форма обновляется, ссылка, которая является приемлемой и передается на сервер, в порядке, но нет необходимости в том, чтобы файловый объект снова устанавливался на сервер. Как проверить форму, если ссылка на файл существует, а ненужный файловый объект пуст?
Вот часть кода, который я использую:
<div class="sj-section-content" flex="60">
<md-card>
<md-input-container>
<div layout="row" layout-align="start center">
<md-button class="md-primary md-raised"
style="max-width: 150px; color: white;"
ngf-select
required
name="resume"
ngf-min-size="0MB"
ngf-max-size="1MB"
ng-model="vm.profile.file">
<span>{{!vm.profile.resume ? 'Select file' : 'Change'}}</span>
</md-button>
<md-button ng-if="vm.profile.resume" ng-click="vm.profile.file = {}" class="md-icon-button">
<md-icon md-font-icon="clear">clear</md-icon>
</md-button>
</div>
<div ng-if="vm.profile.file.name" layout="row" layout-align="start center">
<md-button class="md-icon-button" md-no-ink>
<md-icon md-font-icon="attachment">attachment</md-icon>
</md-button>
<div>{{vm.profile.file.name}}</div>
</div>
<div ng-messages="profileForm.resume.$error"
ng-if="profileForm.resume.$error && (profileForm.$submitted || profileForm.resume.$dirty)"
role="alert">
<div ng-if="profileForm.resume.$error.maxSize"
ng-message="maxSize">Max file size is 10MB</div>
<div ng-if="profileForm.resume.$error.required"
ng-message="required">Resume is a required field</div>
</div>
</md-input-container>
</md-card>
</div>
Служба API:
ProfileApi.prototype.update = function update(model) {
var deferred = $q.defer();
Upload.upload({
url: endpoint,
method: 'PUT',
data: model
}).then(function success(response) {
deferred.resolve(response.data);
}, function error(response) {
deferred.reject(response.data);
});
return deferred.promise;
};
И на сервере:
exports.fileHandler = function(req, res, next) {
var MAX_FILE_SIZE = 10 * 1000000;
var FILE_FIELD = 'file';
var PARENT_DIRECTORY = 'files/resumes/';
// Validate here
var fileFilter = function fileFilter (req, file, callback) {
// allowed extensions .doc .docx .odt .pdf .txt
var allowedMimeTypes = [
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.oasis.opendocument.text',
'application/pdf',
'text/plain'
];
var validMimetype = allowedMimeTypes.some(function(mimetype) {
return file.mimetype == mimetype;
});
if (!validMimetype) return callback(new Error('Resume is not a valid file format'));
callback(null, true)
};
var fileOptions = {
fileFilter: fileFilter,
dest: 'tmp/',
limits: {
fileSize: MAX_FILE_SIZE
}
};
var upload = multer(fileOptions).single(FILE_FIELD);
upload(req, res, function(err) {
if (err) return res.status(400).send({message: err.message});
// We don't need a new file if req.body.resume has a value
console.log(typeof req.body.resume);
if (_.isEmpty(req.body.resume) && typeof req.file === 'undefined') {
return res.status(400).send({message: 'Resume file is required'});
}
// Make sure that if there is a resume file but no new file, the resume exists in the file system.
if (req.body.resume && typeof req.file === 'undefined') {
fs.stat('client/' + req.body.resume, function(err, stats) {
if (err) {
return res.status(400).send({message: 'Resume doesn\'t exist on file server'});
} else {
return next();
}
})
} else {
// Let's add the file path at req.body.resume.
// The idea is that if the save method on the model returns and error. Delete the file
// in the tmp folder. Then return an error. If the model validates and is saved. Move the
// file into the proper folder
req.body.resume = PARENT_DIRECTORY + req.user._id + '/' + req.file.originalname;
return next();
}
});
};
Метод контроллера обновления:
exports.update = function(req, res) {
var crewListing = req.app.locals.crewListing;
// Protect information
delete req.body.author;
delete req.body.__v;
delete req.body._id;
// Merge objects
_.merge(crewListing, req.body);
crewListing.save({runValidators: true}, function(err, result) {
if (req.file) {
if (err) {
// Delete the req file
fs.unlink(req.file.path, function() {
return res.status(400).send(validationErrorHandler(err,true));
});
} else {
// Move the req file
console.log(req.file);
fs.move(req.file.path, 'client/' + crewListing.resume, {clobber: true}, function(err) {
if (err) return res.status(400).send({message: 'Unexpected error has occured'})
return res.json(result);
});
}
} else {
if (err) return res.status(400).send(validationErrorHandler(err, true));
return res.json(result);
}
})
};