aayush's avatar

Equivalent of return view('path',compact('data1', 'data2', 'data3' )) in ajax success.

Before I was making:

Controller


        $this->validate($request,[
            'import_file' => 'required',
        ]);

        $db_header_obj = new Voter();
        $db_header = $db_header_obj->getTableColumns();
        $path = $request->file('import_file')->getRealPath();
        $csv = Reader::createFromPath($path, 'r');
            $csv->setHeaderOffset(0); //set the CSV header offset
            $csv_header = $csv->getHeader(); 

            $sample_data = $csv->fetchOne();
            $sample_data = array_values($sample_data);


        $extension = $request->file('import_file')->getClientOriginalExtension(); 
        $filename = uniqid().'_'.time().'_'.date('Ymd').'.'.$extension;
        Storage::disk('local')->putFileAs('/files/voter/', $request->file('import_file'), $filename);

            $arr = [
                'action' => 'storeCSV',
                'table' => $this->table,
            ];
            $this->storeActivity($arr);

            return view('admin.voter.import_fields', compact( 'csv_header', 'db_header','sample_data','filename'));

Form

                            <form action="{{url('admin/voter/sub/storecsv')}}" class="form-horizontal file-upload" id="file_upload" method="post" enctype="multipart/form-data">
                                {{ csrf_field() }}
                                <input required="" type="file" name="import_file" id="import_file" />
                                <br>
                                <br>
                                <button class="btn btn-success btn-sm" id="upload_csv" disabled="true" type="submit">Import CSV or Excel File</button>
                            </form>

Now Ajax

    $(document).ready(function(){
        $('form').submit(function(event){

            event.preventDefault();
            var formData = new FormData($(this)[0]);
            $.ajax({
                headers: { 'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content') },
                url: "{{url('admin/voter/sub/storecsv')}}",
                data: formData,
                type: 'post',
                cache: false,
                xhr: function() {
                    var xhr = new window.XMLHttpRequest();
                    $("#csv_uploading").modal('show');
                    xhr.upload.addEventListener("progress", function(evt) {
                        if (evt.lengthComputable) {
                            var percentComplete = evt.loaded / evt.total;
                            percentComplete = parseInt(percentComplete * 100);
                            $('.uploadProgressBar').attr('aria-valuenow',percentComplete).css('width',percentComplete + '%').text(percentComplete + '%');
                            if (percentComplete === 100) {
                                $("#csv_uploading").modal('hide');
                            }

                        }
                    }, false);

                    return xhr;
                },
                processData: false,
                contentType: false,

                success:function(data){
                    if(data.success === true){
                        window.href
                    }
                }
            });

        });
    });

Required flow:

  1. Upload FIle
  2. Show Progress Bar On uploading
  3. On completion, Load View (admin.voter.import_fields) with data

Note: import_fields is just the partial.

0 likes
21 replies
jlrdw's avatar

Been answered quite a few times look up JavaScript for a redirect

window.location.href = "whatever location";
aayush's avatar

@jirdw And what about the data? How can I pass the data with post method from ajax to view?

aayush's avatar

@cronix after that how can I pass it to view:

Ajax

    $(document).ready(function(){
        $('form').submit(function(event){

            event.preventDefault();
            var formData = new FormData($(this)[0]);
            $.ajax({
                headers: { 'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content') },
                url: "{{url('admin/voter/sub/storecsv')}}",
                data: formData,
                type: 'post',
                cache: false,
                xhr: function() {
                    var xhr = new window.XMLHttpRequest();
                    $("#csv_uploading").modal('show');
                    xhr.upload.addEventListener("progress", function(evt) {
                        if (evt.lengthComputable) {
                            var percentComplete = evt.loaded / evt.total;
                            percentComplete = parseInt(percentComplete * 100);
                            $('.uploadProgressBar').attr('aria-valuenow',percentComplete).css('width',percentComplete + '%').text(percentComplete + '%');
                            if (percentComplete === 100) {
                                $("#csv_uploading").modal('hide');
                            }

                        }
                    }, false);

                    return xhr;
                },
                processData: false,
                contentType: false,

                success:function(data){
                    if(data.success === true){
                        console.log(data);
                    }
                }
            });

        });
    });

Cronix's avatar

you can see it with:

success:function(data){                  
    console.log(data); // all data
    console.log(data.csv_header);  //csv_header
    console.log(data.db_header);
    // etc
}
aayush's avatar

@cronix I can see that now how can I pass it to other view. Lets say I do it window.location.href = 'url'

Now, how can i pass data.csv_header, data_db_header to view. What is the best way to pass it.

Cronix's avatar

If you're redirecting, you can't directly pass it. A redirect is the same as entering http://yoursite.com/some-other-url in the browser.

You could probably store it in session though, and retrieve it in the controller that you are redirecting to.

jlrdw's avatar

You fill the fields or whatever with data. Perhaps view a YouTube video on some jQuery ajax. Plenty of tutorials floating around for free.

aayush's avatar

@cronix at this moment I'm trying to create view. May be I'm not explaining it in correct way.

Let me explain it in detail.

  1. previously I was uploading csv file through php post form submit.
  2. After uploading csv I was loading view as view('admin.voter.import_fields', compact( 'csv_header', 'db_header','sample_data','filename'));

Here, I need to show uploading progress bar, So I decided to move to ajax form submit to upload file.

Now, I can sucessfully upload file with ajax, and also could return data as you mentioned in your first comment. But, till that time the page remains still. This page admin.voter.import_fields is not loading.

As in previous case when I was performing return view.... I don't think there another controller gets involved. As, at that time it might be loading view If I'm not wrong. So, in your opinion what would be best option for me. And how can I load following view with data.

view('admin.voter.import_fields')

And, thank you for your patience.

jlrdw's avatar

Ajax is for a page already loaded, and you update data in a Division or whatever on the fly.

see jquery ajax get response:

https://laracasts.com/discuss/channels/guides/jquery-get-response

For quick example, for post see

https://laracasts.com/discuss/channels/guides/jquery-ajax-post-example

Another good ajax example was in this post https://laracasts.com/discuss/channels/laravel/why-are-not-appearing-all-conferences-that-belong-to-the-clicked-category

Cronix's avatar

is view('admin.voter.import_fields') an entire page on it's own, like html head/body and everything, or is it just a partial view that you want to insert into the current page that the ajax call is making?

jlrdw's avatar

Before I was making:

Maybe easier to show all the before code so we understand exactly what you are tring to do. Very hard to guess. And I don't have ESP, Extrasensory perception.

aayush's avatar

@cronix and @ jirdw, I have updated the question with whole code snippet. I hope, it will give you some idea about what I'm looking for.

~~ I can move back to previous process with no involvement of ajax, if I can show upload progress bar without ajax method.

~~ With ajax method, all the data are available on network -> xhr -> response, but not on main page. Even after uploading, it is remaining still. It is not loading the next view. That is my main problem.

aayush's avatar

@jirdw getting error

The page has expired due to inactivity. Please refresh and try again.

jlrdw's avatar

Also study some examples here of what and how it was done https://jqueryui.com/progressbar/ you may have to play around with the code a bit.

Remember the bar on local will seem much faster, but in live site slower.

One other idea is see if there is a good package for it, like http://image.intervention.io/use/uploads works with images. Perhaps you can find one for files.

Another idea is don't use bar, rather a spinner. You know the round and round thing while operation is in progress.

aayush's avatar

@jirdw I don't get what you are trying to say here. But did you read my previous message?

The page has expired due to inactivity. Please refresh and try again.

This type of situation used to arise when I didn't pass csrf token during form submission.

jlrdw's avatar

You may have to comment out parts of the jquery code, and post something easier till you find where the problem is. Also try alerts along the code.

I don't know if your jquery is correct, but post a simple thing and see if it works and build from there.

This stuff can be tricky and a little trial and error usually finds the problem.

Also double check all code.

Also try as in my example and use getElementsByName to retrieve the CSRF token.

It's probably one little over looked thing.

aayush's avatar

javascript

var _submit = document.getElementById('_submit'), 
_file = document.getElementById('_file'), 
_token = document.getElementsByName('_token')
_progress = document.getElementById('_progress');
var upload = function(){

    if(_file.files.length === 0){
        return;
    }

    var data = new FormData();
    data.append('SelectedFile', _file.files[0]);
    data.append('_token', _token);
    console.log(data);
    var request = new XMLHttpRequest();
    request.onreadystatechange = function(){
        if(request.readyState == 4){
            try {
                var resp = JSON.parse(request.response);
            } catch (e){
                var resp = {
                    status: 'error',
                    data: 'Unknown error occurred: [' + request.responseText + ']'
                };
            }
            console.log(resp.status + ': ' + resp.data);
        }
    };

    request.upload.addEventListener('progress', function(e){
        _progress.style.width = Math.ceil(e.loaded/e.total) * 100 + '%';
    }, false);

    request.open('POST', "<?php echo url('admin/voter/sub/storecsv'); ?>");
    request.send(data);
}

_submit.addEventListener('click', upload);

Html

                            <div class='container'>
                                <p>
                                    Select File:{{ csrf_field() }}<input type='file' id='_file'> <input type='button' id='_submit' value='Upload!'>
                                </p>
                                <div class='progress_outer'>
                                    <div id='_progress' class='progress'></div>
                                </div>
                            </div>

error

The page has expired due to inactivity. Please refresh and try again.

Inquisitive's avatar
Level 9

I don't know if this is what you are looking, but I could show you how you can tackle this problem.

  1. Return just the filename from controller on completion of upload.
return response()->json(array('success' => true, 'filename'=>$filename));
  1. On success submit a form, but before that just place a form on html and make it hiddden. So, on success, on ajax request, submit that form with filename to another controller.
                success:function(data){
                    if(data.success === true){
                        $("#modal_id").modal('hide');
                        $('<input />').attr('type', 'hidden') .attr('name', "filename") .attr('value', data.filename).appendTo('#hidden_form_id');
                        $('#hidden_form_id').submit();
                    }
                }
  1. From that second controller, just return data as in other methods with return view and compact.

Please or to participate in this conversation.