So I have Laravel project and I use Ajax for CRUD.
This is my Controller:
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$rules = array(
'naziv' => 'required|max:90|unique:restaurants',
'adresa' => 'required|max:150',
'min_dostava' => 'required|max:5',
'vrijeme_dostave' => 'required|max:10',
'cijena_dostave' => 'required|max:5',
'podrucije_grada' => 'required',
'br_telefona' => 'required|numeric|unique:restaurants',
'kuhinja_id' => 'required',
'user_id' => 'required',
'lokacija' => 'max:999',
);
$error = Validator::make($request->all(), $rules);
if($error->fails())
{
return response()->json(['errors' => $error->errors()->all()]);
}
// logo
$logo = $request->file('logo');
$filename = $logo->getClientOriginalName();
//Fullsize
$logo->move(public_path().'/uploads/',$filename);
$image_resize = Image::make(public_path().'/uploads/'.$filename);
$image_resize->fit(800, 600);
$image_resize->save(public_path('uploads/'.$filename));
// logo finish
$restaurant = Restaurant::updateOrCreate(['id' => $request->restaurant_id],
[
'naziv' => $request->naziv,
'adresa' => $request->adresa,
'min_dostava' => $request->min_dostava,
'vrijeme_dostave' => $request->vrijeme_dostave,
'cijena_dostave' => $request->cijena_dostave,
'podrucije_grada' => $request->podrucije_grada,
'br_telefona' => $request->br_telefona,
'kuhinja_id' => $request->kuhinja_id,
'user_id' => $request->user_id,
'lokacija' => $request->lokacija,
'logo' => $filename
]);
$restaurant->save();
if($restaurant->wasChanged()){
return response()->json(['success'=>'Uspjesno ste izmijenili restoran.']);
}
return response()->json(['success'=>'Uspjesno ste dodali novi restoran.']);
}
And a part of form where is file input in my blade:
<div class="form-group">
<label for="exampleFormControlFile1" class="form-control-sm">Logorestorana</label>
<input type="file" class="form-control-file" id="logo" name="logo" value="">
</div>
And my jquery script:
<script type="text/javascript">
$(function () {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
var table = $('#dataTable').DataTable({
processing: true,
serverSide: true,
ajax: "{{ route('admin.restaurants.index') }}",
columns: [
{data: 'id', name: 'id'},
{data: 'logo', name: 'logo'},
{data: 'naziv', name: 'naziv'},
{data: 'adresa', name: 'adresa'},
{data: 'min_dostava', name: 'min_dostava'},
{data: 'vrijeme_dostave', name: 'vrijeme_dostave'},
{data: 'cijena_dostave', name: 'cijena_dostave'},
{data: 'podrucije_grada', name: 'podrucije_grada'},
{data: 'br_telefona', name: 'br_telefona'},
{data: 'kuhinja_id', name: 'kuhinja_id'},
{data: 'user_id', name: 'user_id'},
{data: 'lokacija', name: 'lokacija'},
{data: 'action', name: 'action', orderable: false, searchable: false},
]
});
$('#createNewProduct').click(function () {
$('#saveBtn').val("create-product");
$('#restaurant_id').val('');
$('#productForm').trigger("reset");
$('#modelHeading').html("Create New Product");
$('#ajaxModel').modal('show');
});
$('body').on('click', '.editProduct', function () {
var restaurant_id = $(this).data('id');
$.get("{{ route('admin.restaurants.index') }}" +'/' + restaurant_id +'/edit', function (data) {
$('#modelHeading').html("Edit Product");
$('#saveBtn').val("edit-user");
$('#ajaxModel').modal('show');
$('#restaurant_id').val(data.id);
$('#naziv').val(data.naziv);
$('#adresa').val(data.adresa);
$('#min_dostava').val(data.min_dostava);
$('#vrijeme_dostave').val(data.vrijeme_dostave);
$('#cijena_dostave').val(data.cijena_dostave);
$('#podrucije_grada').val(data.podrucije_grada);
$('#br_telefona').val(data.br_telefona);
$('#kuhinja_id').val(data.kuhinja_id);
$('#br_telefona').val(data.br_telefona);
$('#lokacija').val(data.lokacija);
$('#logo').val(data.logo);
})
});
$('#saveBtn').click(function (e) {
e.preventDefault();
$(this).html('+ Novi restoran');
$.ajax({
data: $('#productForm').serialize(),
url: "{{ route('admin.restaurants.store') }}",
type: "POST",
dataType: 'json',
success: function (data) {
var html = '';
if(data.errors)
{
html = '<div class="alert alert-danger">';
for(var count = 0; count < data.errors.length; count++)
{
html += '<p>' + data.errors[count] + '</p>';
}
html += '</div>';
}
if(data.success)
{
html = '<div class="alert alert-success alert-dismissible fade show" role="alert"><strong><i class="fas fa-check-circle"></i> ' + data.success + '</strong><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button></div>';
$('#productForm').trigger("reset");
$('#ajaxModel').modal('hide');
table.draw();
}
$('#form_result').html(html);
}
});
});
$('body').on('click', '.deleteProduct', function () {
var restaurant_id = $(this).data("id");
confirm("Are You sure want to delete !");
$.ajax({
type: "DELETE",
url: "{{ route('admin.restaurants.store') }}"+'/'+restaurant_id,
success: function (data) {
table.draw();
html = '<div class="alert alert-danger alert-dismissible fade show" role="alert"><strong><i class="fas fa-trash"></i> ' + data.success + '</strong><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button></div>';
$('#form_result').html(html);
},
error: function (data) {
console.log('Error:', data);
}
});
});
});
</script>
ISSUE
I'm keep getting same issue in my Network console and it is
Call to a member function getClientOriginalName() on null
What I'm doing wrong here?
I also included #crsf in form and enctype="multipart/form-data".
And I'm also using Laravel Intervention Image.
Please help.
You can not pass enctype and mimetype in ajax function. Please try this
$.ajax({
data: $('#productForm').serialize(),
url: "{{ route('admin.restaurants.store') }}",
type: "POST",
dataType: 'json',
enctype: 'multipart/form-data',
mimeType: 'multipart/form-data',
success: function (data) {
var html = '';
if(data.errors)
{
html = '<div class="alert alert-danger">';
for(var count = 0; count < data.errors.length; count++)
{
html += '<p>' + data.errors[count] + '</p>';
}
html += '</div>';
}
if(data.success)
{
html = '<div class="alert alert-success alert-dismissible fade show" role="alert"><strong><i class="fas fa-check-circle"></i> ' + data.success + '</strong><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button></div>';
$('#productForm').trigger("reset");
$('#ajaxModel').modal('hide');
table.draw();
}
$('#form_result').html(html);
}
});
The error message means that 'logo' is not in the request.
When you try to get it with
$logo = $request->file('logo');
it is probably null. When you then try to get the filename
$filename = $logo->getClientOriginalName();
it fails because $logo=null.
Try to use
dd($request->input());
to see what is actually in the request. Or you can log it with
Log::info("Request data = ", ['request' => $request->input()])
Related
I tried to solve this problem:
The GET method is not supported for this route. Supported methods:
POST.
But I can not find right way and error on Laravel 8.
Here is blade:
<a href="{{ route('operDel',$data->id) }}" class="btn btn-danger btn-sm"
data-tr="tr_{{$data->id}}"
data-id="{{$data->id}}"
data-toggle="confirmation"
data-btn-ok-label="Delete" data-btn-ok-icon="fa fa-remove"
data-btn-ok-class="btn btn-sm btn-danger"
data-btn-cancel-label="Cancel"
data-btn-cancel-icon="fa fa-chevron-circle-left"
data-btn-cancel-class="btn btn-sm btn-default"
data-title="Are you sure you want to delete ?"
data-placement="left" data-singleton="true">Delete</a>
And JavaScript in this blade
$(document).on('confirm', function (e) {
var ele = e.target;
e.preventDefault();
$.ajax({
url: ele.href,
type: 'DELETE',
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
success: function (data) {
if (data['success']) {
$("#" + data['tr']).slideUp("slow");
alert(data['success']);
} else if (data['error']) {
alert(data['error']);
} else {
alert('Whoops Something went wrong!!');
}
},
error: function (data) {
alert(data.responseText);
}
});
return false;
});
Here is Route
Route::delete('operDel/{id}', '\App\Http\Controllers\OperationController#destroy')->name('operDel')->middleware('auth');
And this is Controller
public function destroy($id)
{
Kvit::where('id', $$id)->delete();
return response()->json([
'success'=>"Product Deleted successfully.", 'tr'=>'tr_'.$id
]);
}
What I missed?
You need to pass method to the server.
$.ajax({
url: "operDel/"+id,
type: 'get',
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
data: {
"id": id,
"_method": 'DELETE',
"_token": token,
},
success: function(data){
//do stuff
},
error: function(data){
//do stuff
}
);
Solved by this code
Blade
<button class="btn btn-icon btn-flat-danger deleteRecord"
data-id="{{$data->id}}">
<i class="fas fa-trash"></i>
</button>
JavaScript
$(".deleteRecord").click(function(){
var id = $(this).data("id");
var token = $("meta[name='csrf-token']").attr("content");
if(confirm('Do you want to delete?')){
$.ajax(
{
url: "operDel/"+id,
type: 'post',
cache: false,
data: {
"id": id,
"method": 'post',
"_token": token,
},
dataType: "json",
success: function(response) {
if(response.status == "success"){
window.location.href='/operations';
}else if(response.status == "error"){
{toastr['error'](
'Please check datas..',
'You can not delete this!',
{
closeButton: true, tapToDismiss: true, progressBar: true,
}
);
}
}
},
});
}
});
In his life, he only encountered an ajax 2 times and here again our paths intertwined with him and he gave me 422 errors. I googled and realized that 422 error is a validation error, but in what specific place the error, I just can not understand.
This is my script
<script type="text/javascript">
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$( "#form" ).submit(function( e ) {
e.preventDefault();
var message = $('#message').val();
var img = $('#img').val();
var user_id = $('#user_id').val();
$.ajax({
type: "POST",
url: "{{route('profile.store', ['id' => Auth::user()->id])}}",
data: {message:message, img:img, user_id:user_id},
success: function (data) {
$("#textpost").html($(data).find("#textpost").html());
},
});
});
</script>
And my method
public function store(Request $request) {
$validator = $this->validate($request,[
'message' => 'required|max:1000',
'img' => 'mimes:jpeg,png,gif|max:3000',
]);
if($validator ) {
$post = new Profile();
$post->message = $request->message;
$post->user_id = Auth::user()->id;
if($request->file('img')) {
$path = Storage::putFile('public', $request->file('img'));
$url = Storage::url($path);
$post->img = $url;
}
$post->save();
}
return redirect()->back();
}
And my form
<div class="card-header">
<div class="input-group">
<form action="{{route('profile.store', ['id' => Auth::user()->id])}}" method="post" enctype="multipart/form-data" id="form">
#csrf
<textarea class="form-control" id="message" name="message" cols="100" rows="4" placeholder="О чем думаешь?"></textarea>
<input type="file" id="img" name="img" value="Прикрепить изображение" class="mt-2">
<div class="text-right">
{{-- <input type="submit" id="btn" value="Отправить" class="btn btn-outline-dark btn-sm mt-4">--}}
<button type="submit" id="btn" class="btn btn-outline-dark btn-sm mt-4">Отправить</button>
</div>
</form>
</div>
</div>
$validator = $this->validate($request,[
'message' => 'required|max:1000',
'img' => 'mimes:jpeg,png,gif|max:3000',
]);
This portion of your code throws a validation errors exception which returns 422.
If you wish to handle validation on your own, try this logic instead:
$validator = validator($request->all(), [
'message' => 'required|max:1000',
'img' => 'mimes:jpeg,png,gif|max:3000',
]);
if($validator->fails()) {
// return as appropriate
return response()->son($validatior->errors(), 422);
}
// rest of your code
There is a problem with your Ajax call, because you are uploading text and file at the same time you can pass it through FormData. You were also missing
contentType: false,
processData: false,
Here is the updated ajax call:
<script type="text/javascript">
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$( "#form" ).submit(function( e ) {
e.preventDefault();
var formData = new FormData(this); //set formData to selected instance
var message = $('#message').val();
var img = $('#img').val();
var user_id = $('#user_id').val();
$.ajax({
type: "POST",
url: "{{route('profile.store', ['id' => Auth::user()->id])}}",
data: formData, //pass to our Ajax data to send
success: function (data) {
$("#textpost").html($(data).find("#textpost").html());
},
contentType: false,
processData: false,
});
});
</script>
Setting processData makes it so your FormData is not converted to a string. Setting contentType to false is used for forms that pass files, when false, no header will be added to the request, which is exactly what we want when submitting multipart/form-data.
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">×</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>
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();
}
});
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();
}
});
});
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!
I have some code to request datatable via jquery ajax that returns:
403 forbidden
in a production environment, it's working properly in my local environment.
When I open url directly in browser it shows JSON array.
this is my ajax request:
$(function(){
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
var state = true;
var otable = $('#example').DataTable({
processing: true,
serverSide: true,
ajax: "{{ route('get.data') }}",
columns: [
{ data: 'CountryCode', name: 'CountryCode' },
{ data: 'CountryName', name: 'CountryName' },
{ data: 'FgActive', name: 'FgActive' },
{ data: 'action', name: 'action' }
]
});
my route
Route::get('get-data-my-datatables', [
'as'=>'get.data',
'uses'=>'CountryController#getData'
]);
Below is function in controller
public function getData()
{
$country = Country::all();
return datatables()
->of($country)
->addColumn('action', function ($country) {
return
'<button type="button" name="'.$country->CountryCode.'" class="btn btn-primary btn-sm fa fa-pencil" id="btnEdit" data-toggle="modal"></button>
<button type="button" name="'.$country->CountryCode.'" class="btn btn-danger btn-sm fa fa-trash" id="btnDel" data-toggle="modal"></button>'
;
})
->make(true);
}
Thank you for your attention.
Update
As requested, this is my network tab:
This is the view :
{{ Form::open([
'url' => '/contacts/create',
'files' => true
])}}
<div class="row">
<div class="collapse" id="collapseExample">
<div class="col-md-9">
{{ Form::label('group', 'group name')}}
{{ Form::text('group', null, [
'placeholder' => 'Enter group name here',
'class' => 'form-control'
])}}
</div>
<div class="col-md-3">
<button id="add-new-btn" class="btn btn-success"><i class="pe-7s-add-user"></i> Add</button>
</div>
</div>
</div>
{{ Form::close() }}
in my that view i have this script
$("#add-new-btn").click(function(e) {
e.preventDefault();
e.stopImmediatePropagation();
var newGroup = $('#group');
$.ajax({
url: "/groups/autocomplete",
method: "post",
data: {
name: $("#group").val(),
_token: $("input[name=_token]").val()
},
success: function(response) {
console.log(response);
},
error: function(xhr) {
var errors = xhr.responseJSON;
var error = errors.name[0];
if(error) {
newGroup.addClass('has-error');
var inputGroup = newGroup.closest('.col-md-9');
inputGroup.next('text-danger').remove();
inputGroup
.find('input')
.after('<p class="text-danger">' + error + '</p>');
}
}
});
});
and in store method of GroupsController i have a simple Validator that may returns these 2 values:
1.The name field is required
2.The name has already been taken
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|unique:groups'
]);
}
Now the problem is this :
Every time i try to submit the form, the browser returns this error "errors.name is undefined" in console.
where is the problem?
i had a mistake for accessing property of object, jsonData.errors
var data = xhr.responseText;
var jsonData = JSON.parse(data);
var msg = jsonData.errors.name[0];
console.log(msg);
or
var jsonData = xhr.responseJSON;
var msg = jsonData.errors.name[0];
console.log(msg);