在提交之前使用Ajax上传文件的最佳方式

时间:2017-12-03 19:49:03

标签: javascript php jquery ajax laravel

我有一个包含多个字段的表单,但也有一个文件上传。我可以上传多个文件。

我也知道可以使用AJAX上传文件。 因此,我希望使用ajax上传我的文件,同时填写其他所有字段。但是,如何链接已上传的图像呢?还会阻止图像再次上传?

这是表格:

(function() {

      init(); //on page load - show first slide, hidethe rest

      function init() {

        parents = document.getElementsByClassName('slideshow-container');

        for (j = 0; j < parents.length; j++) {
          var slides = parents[j].getElementsByClassName("mySlides");
          var dots = parents[j].getElementsByClassName("dot");
          slides[0].classList.add('active-slide');
          dots[0].classList.add('active');
        }
      }

      dots = document.getElementsByClassName('dot'); //dots functionality

      for (i = 0; i < dots.length; i++) {

        dots[i].onclick = function() {

          slides = this.parentNode.parentNode.getElementsByClassName("mySlides");

          for (j = 0; j < this.parentNode.children.length; j++) {
            this.parentNode.children[j].classList.remove('active');
            slides[j].classList.remove('active-slide');
            if (this.parentNode.children[j] == this) {
              index = j;
            }
          }
          this.classList.add('active');
          slides[index].classList.add('active-slide');

        }
      }
    //prev/next functionality
      links = document.querySelectorAll('.slideshow-container a');

      for (i = 0; i < links.length; i++) {
        links[i].onclick = function() {
          current = this.parentNode;

          var slides = current.getElementsByClassName("mySlides");
          var dots = current.getElementsByClassName("dot");
          curr_slide = current.getElementsByClassName('active-slide')[0];
          curr_dot = current.getElementsByClassName('active')[0];
          curr_slide.classList.remove('active-slide');
          curr_dot.classList.remove('active');
          if (this.className == 'next') {
            console.log('next ', curr_slide);
            if (curr_slide.nextElementSibling.classList.contains('mySlides')) {
              curr_slide.nextElementSibling.classList.add('active-slide');
              curr_dot.nextElementSibling.classList.add('active');
            } else {
              slides[0].classList.add('active-slide');
              dots[0].classList.add('active');
            }

          }

          if (this.className == 'prev') {
            console.log('previous ', curr_slide);
              if (curr_slide.previousElementSibling.classList.contains('mySlides')) {
                  curr_slide.previousElementSibling.classList.add('active-slide');
                  curr_dot.previousElementSibling.classList.add('active');
                } else {
                    slides[slides.length - 1].classList.add('active-slide');
                 dots[slides.length - 1].classList.add('active');
            }

          }

        }

      }
    })();

这是保存表单信息的PHP代码:

<form id="form_validation" method="POST" action="{{route('storeexpense')}}" enctype="multipart/form-data">
                            {{ csrf_field() }}
                            <div class="form-group form-float">
                                <div class="form-line">
                                    <input type="text"  class="form-control" name="description" required>
                                    <label class="form-label">Omschrijving</label>
                                </div>
                            </div>
                            <div class="form-group form-float">
                                <div class="form-line">
                                    <input type="number" class="form-control" name="amount" required>
                                    <label class="form-label">Bedrag</label>
                                </div>
                            </div>
                            <div class="form-group form-float">
                                @foreach ($types as $type)
                                    @if ($type->id === 1)
                                        <input name="transactiontype" type="radio" id="rdio{{$type->id}}" value="{{$type->id}}" checked />
                                        <label for="rdio{{$type->id}}">{{$type->description}}</label>
                                    @else
                                        <input name="transactiontype" type="radio" id="rdio{{$type->id}}" value="{{$type->id}}" />
                                        <label for="rdio{{$type->id}}">{{$type->description}}</label>
                                    @endif
                                @endforeach
                            </div>
                            <div class="form-group form-float">
                                <div class="form-line">
                                    <input type="text" class="datepicker form-control" name="date" placeholder="Please choose a date..." required>

                                    <!-- <label class="form-label">Datum</label> -->
                                </div>
                            </div>
                            <div class="form-group demo-tagsinput-area">
                                <div class="form-line">
                                    <input type="text" class="form-control" id="tagsinput" data-role="tagsinput" placeholder="Labels" name="tags" required>

                                </div>
                            </div>
                            <div class="form-group form-float">
                                <div class="form-line">
                                     @if (count($errors) > 0)
                                        <ul>
                                            @foreach ($errors->all() as $error)
                                                <li>{{ $error }}</li>
                                            @endforeach
                                        </ul>
                                    @endif
                                    <input type="file" name="attachments[]" multiple class="custom-file-control"/>
                                </div>
                            </div>


                            <button class="btn btn-primary waves-effect" type="submit">SAVE</button>
                        </form>

谢谢, 巴特

1 个答案:

答案 0 :(得分:1)

听起来你想制作一个花哨的表格,一旦你选择它就开始上传文件,同时用户可以继续填写表格的其余部分。如果是这样,我就这样做:

实施您的主要文本/数据表单,例如

<form method="POST" action="/save-data-endpoint.php">
    <input name="email" type="text" />
    <button type="submit>Submit</button>
</form>

在它旁边,一个图像的表单。例如

<form method="POST" class="file-upload-form" action="/save-file.php">
    <input name="my-file" type="file" />
    <!-- note that we wont show a submit button -->
</form>

对于用户来说,它们看起来都是相同的形式,但点击提交按钮只会将数据发送到save-data-endpoint.php。现在我们需要一些j来控制这种疯狂(为了简洁,我将使用jQuery)。但你可以在js中使用FileReader api,ajax进度跟踪使它更加漂亮。有关详情,请参阅https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications

$(function(){ // run when document is ready
    // listen when the input changes (when a file is selected)
    $('.file-upload-form').on('change', function(e){
        // file has been selected, submit it via ajax
        // show some kind of uploading indication, eg. a spinner
        $.ajax({
            type:'POST',
            url: $(this).attr('action'),
            data: new FormData(this),
            cache:false,
            contentType: false,
            processData: false,
            success:function(data){
                // the save-file.php endpoint returns an id and/or a url to the saved/resized/sanitized image
                console.log(data.id, data.url);
                // we then inject this id/url, into the main data form
                var $hiddenInput = $('<input type="hidden" name="uploads[]" value="'+data.id+'">');
                $('.main-form').append($hiddenInput);

                // show a thumbnail maybe?
                var $thumbnail = $('<img src="'+data.url+'" width="20" height="20" />');
                $('.main-form').append($thumbnail);

                // hide spinner
                // reactivate file upload form to choose another file
                $('.file-upload-form').find('input').val('');
            },
            error: function(){
                console.log("error");
            }
        });
    });
});

您的后端将逐个获取所选图像。然后保存它们并将id和/或url返回到js中成功处理程序中使用的图像。添加一些图像后,您的主要表单应如下所示:

<form method="POST" action="/save-data-endpoint.php">
    <input name="email" type="text" />
    <button type="submit>Submit</button>

    <input type="hidden" name="uploads[]" value="x">
    <img src="...x.jpg" width="20" height="20" />
    <input type="hidden" name="uploads[]" value="y">
    <img src="...y.jpg" width="20" height="20" />
</form>

现在,当用户填写剩余字段并单击“提交”时,您的服务器将获取所有数据以及名为uploads的数组,其中包含您已保存的所有图像ID /路径。您现在可以存储此数据并将其与文件相关联。

我不会在后端更深入,因为它可以在任何语言上实现。总之,基本流程将是:

  • 一次发送一个文件到保存文件端点,该端点返回文件标识符(可以是id,哈希,图像的完整路径等)
  • js将这些ID注入主窗体
  • 将主表单提交给保存数据端点,该端点返回成功或错误消息,并将所有数据存储+关联到您首选的存储方法中。

希望它有所帮助!