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.

7
  • can you please add the note data .. Commented Sep 14, 2020 at 14:06
  • @Shibon What do you mean? The note data is just a simple text box. The user can enter a message, than attach files to that. Commented Sep 14, 2020 at 14:12
  • Try like this by removing ** Commented Sep 14, 2020 at 14:16
  • $validated = $request->validate([ 'lead_id' => 'numeric|required', 'note' => 'string|required', ]); Commented Sep 14, 2020 at 14:17
  • I have tried that as per what @Bazaim suggested, it didn't work. Commented Sep 14, 2020 at 14:19

1 Answer 1

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);
        }
    });
Sign up to request clarification or add additional context in comments.

9 Comments

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].
Can you add return response()->json($request->all()); at the beginning of the method ? and past it on your question.
Added, as per your request.
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, ....}.
PS: it's in the Laravel's method public function createNote(Request $request).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.