Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.2k views
in Technique[技术] by (71.8m points)

jsf - Multiple file upload with extra inputText

I need to implement the following:

  1. multiple file upload in ajax style (without refreshing whole page)
  2. description field per file
  3. it must be done with JSF 2.0

There isn't problem to do 2 of 3 requirement in any combination. Multiple fileUpload with JSF 2.0 = PrimeFaces, multiple file upload + description is possible with JSF 2.2 because it has native upload element (I guess it can be ajaxed but didn't check it because I can't use it), but when I get all three requirements together I get stuck. On PrimeFaces's p:fileUpload there isn't description field and its simple mode doesn't support ajax. JSF 2.0 doesn't have native fileUpload component. I can bind description field with PrimeFaces's p:fileUpload but I can't prevent from a user to choose multiple files and it cause that few files will be tied to one description.

So, is it possible to do multiple file upload in ajax style with description field in PrimeFaces and JSF 2.0?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

PrimeFaces upload is based on blueimp/jQuery-File-Upload.

When .serializeArray() gets called, all the data inside that form would be serialized.

In that case you could override the PrimeFaces implementation of the add option to append one extra input text for each file.

So the result would look like this:

fileUpload with title

Now that would be one extra line of code, exactly here:

.append('<td class="title"><label>Title: <input name="title['+ file.name +']"></label></td>') //the only modification we have to do

The extra input text is called title[fileName], in that case you would get the value of the request parameter by the current file name.

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);            
}

Here's the full implementation of the add option (assuming your widgetVar is fileUpload)

$(document).ready(function() {
   setTimeout(fileUpload, 1000);
})

function fileUpload() {

PF('fileUpload').jq.fileupload({
    add: function(e, data) {
        $this = PF('fileUpload');
        $this.chooseButton.removeClass('ui-state-hover ui-state-focus');
        if ($this.files.length === 0) {
            $this.enableButton($this.uploadButton);
            $this.enableButton($this.cancelButton);
        }

        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: file.name,
                    filesize: file.size
                });
            }
            else {
                $this.clearMessages();                                                                               
                //the only modification we have to do
                var row = $('<tr></tr>').append('<td class="ui-fileupload-preview"></td>')
                        .append('<td>' + file.name + '</td>')
                        .append('<td class="title"><label>Title: <input name="title['+ file.name +']"></label></td>') 
                        .append('<td>' + $this.formatSize(file.size) + '</td>')
                        .append('<td class="ui-fileupload-progress"></td>')
                        .append('<td><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></td>')
                        .appendTo($this.filesTbody);

                
                if ($this.isCanvasSupported() && window.File && window.FileReader && $this.IMAGE_TYPES.test(file.name)) {
                    var imageCanvas = $('<canvas></canvas')
                            .appendTo(row.children('td.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('td.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();
                }
            }
        }
    }});
}

Just included the above code in some js file and included it before the end of </h:body>

Here's an online Demo.

Note: the only drag you might have in this approach, if the user has selected multiple files with the same exact name and extension you would get the first title twice!, for some this would be okay, since the user isn't supposed to upload identical files.

This is test on PrimeFaces 5.0 and Chrome.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...