Integrating a robust multi-image upload component with existing data editing capabilities is a common requirement in content management systems. By combining ThinkPHP 5 with the Bootstrap FileInput plugin, you can handle asynchronous file uploads, preview existing images, and manage deletions seamlessly.
Frontend Form Configuration
First, construct the view template. The form needs a input element configured for multiple file selections. We use ThinkPHP's template engine to bind existing data (like title, category, and content) and include a specific file input for the gallery.
<form id="postForm" method="POST" action="{:url('admin/post/save')}">
<div class="form-group">
<label>Title</label>
<input type="text" name="post_title" id="post_title" class="form-control" value="{$post.title|default=''}" placeholder="Enter post title">
</div>
<div class="form-group">
<label>Category</label>
<select name="cat_id" id="cat_id" class="form-control">
{volist name="categoryList" id="cat"}
<option value="{$cat.id}" {if condition="$post.cat_id == $cat.id"}selected{/if}>{$cat.name}</option>
{/volist}
</select>
</div>
<div class="form-group">
<label>Gallery Images</label>
<input id="gallery-files" name="gallery_files[]" type="file" multiple class="file-loading">
</div>
<div class="form-group">
<label>Content</label>
<textarea name="post_content" id="post_content" class="form-control">{$post.content|default=''}</textarea>
</div>
<input type="hidden" name="__token__" value="{$Request.token}">
<input type="hidden" name="post_id" id="post_id" value="{$post.id|default=''}">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Client-Side Scripting and Initialization
The necessary dependencies include the KindEditor for the textarea, BootstrapValidator for form validation, and the FileInput plugin files (CSS and JS along with the language localization). We will fetch existing images via a AJAX request and configure the FileInput component dynamically.
// Initialize Rich Text Editor
KindEditor.ready(function(K) {
K.create('#post_content', { allowFileManager: true });
});
// Form Validation Setup
$('#postForm').bootstrapValidator({
fields: {
post_title: {
validators: {
notEmpty: { message: 'Title is required' },
stringLength: { min: 2, max: 50, message: 'Title must be between 2 and 50 characters' }
}
},
post_content: {
validators: { notEmpty: { message: 'Content is required' } }
}
}
});
// Load Existing Gallery Images
$(document).ready(function() {
$.post('/admin/post/fetchGallery', { id: $('#post_id').val() }, function(response) {
if (response.status) {
initializeFileInput(response.data);
}
}, 'json');
});
function initializeFileInput(imageData) {
let previewMarkup = [];
let previewConfig = [];
// Build preview array from server response
imageData.forEach(function(item) {
previewMarkup.push(`<img src="${item.url}" class="file-preview-image" style="width:120px">`);
previewConfig.push({
caption: item.filename,
size: item.filesize,
key: item.uid,
url: '/admin/post/removeImage' // Endpoint for AJAX deletion
});
});
// Initialize FileInput Plugin
$('#gallery-files').fileinput({
uploadUrl: '/upload/processImage', // Endpoint for new uploads
uploadAsync: true,
overwriteInitial: false,
initialPreview: previewMarkup,
initialPreviewConfig: previewConfig,
initialPreviewShowDelete: true,
maxFileCount: 10,
dropZoneEnabled: false,
showRemove: false,
allowedPreviewTypes: ['image'],
previewFileIconSettings: {
'doc': '<i class="fa fa-file-word-o text-primary"></i>',
'xls': '<i class="fa fa-file-excel-o text-success"></i>'
}
}).on('fileuploaded', function(event, responseData) {
// Handle post-upload logic, e.g., saving the returned file ID
let fileId = responseData.response.uid;
console.log('Uploaded successfully, ID:', fileId);
});
}
Backend Cnotroller Logic (ThinkPHP 5)
The backend must supply the image data in the specific JSON format expected by the initialPreviewConfig property. Here is a sample controller method that retrieves and formats the gallery data for the frontend.
namespace app\admin\controller;
use think\Controller;
use think\Json;
class Post extends Controller
{
public function fetchGallery()
{
// In a real application, query the database based on the post ID.
// Example hardcoded data for demonstration:
$galleryData = [
[
'url' => 'https://example.com/uploads/img01.jpg',
'uid' => 1001,
'filename' => 'image_alpha.jpg',
'filesize' => 245000
],
[
'url' => 'https://example.com/uploads/img02.jpg',
'uid' => 1002,
'filename' => 'image_beta.png',
'filesize' => 128000
]
];
return json(['status' => true, 'data' => $galleryData]);
}
}