0

I have a requirement where every file selected for upload should contain a dropdown to choose from predefined values. I can create a plain select by injecting a piece of code similar to the input in Multiple file upload with extra inputText. But My requirement is to have a primefaces one menu, a dropdown like interface with same look and feel (as in p:selectOneMenu). The expected result is some thing like the bwloe image. Required FileUpload Inteface with primefaces.

Sandeep YS
  • 11
  • 6
  • Simply not possible without a lot of hacking... But you might try to put a plain html select in there and use Prime-UI to style it like a p:selectOneMenu. – Kukeltje Apr 17 '18 at 11:19
  • @Kukeltje i can go through the primefaces source to check the renderer/js and replicate similar tag. Any ideas to apply similar style would be appriciated as the UI rendered by primefaces is by masking the actual select element and reconstructing the div components for dropdown. So plain select will not work in this case – Sandeep YS Apr 17 '18 at 14:10
  • No I stated PrimeUI! It is a plain javascript library that can 'render' the plain select as something with the look of PrimeFaces – Kukeltje Apr 17 '18 at 14:13
  • @Kukeltje. Thanks for your help. I was able to achieve this using Prime-UI. One change I had to do was change some style classes in the dropdown.js of Prime-UI with class from p:selectOneMenu. – Sandeep YS Apr 18 '18 at 08:34
  • Great that the idea I had works. Can you please create an asnwer... Would be very helpful to others (including myself ;-)). – Kukeltje Apr 18 '18 at 08:38

1 Answers1

1

Override the PrimeFaces implementation of fileupload widget and modify the add option for each file.

under the row variable add the below line

.append('<div><select class="custom-select" name="title['+ file.name +']" style="width:180px;"></select></div>')

After this statement add the below block to convert the select element to Prime-UI dropdown:

var themes = new Array('afterdark', 'afternoon', 'afterwork', 'vader'); 
$(row).find('.custom-select').puidropdown({
    filter: true,
    data: themes
});

So the overall implementation of add would look like:

add: function(e, data) {
            $this.chooseButton.removeClass('ui-state-hover ui-state-focus');

            if($this.fileAddIndex === 0) {
                $this.clearMessages();
            }

            if($this.cfg.fileLimit && ($this.uploadedFileCount + $this.files.length + 1) > $this.cfg.fileLimit) {
                $this.clearMessages();
                $this.showMessage({
                    summary: $this.cfg.fileLimitMessage
                });

                return;
            }

            var file = data.files ? data.files[0] : null;
            if(file) {
                var validMsg = $this.validate(file);

                if(validMsg) {
                    $this.showMessage({
                        summary: validMsg,
                        filename: PrimeFaces.escapeHTML(file.name),
                        filesize: file.size
                    });
                }
                else {
                    var row = $('<div class="ui-fileupload-row"></div>').append('<div class="ui-fileupload-preview"></td>')
                            .append('<div>' + PrimeFaces.escapeHTML(file.name) + '</div>')
                            .append('<div>' + $this.formatSize(file.size) + '</div>')
                            <b>.append('<div><select class="custom-select" name="title['+ file.name +']" style="width: 180px;"></select></div>')</b>
                            .append('<div class="ui-fileupload-progress"></div>')
                            .append('<div><button class="ui-fileupload-cancel ui-button ui-widget ui-state-default ui-corner-all ui-button-icon-only"><span class="ui-button-icon-left ui-icon ui-icon ui-icon-close"></span><span class="ui-button-text">ui-button</span></button></div>')
                            .appendTo($this.filesTbody);

                            var themes = new Array('afterdark', 'afternoon', 'afterwork', 'vader');

                            $(row).find('.custom-select').puidropdown({
                                filter: true,
                                data: themes
                            });

                    if($this.filesTbody.children('.ui-fileupload-row').length > 1) {
                        $('<div class="ui-widget-content"></div>').prependTo(row);
                    }

                    //preview
                    if(window.File && window.FileReader && $this.IMAGE_TYPES.test(file.name)) {
                        var imageCanvas = $('<canvas></canvas>')
                                                .appendTo(row.children('div.ui-fileupload-preview')),
                        context = imageCanvas.get(0).getContext('2d'),
                        winURL = window.URL||window.webkitURL,
                        url = winURL.createObjectURL(file),
                        img = new Image();

                        img.onload = function() {
                            var imgWidth = null, imgHeight = null, scale = 1;

                            if($this.cfg.previewWidth > this.width) {
                                imgWidth = this.width;
                            }
                            else {
                                imgWidth = $this.cfg.previewWidth;
                                scale = $this.cfg.previewWidth / this.width;
                            }

                            var imgHeight = parseInt(this.height * scale);

                            imageCanvas.attr({width:imgWidth, height: imgHeight});
                            context.drawImage(img, 0, 0, imgWidth, imgHeight);
                        };

                        img.src = url;
                    }

                    //progress
                    row.children('div.ui-fileupload-progress').append('<div class="ui-progressbar ui-widget ui-widget-content ui-corner-all" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="ui-progressbar-value ui-widget-header ui-corner-left" style="display: none; width: 0%;"></div></div>');

                    file.row = row;

                    file.row.data('filedata', data);

                    $this.files.push(file);

                    if($this.cfg.auto) {
                        $this.upload();
                    }
                }

                if($this.files.length > 0) {
                    $this.enableButton($this.uploadButton);
                    $this.enableButton($this.cancelButton);
                }

                $this.fileAddIndex++;
                if($this.fileAddIndex === (data.originalFiles.length)) {
                    $this.fileAddIndex = 0;
                }
            }
        }   

Include the necessary scripts in the facelet:

<script type="text/javascript" src="x-tag-core.min.js"></script>
<script type="text/javascript" src="core.js"></script>
<script type="text/javascript" src="inputtext-element.js"></script>
<script type="text/javascript" src="inputtext.js"></script>
<script type="text/javascript" src="dropdown-element.js"></script>
<script type="text/javascript" src="dropdown.js"></script>

Create a primefaces fileUpload Component with an uploadListener in the bean:

public void handleFileUpload(FileUploadEvent event) {
    FacesContext context = FacesContext.getCurrentInstance();
    Map map = context.getExternalContext().getRequestParameterMap();
    String paramName = "title["+event.getFile().getFileName()+"]";
    String fileWithTitle = (String) map.get(paramName);            
}

Now modify the styles in the dropdown.js to reflect the default styles used by primefaces as follows.

replace styles by name ui-dropdown by ui-selectonemenu

This would yield a result as in this link final UI

Sandeep YS
  • 11
  • 6
  • Thanks! Clear explanation – Kukeltje Apr 18 '18 at 11:16
  • Current solution resets the dropdown every time a file is added. need to handle the puidropdown by modifying $(row).find('.custom-select').puidropdown. Will update the solution as well. – Sandeep YS Apr 23 '18 at 07:56