0

Been trying different ways to get a FormData object validated within Laravel. Here is my javascript:

$("#submit-note").click(function(e) {
    e.preventDefault();
    var lead_id = $('input[name="lead_id"]').val();
    var note = $("#note").val();
    var file = $('#file-upload');

    let formData = new FormData($('#edit-form')[0]);

    //JSON.stringify(Array.from(formData));

    console.log(...formData);

    $.ajaxSetup({
        headers: {
            "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content")
        }
    });
    $.ajax({
        url: "/leadme/create-note",
        method: "POST",
        cache:false,
        dataType: false,
        processData: false,
        data: formData,
        success: function(response) {
            console.log('Formdata sent');
            console.log(response);
            $(".toast").toast("show");
        },
        error: function (jqXHR, textStatus, errorThrown) {
            console.log(jqXHR, textStatus, errorThrown);
        }
    });
});

This then gets received by the following Laravel controller:

public function createNote(Request $request)
    {
        $validated = $request->validate([
            '*.lead_id.*' => 'numeric|required',
            '*.note.*' => 'string|required',
            //'files.*' => 'mimes:jpeg, jpg, png, bmp, doc, pdf, mp3, svg, gif, webp|nullable|max:250000',
        ]);

        dd($validated);

        $lead = Lead::where('id', $request->lead_id)->first();

        $validated['date'] = date('Y-m-d');
        $validated['time'] = date('G:i');
        $validated['action'] = 'action';
        $validated['lead_status_option_id'] = 1;
        $validated['user_id'] = auth()->user()->id;

        if ($request->hasFile('files') && !empty($validated['files']->name)) {
            foreach ($request->files as $file) {
                //Get filename with the extension
                $fileNameWithExt = $file->getClientOriginalName();
                //Filename to store example: lead_4_document.pdf
                $fileNameToStore =  'lead_' . $lead->id . '_' . $fileNameWithExt;
                //Upload image
                $path = $file->storeAs('/storage/user_uploads', $fileNameToStore);

                dd($lead->uploadFile->update(array('filename' => $fileNameToStore, 'file_url' => $path)));
            }
        }
        Note::create($validated);
        //$lead->note->update(array('note' => $request->note));
        //$lead->update($validated);
    }

Essentially this controller has to save the submitted note and potentially a number of files attached. Though before I can move onto fixing the images I have to get the notes section right. Also, if you are wondering why I am doing this the way I am, this is what has been recommended to me, apparently it makes the multi-file upload process easier. So far, no success. Any help is appreciated, thank you!

As per @Bazaim's request:

{"------WebKitFormBoundarybD9HBrf3Pp8mqc7o
↵Content-Disposition:_form-data;_name": ""_token"
↵
↵77fGMTkhrymzykdxDahWuriG5mItSJn1EX4j53…m
↵
↵
↵------WebKitFormBoundarybD9HBrf3Pp8mqc7o--"}
"------WebKitFormBoundarybD9HBrf3Pp8mqc7o ↵Content-Disposition:_form-data;_name": ""_token"
↵
↵77fGMTkhrymzykdxDahWuriG5mItSJn1EX4j53kY
↵------WebKitFormBoundarybD9HBrf3Pp8mqc7o
↵Content-Disposition: form-data; name="lead_id"
↵
↵13
↵------WebKitFormBoundarybD9HBrf3Pp8mqc7o
↵Content-Disposition: form-data; name="toggle_option-13"
↵
↵0
↵------WebKitFormBoundarybD9HBrf3Pp8mqc7o
↵Content-Disposition: form-data; name="toggle_option-13-13"
↵
↵2
↵------WebKitFormBoundarybD9HBrf3Pp8mqc7o
↵Content-Disposition: form-data; name="note"
↵
↵dgdgdg
↵------WebKitFormBoundarybD9HBrf3Pp8mqc7o
↵Content-Disposition: form-data; name="file[]"; filename=""
↵Content-Type: application/octet-stream
↵
↵
↵------WebKitFormBoundarybD9HBrf3Pp8mqc7o--"
__proto__:
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()

And here is the extended version of the the hidden text: ""_token"

77fGMTkhrymzykdxDahWuriG5mItSJn1EX4j53kY
------WebKitFormBoundarybD9HBrf3Pp8mqc7o
Content-Disposition: form-data; name="lead_id"

13
------WebKitFormBoundarybD9HBrf3Pp8mqc7o
Content-Disposition: form-data; name="toggle_option-13"

0
------WebKitFormBoundarybD9HBrf3Pp8mqc7o
Content-Disposition: form-data; name="toggle_option-13-13"

2
------WebKitFormBoundarybD9HBrf3Pp8mqc7o
Content-Disposition: form-data; name="note"

dgdgdg
------WebKitFormBoundarybD9HBrf3Pp8mqc7o
Content-Disposition: form-data; name="file[]"; filename=""
Content-Type: application/octet-stream


------WebKitFormBoundarybD9HBrf3Pp8mqc7o--"

After implementing Bazaim's edit: the AJAX looks like this:

$("#submit-note").click(function(e) {
    e.preventDefault();
    var lead_id = $('input[name="lead_id"]').val();
    var note = $("#note").val();
    var file = $('#file-upload');


    let formData = new FormData($('#edit-form')[0]);

    //JSON.stringify(Array.from(formData));

    console.log(...formData);

    $.ajaxSetup({
        headers: {
            "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content")
        }
    });
    $.ajax({
        url: "/leadme/create-note",
        method: "POST",
        cache:false,
        dataType: false,
        processData: false,
        contentType: false,
        data: formData,
        success: function(response) {
            console.log('Formdata sent');
            console.log(response);
            $(".toast").toast("show");
        },
        error: function (jqXHR, textStatus, errorThrown) {
            console.log(jqXHR, textStatus, errorThrown);
        }
    });
});

And the controller like this:

public function createNote(Request $request)
    {
        //return response()->json($request->all());

        $validated = $request->validate([
            'lead_id' => 'numeric|required',
            'note' => 'string|required',
            //'files.*' => 'mimes:jpeg, jpg, png, bmp, doc, pdf, mp3, svg, gif, webp|nullable|max:250000',
        ]);

        $lead = Lead::where('id', $request->lead_id)->first();

        $validated['date'] = date('Y-m-d');
        $validated['time'] = date('G:i');
        $validated['action'] = 'action';
        $validated['lead_status_option_id'] = 1;
        $validated['user_id'] = auth()->user()->id;

        if ($request->hasFile('files') && !empty($validated['files']->name)) {
            foreach ($request->files as $file) {
                //Get filename with the extension
                $fileNameWithExt = $file->getClientOriginalName();
                //Filename to store example: lead_4_document.pdf
                $fileNameToStore =  'lead_' . $lead->id . '_' . $fileNameWithExt;
                //Upload image
                $path = $file->storeAs('/storage/user_uploads', $fileNameToStore);

                dd($lead->uploadFile->update(array('filename' => $fileNameToStore, 'file_url' => $path)));
            }
        }
        Note::create($validated);
        //$lead->note->update(array('note' => $request->note));
        //$lead->update($validated);
    }

The note now gets through and updates successfully. Just need to implement the files next.

BenjaminD
  • 29
  • 1
  • 7

1 Answers1

1

If I understand weel, you have one lead_id.
But your validator required an array of number.

(I've removed *. & .* from the line lead_id.)

Correction :

$validated = $request->validate([
            'lead_id' => 'numeric|required',
            '*.note.*' => 'string|required',
            //'files.*' => 'mimes:jpeg, jpg, png, bmp, doc, pdf, mp3, svg, gif, webp|nullable|max:250000',
        ]);

Can you change your AJAX call for :

(Added contentType: false,)

 $.ajax({
        url: "/leadme/create-note",
        method: "POST",
        cache:false,
        dataType: false,
        processData: false,
        contentType: false,
        data: formData,
        success: function(response) {
            console.log('Formdata sent');
            console.log(response);
            $(".toast").toast("show");
        },
        error: function (jqXHR, textStatus, errorThrown) {
            console.log(jqXHR, textStatus, errorThrown);
        }
    });
Obzi
  • 2,384
  • 1
  • 9
  • 22
  • Hey, thanks for the quick response, this is what it gives me if I do that: responseJSON: responseText: "{"message":"The given data was invalid.","errors":{"lead_id":["The lead id field is required."]}}" This is due to the way the FormData works. I believe the whole thing is a massive array that contains sub-arrays. Essentially even lead_id is an array like [lead_id => 13]. – BenjaminD Sep 14 '20 at 13:41
  • Can you add `return response()->json($request->all());` at the beginning of the method ? and past it on your question. – Obzi Sep 14 '20 at 14:06
  • Added, as per your request. – BenjaminD Sep 14 '20 at 14:17
  • How did you add this code ? It should display a JSON containing values of the request, like : `{'lead_id':13, 'toggle_option-13':0, 'toggle_option-13-13': 2, ....}`. – Obzi Sep 14 '20 at 14:23
  • PS: it's in the Laravel's method `public function createNote(Request $request)`. – Obzi Sep 14 '20 at 14:24
  • Literally as you said: ` public function createNote(Request $request) { return response()->json($request->all()); $validated = $request->validate([ '*.lead_id' => 'numeric|required', '*.note.*' => 'string|required', //'files.*' => 'mimes:jpeg, jpg, png, bmp, doc, pdf, mp3, svg, gif, webp|nullable|max:250000', ]);` – BenjaminD Sep 14 '20 at 14:24
  • That's amazing, I finally get the following: `{_token: "77fGMTkhrymzykdxDahWuriG5mItSJn1EX4j53kY", lead_id: "13", toggle_option-13: "0", toggle_option-13-13: "2", note: "Testing note"} lead_id: "13" note: "Testing note" toggle_option-13: "0" toggle_option-13-13: "2" _token: "77fGMTkhrymzykdxDahWuriG5mItSJn1EX4j53kY" __proto__: Object ` – BenjaminD Sep 14 '20 at 14:43
  • Fine, found the solution here : https://stackoverflow.com/questions/6974684/how-to-send-formdata-objects-with-ajax-requests-in-jquery – Obzi Sep 14 '20 at 14:48
  • This is the answers : https://stackoverflow.com/a/8244082/6887846 – Obzi Sep 14 '20 at 14:52