@@ -5,8 +5,9 @@ import { Controller } from "@hotwired/stimulus";
55 *
66 * This controller:
77 * - Listens for file selection on an `<input type="file" multiple="multiple">`
8- * - Displays selected file names in a custom list **when multiple files are selected
9- * - Defaults to the browser’s built-in display for a single file selection
8+ * - Displays selected file names in a custom list when multiple files are selected
9+ * - If provided a `filenames` array, displays those file names as if user had just selected them.
10+ * This is useful for displaying previously selected files on page load with validation errors.
1011 *
1112 * Expected HTML structure should have a placeholder div for the selected file names:
1213 *
@@ -20,29 +21,60 @@ import { Controller } from "@hotwired/stimulus";
2021export default class extends Controller {
2122 static targets = [ "input" , "list" ] ;
2223
24+ static values = {
25+ filenames : Array
26+ }
27+
2328 connect ( ) {
2429 this . inputTarget . addEventListener ( "change" , ( ) => this . updateFileList ( ) ) ;
30+
31+ if ( this . hasFilenamesValue && this . filenamesValue . length > 0 ) {
32+ this . updateFileListFromValue ( ) ;
33+ }
34+ }
35+
36+ // Opens the hidden file input when "Choose Files" button is clicked
37+ triggerFileSelection ( ) {
38+ this . inputTarget . click ( ) ;
2539 }
2640
41+ // native file input selection
2742 updateFileList ( ) {
2843 const files = this . inputTarget . files ;
29- this . listTarget . innerHTML = "" ; // Clear previous list
3044
31- // If no files or only one file is selected, let the native UI handle it
32- if ( files . length <= 1 ) {
45+ if ( files . length === 0 ) {
3346 return ;
3447 }
3548
49+ this . renderFileList ( Array . from ( files ) . map ( file => file . name ) ) ;
50+ }
51+
52+ updateFileListFromValue ( ) {
53+ this . renderFileList ( this . filenamesValue ) ;
54+ }
55+
56+ renderFileList ( fileNames ) {
57+ // Clear previous list
58+ this . listTarget . innerHTML = "" ;
59+
60+ // Create subheader
61+ const header = document . createElement ( "p" ) ;
62+ header . textContent = "Selected files:" ;
63+ header . classList . add ( "font-weight-bold" , "mb-1" ) ;
64+
65+ // Create file list
3666 const ul = document . createElement ( "ul" ) ;
3767 ul . classList . add ( "list-unstyled" , "mt-2" ) ;
3868
39- Array . from ( files ) . forEach ( ( file ) => {
69+ fileNames . forEach ( ( name ) => {
4070 const li = document . createElement ( "li" ) ;
4171 li . classList . add ( "p-1" , "rounded" , "mb-1" ) ;
42- li . textContent = file . name ;
72+ li . textContent = name ;
4373 ul . appendChild ( li ) ;
4474 } ) ;
4575
76+ // Append header and list to target container
77+ this . listTarget . appendChild ( header ) ;
4678 this . listTarget . appendChild ( ul ) ;
4779 }
4880}
0 commit comments