0

I am trying to upload an image using ajax in Laravel, but when I do, I receive this message Call to a member function getClientOriginalExtension() on null. I don't know if there is something wrong with my code. Help!

ProductController

This is where I try to send the image.

public function store(Request $request)
    {
        $validator = Validator::make($request->input(), array(
            'name' => 'required',
            'category_id' => 'required',
            'description' => 'required',
            'price_neto' => 'required',
            'iva' => 'required',
            'price_total' => 'required',
            'image' => 'required|image',
        ));

        $productImage = $request->file('image');
        $productImageName = time() . $productImage->getClientOriginalExtension();
        $productImage->move(public_path("img/products"), $productImageName);

        if ($validator->fails()) {
            return response()->json([
                'error'    => true,
                'messages' => $validator->errors(),
            ], 422);
        }

        $products = Product::create($request->all());

        return response()->json([
            'error' => false,
            'products'  => $products,
        ], 200);
    }

Product.js

This is my Product.js file. It works correctly but now I need to add the image to the product.

$(document).ready(function() {
$("#btn-add").click(function() {
        $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            }
        });

        $.ajax({
            type: 'POST',
            url: '/product',
            data: {
                name: $("#frmAddProduct input[name=name]").val(),
                category_id: $("#frmAddProduct select[name=category_id]").val(),
                description: $("#frmAddProduct input[name=description]").val(),
                price_neto: $("#frmAddProduct input[name=price_neto]").val(),
                iva: $("#frmAddProduct input[name=iva]").val(),
                price_total: $("#frmAddProduct input[name=price_total]").val(),
                image: $("#frmAddProduct input[name=image]").val(),
            },
            dataType: 'json',
            success: function(data) {
                $('#frmAddProduct').trigger("reset");
                $("#frmAddProduct .close").click();
                window.location.reload();

            },
            error: function(data) {
                var errors = $.parseJSON(data.responseText);
                $('#add-product-errors').html('');
                $.each(errors.messages, function(key, value) {
                    $('#add-product-errors').append('<li>' + value + '</li>');
                });
                $("#add-error-bag").show();
            }
        });
    });
});

function addProductForm() {
    $(document).ready(function() {
        $("#add-error-bag").hide();
        $('#addProductModal').modal('show');
    });
}

Product.blade.php

<div class="modal fade" id="addProductModal">
    <div class="modal-dialog">
        <div class="modal-content">
            <form id="frmAddProduct">
                <div class="modal-header">
                    <h5 class="modal-title">
                        <span class="fw-mediumbold">New</span> 
                        <span class="fw-light"> Product</span>
                    </h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>

                <div class="modal-body">
                    <div class="alert alert-danger" id="add-error-bag">
                        <ul id="add-product-errors"></ul>
                    </div>
                    <div class="row">

                        {{-- another code --}}

                        <div class="col-md-6">
                            <div class="form-group">
                                <label>Imagen</label>
                                <input class="form-control-file" id="image" name="image" required="" type="file">
                            </div>
                        </div>

                    </div>
                </div>
                    <div class="modal-footer">
                        <button type="button" id="btn-add" class="btn btn-primary">Add</button>
                        <button type="button" class="btn btn-danger" data-dismiss="modal">Close</button>
                    </div>
            </form>         
        </div>
    </div>
</div>
3
  • Put the condicional if ($validator->fails()) before tying to get the file extension to avoid the exeption if there is not file Commented Oct 23, 2019 at 1:34
  • Then add your inputs to a FormData object and send the formdata stackoverflow.com/a/21045034/7498116 Commented Oct 23, 2019 at 1:53
  • Try changing from image: $("#frmAddProduct input[name=image]").val() to image: $("#frmAddProduct input[name=image]")[0].files[0] in your data object Commented Oct 23, 2019 at 4:27

3 Answers 3

1

You can't pass an image through ajax by getting the element's value. Also, it's convenient and preferred to use FormData object to send files to the server via ajax.

So, try this instead:

// Select the image holding element.
var productImage = document.querySelector('#frmAddProduct input[name=image]');

// Creating an instance of FormData to submit the form.
var formData = new FormData();
formData.append('name', $("#frmAddProduct input[name=name]").val());
formData.append('category_id', $("#frmAddProduct select[name=category_id]").val());
formData.append('description', $("#frmAddProduct input[name=description]").val());
formData.append('price_neto', $("#frmAddProduct input[name=price_neto]").val());
formData.append('iva', $("#frmAddProduct input[name=iva]").val());
formData.append('price_total', $("#frmAddProduct input[name=price_total]").val());
formData.append('image', productImage.files[0]);

$.ajax({
    type: 'POST',
    url: '/product',
    data: formData,
    processData: false,
    contentType: false,
    dataType: 'json',
    success: function(data) {
        $('#frmAddProduct').trigger("reset");
        $("#frmAddProduct .close").click();
        window.location.reload();

    },
    error: function(data) {
        var errors = $.parseJSON(data.responseText);
        $('#add-product-errors').html('');
        $.each(errors.messages, function(key, value) {
            $('#add-product-errors').append('<li>' + value + '</li>');
        });
        $("#add-error-bag").show();
    }
});
Sign up to request clarification or add additional context in comments.

Comments

0

You need to use FormData:

$("#btn-add").click(function(){
    var formData = new FormData($("#frmAddProduct")[0]);
    $.ajaxSetup({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        }
    });
    $.ajax({
        type: 'POST',
        url: '/product',
        data: formData,
        dataType: 'json',
        success: function(data) {
            $('#frmAddProduct').trigger("reset");
            $("#frmAddProduct .close").click();
            window.location.reload();
        },
        error: function(data) {
            var errors = $.parseJSON(data.responseText);
            $('#add-product-errors').html('');
            $.each(errors.messages, function(key, value) {
                $('#add-product-errors').append('<li>' + value + '</li>');
            });
            $("#add-error-bag").show();
        }
    });
});

2 Comments

Thanks! That works too. I am going to use this method.
Glad I can help.
0

This is my code after some corrections.

Product Controller

public function store(Request $request)
    {
        $validator = Validator::make($request->input(), array(
            'name' => 'required',
            'category_id' => 'required',
            'description' => 'required',
            'price_neto' => 'required',
            'iva' => 'required',
            'price_total' => 'required',
            'image' => '',
        ));

        $productImage = $request->file('image');
        $productImageName = rand() . '.' . $productImage->getClientOriginalExtension();
        $productImage->move(public_path('img/products'), $productImageName);

        if ($validator->fails()) {
            return response()->json([
                'error'    => true,
                'messages' => $validator->errors(),
            ], 422);
        }

        $products = Product::create([
            'name' => $request->name,
            'category_id' => $request->category_id,
            'description' => $request->description,
            'price_neto' => $request->price_neto,
            'iva' => $request->iva,
            'price_total' => $request->price_total,
            'image' => $productImageName,
        ]);

        return response()->json([
            'error' => false,
            'products'  => $products,
        ], 200);
    }

Product.js

$("#btn-add").click(function() {

        var formData = new FormData($("#frmAddProduct")[0]);

        $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            }
        });

        $.ajax({
            type: 'POST',
            url: '/product',
            data: formData,
            processData: false,
            contentType: false,
            dataType: 'json',
            success: function(data) {
                $('#frmAddProduct').trigger("reset");
                $("#frmAddProduct .close").click();
                window.location.reload();

            },
            error: function(data) {
                var errors = $.parseJSON(data.responseText);
                $('#add-product-errors').html('');
                $.each(errors.messages, function(key, value) {
                    $('#add-product-errors').append('<li>' + value + '</li>');
                });
                $("#add-error-bag").show();
            }
        });
    });

And in my form, I just added enctype= "multipart/form-data". Thanks!

Comments

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.