Laravel 9 Vue js 3 multipart form, console showing full html, not only the retrieved data - laravel

I'm using a multipart form to send texts and image to database,
The data have been successfully sent to the database, but why in the console it is showing the data infull html ? not only the data that has been retrieved ?
this is my code
<template>
<div class="gabungPage">
<div class="row">
<div class="backgroundGabung" id="hrefGabung">
<div class="tulisanGabung p-5">
<div class="cardGabung">
<p class="teksGabung">Tingkatkan bisnismu sekarang dengan bergabung menjadi mitra JAI'</p>
<form #submit.prevent="submitForm">
<div class="form-group">
<label for="nama">Nama</label>
<input
type="text"
id="nama"
v-model="formulirs.nama"
class="form-control"
/>
</div>
<div class="form-group">
<label for="alamat">Alamat</label>
<input
type="text"
id="alamat"
v-model="formulirs.alamat"
class="form-control"
/>
</div>
<div class="form-group">
<label for="email">Email</label>
<input
type="text"
id="email"
v-model="formulirs.email"
class="form-control"
/>
</div>
<div class="form-group">
<label for="nomor">nomor</label>
<input
type="text"
id="nomor"
v-model="formulirs.nomor"
class="form-control"
/>
</div>
<div class="form-group">
<label for="image">Image</label>
<input
type="file"
id="image"
ref="imageInput"
#change="uploadImage"
/>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
<div class="tesss">
<h1> <span class="tulisKiri1">Gabung jadi</span> <br> <span class="tulisKiri2">mitra jahit</span></h1>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
formulirs: {
nama: '',
alamat: '',
nomor: '',
email: '',
image: null,
},
};
},
methods: {
uploadImage() {
this.formulirs.image = this.$refs.imageInput.files[0];
},
async submitForm() {
const formData = new FormData();
formData.append('nama', this.formulirs.nama);
formData.append('alamat', this.formulirs.alamat);
formData.append('email', this.formulirs.email);
formData.append('nomor', this.formulirs.nomor);
formData.append('image', this.formulirs.image);
axios.post('/api/submit-form', formData).then(
response => {
console.log(response);
this.$toast.success(`Data berhasil dikirim`,{
position: "bottom",
});
}
). catch(error => {
console.log('error');
this.$toast.error(`Terjadi kegagalan`,{
position: "bottom",
});
})
},
},
};
</script>
the routes/web.php
Route::post('/api/submit-form', [FormulirsController::class, 'store']);
the controller
public function store(Request $request)
{
$validatedData = $request->validate([
'nama' => 'required',
'alamat' => 'required',
'nomor' => 'required',
'email' => 'required|email',
'image' => 'required|image',
]);
$formulir = new Formulirs;
$formulir->nama = $validatedData['nama'];
$formulir->alamat = $validatedData['alamat'];
$formulir->nomor = $validatedData['nomor'];
$formulir->email = $validatedData['email'];
$image = $request->file('image');
$imageName = time().$image->getClientOriginalName();
$image->storeAs('public/images', $imageName);
$formulir->image = $imageName;
$formulir->save();
return back()->with('success', 'Data berhasil dikirim');
}
I have tried to show the data only by changing to
console.log(response.data)
But it got worse, it only shows full html page in the console, what should I do so that it doesn't display the full html page?

You're making an axios request and returning back method. This is used for redirecting in a monolitic app. I recommend you return a JSON response in your controller. Something like this:
public function store(Request $request)
{
$validatedData = $request->validate([
'nama' => 'required',
'alamat' => 'required',
'nomor' => 'required',
'email' => 'required|email',
'image' => 'required|image',
]);
$formulir = new Formulirs;
$formulir->nama = $validatedData['nama'];
$formulir->alamat = $validatedData['alamat'];
$formulir->nomor = $validatedData['nomor'];
$formulir->email = $validatedData['email'];
$image = $request->file('image');
$imageName = time().$image->getClientOriginalName();
$image->storeAs('public/images', $imageName);
$formulir->image = $imageName;
$formulir->save();
return back()->with('success', 'Data berhasil dikirim'); // this is yours
return response()->json('Data berhasil dikirim'); // 200 status code is the second param by default. You can change for whatever you want.
}

Related

Image CRUD in laravel 9 with vue Js

I have a form that and I want it to have a CRUD function, I have made the function for the text, but I have no idea how to do CRUD with images,
Here is my code :
Model
protected $fillable= [
'nama',
'alamat',
'nomor',
'email',
];
Controller :
public function index()
{
return Form::all();
}
public function store(Request $request)
{
$data = $request->all();
$response = Form::create($data);
return response()->json([
'status' => 'success',
'data' => $response
], 200);
}
The Form :
<Form #submit="saveData()">
<div class="form-row form-section" id="formParent">
<div class="col-12 mb-3">
<Field name="nama" type="text" class="form-control1" v-model="form.nama" placeholder=" Nama Lengkap" :rules="isRequired" />
<br>
<ErrorMessage name="nama" />
<br>
<Field name="alamat" type="text" class="form-control2" v-model="form.alamat" placeholder=" Alamat" :rules="isRequired" />
<br>
<ErrorMessage name="alamat" />
<br>
<Field name="nomor" type="text" class="form-control3" v-model="form.nomor" placeholder=" Nomor Telfon" :rules="isRequired" />
<br>
<ErrorMessage name="nomor" />
<br>
<Field name="nomor" type="file" class="form-control3" v-model="form.nomor" placeholder=" Nomor Telfon" :rules="isRequired" />
<Field name="email" type="text" class="form-control4" v-model="form.email" placeholder=" Email" :rules="validateEmail" />
<br>
<ErrorMessage name="email" />
</div>
<button class="btnSubmit" type="submit">
Gabung Mitra
</button>
</div>
</Form>
Script :
<script>
import axios from 'axios';
import { Form, Field, ErrorMessage} from 'vee-validate';
export default {
components: {
Form,
Field,
ErrorMessage
},
data() {
return {
form: {
nama: '',
alamat: '',
nomor: '',
email: '',
},
};
},
methods: {
isRequired(value){
if (value && value.trim()){
return true;
}
return 'This is required';
},
validateEmail(value) {
// if the field is empty
if (!value) {
return 'This field is required';
}
// if the field is not a valid email
const regex = /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i;
if (!regex.test(value)) {
return 'This field must be a valid email';
}
// All is good
return true;
},
saveData(){
axios.post('/form/submit', this.form).then(
response => {
console.log(response);
this.$toast.success(`Data berhasil dikirim`,{
position: "bottom",
});
}
). catch(error => {
console.log('error');
this.$toast.error(`Terjadi kegagalan`,{
position: "bottom",
});
})
}
}
};
</script>
What should I do so that the user can upload an image to the form and save it to the database. I tried to change the field type to file, but I have no idea how the function works in the controller.
For storing images with Form you need to add few lines inside contoller for handling and storing image and also you need to add enctype inside form submit.
First you need to change :
<Form #submit="saveData()" enctype="multipart/form-data">
Now you need to change image input field :
<Field name="image" type="file" class="form-control3" v-model="form.image" :rules="isRequired" />
And inside the controller you need to change code for request :
public function store(Request $request)
{
$data = $request->all();
if ($request->hasFile('image')) {
$image = $request->file('image');
$path = $image->store('public/images');
$data['image'] = $path;
}
$response = Form::create($data);
return response()->json([
'status' => 'success',
'data' => $response
], 200);
}
And finally in your model :
protected $fillable = [
'nama',
'alamat',
'nomor',
'email',
'image',
];

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'player_id' cannot be null

I have this error when I try to add data. I have 2 tables on my database, the (players) table and the (stats) table which are connected with the "player_id" being the foreign key to the players table.
players table:enter image description here
stats table:enter image description here
StatsController:
public function index(){
$stats = Stats::all();
return view('stats', ['stats' => $stats]);
}
public function addstats(){
if($this->request->method() == 'POST'){
$alert = request() -> validate([
'points' => 'required|numeric',
'average_points' => 'required|numeric',
'games' => 'required|numeric',
'duration' => 'required|numeric'
]);
$stats = new Stats;
$stats->player_id = $this->request->id;
$stats->points = $this->request->get('points');
$stats->average_points = $this->request->get('average_points');
$stats->games = $this->request->get('games');
$stats->duration = $this->request->get('duration');
if($stats -> save()){
echo 'Success';
}
}
return view('addstats', ['player_id' => $this->request->player_id]);
}
public function editstats(Stats $stats){
if($this->request->method() == 'POST'){
$alert = request() -> validate([
'points' => 'required|numeric',
'average_points' => 'required|numeric',
'games' => 'required|numeric',
'duration' => 'required|numeric'
]);
$stats->player_id = $this->request->id;
$stats->fullname = $this->request->get('points');
$stats->age = $this->request->get('average_points');
$stats->height = $this->request->get('games');
$stats->weight = $this->request->get('duration');
if($stats -> save()){
return redirect('stats/');
}
}
return view('editstats', ['stats' => $stats]);
}
public function destroy(Stats $stats){
$stats->delete();
return redirect('stats/');
}
addstats blade php:
#section('content')
<div class="container">
<form action="{{route('addstats')}}" method="POST">
#csrf
<input type="hidden" name="id" value="{{$player_id}}">
<p>Overall Points:</p>
<input type="number" name="points" class="form-control" value="{{Request::old('points')}}" required>
<p style="color: red">#error('points') {{$message}} #enderror</p>
<p>Average points per game:</p>
<input type="number" name="average_points" class="form-control" value="{{Request::old('average_points')}}" required>
<p style="color: red">#error('average_points') {{$message}} #enderror</p>
<p>Games:</p>
<input type="number" name="games" class="form-control" value="{{Request::old('games')}}" required>
<p style="color: red">#error('games') {{$message}} #enderror</p>
<p>Duration:</p>
<input type="number" name="duration" class="form-control" value="{{Request::old('duration')}}" required>
<p style="color: red">#error('duration') {{$message}} #enderror</p>
<button class="btn btn-primary">Submit</button>
</form>
</div>
#endsection
my Routes:
Route::middleware('auth')->group(function(){
Route::get('/', [PlayersController::class, 'index']);
Route::post('/addplayer', [PlayersController::class, 'addplayer'])->name('addplayer');
Route::get('/addplayer', [PlayersController::class, 'addplayer'])->name('addplayer');
Route::get('/editplayer/{players}', [PlayersController::class, 'editplayer'])->name('editplayer');
Route::post('/editplayer/{players}', [PlayersController::class, 'editplayer'])->name('editplayer');
Route::get('/destroy/{players}', [PlayersController::class, 'destroy'])->name('destroy');
Route::get('/stats/{player_id?}', [StatsController::class, 'index']);
Route::post('/addstats', [StatsController::class, 'addstats'])->name('addstats');
Route::get('/addstats', [StatsController::class, 'addstats'])->name('addstats');
Route::get('/editstats/{stats?}', [StatsController::class, 'editstats'])->name('editstats');
Route::post('/editstats/{stats?}', [StatsController::class, 'editstats'])->name('editstats');
Route::get('/destroy/{stats?}', [StatsController::class, 'destroy'])->name('destroy');
});
class Stats extends Model
{
use HasFactory;
protected $table = 'stats';
protected $fillable = [
'player_id','points','average_points','games','duration'
];
}

Call to a member function store() on null on Laravel with Nuxt

I am currently having issues saving in Laravel from my Nuxt Application. I tried to perform the creating data from my postman and it works. I don't know what I missing here.
Controller
$book = Book::create([
'name' => $request->name,
'about' => $request->about,
// dd($request->file('image')),
'image' => $request->file('image')->store('images'),
]);
In my Nuxt template I have this
<form method="POST" enctype="multipart/form-data" #submit.prevent="save">
<div class="form-group">
<label for="name">Book Name</label>
<input
id="name"
v-model="editedItem.name"
type="text"
class="form-control"
placeholder="Book Name"
>
</div>
<div class="form-group">
<label for="image">Upload Book Cover</label>
<input
id="image"
name="image"
type="file"
accept="image/*"
class="form-control-file"
#change="onUpload"
>
</div>
<button type="submit" class="btn btn-primary">
Create Book
</button>
</form>
My nuxt methods
async save () {
try {
const formData = new FormData()
formData.append('name', this.editedItem.name)
formData.append('image', this.editedItem.imageurl.name)
await this.$axios.post('http://127.0.0.1:8000/api/createbookapi',
formData,
{
headers: {
enctype: 'multipart/form-data'
}
}
)
},
onUpload (e) {
this.editedItem.imageurl = e.target.files[0]
},
data: () => ({
editedItem: {
name: '',
imageurl: ''
}),
When I tried to save using postman, it works.
I don't know what I am missing here.
Call to a member function store() on null
becouse your file is null to avoid this add validation or make it optional
example of optional image
make sure database field is nullable
$book = Book::create([
'name' => $request->name,
'about' => $request->about,
'image' => $request->hasFile('image')
? $request->file('image')->store('images')
: null,
]);
for validation example
'image' => 'required|file', // it should check for file because file have class have store method

Call to a member function getClientOriginalName() on null when upload image use file system Laravel

I want to upload an image using Laravel storage file system in my admin data. However, there's an error when I attempt to upload an image.
Call to a member function getClientOriginalName() on null
Controller
public function store(Request $request)
{
$admin = $request->all();
$fileName = $request->file('foto')->getClientOriginalName();
$destinationPath = 'images/';
$proses = $request->file('foto')->move($destinationPath, $fileName);
if($request->hasFile('foto'))
{
$obj = array (
'foto' => $fileName,
'nama_admin' => $admin['nama_admin'],
'email' => $admin['email'],
'jabatan' => $admin['jabatan'],
'password' => $admin['password'],
'confirm_password' => $admin['confirm_password']
);
DB::table('admins')->insert($obj);
}
return redirect()->route('admin-index');
}
View
<div class="form-group">
<label for="" class="col-md-4">Upload Foto</label>
<div class="col-md-6">
<input type="file" name="foto">
</div>
</div>
Error
You can check wheather you are getting file or not by var_dump($request->file('foto')->getClientOriginalName());
And make sure your form has enctype="multipart/form-data" set
<form enctype="multipart/form-data" method="post" action="{{ url('/store')}}">
<div class="form-group">
<label for="" class="col-md-4">Upload Foto</label>
<div class="col-md-6">
<input type="file" name="foto">
</div>
</div>
</form>
Error because of client Side
<form enctype="multipart/form-data" method="post" action="{{ url('/store')}}">
<div class="form-group">
<label for="" class="col-md-4">Upload Foto</label>
<div class="col-md-6">
<input type="file" name="foto">
</div>
</div>
</form>
you ned to add enctype="multipart/form-data" inside the form
If You are using the form builder version
{!! Form::open(['url' => ['store'],'autocomplete' => 'off','files' => 'true','enctype'=>'multipart/form-data' ]) !!}
{!! Form::close() !!}
Then In your Controller You can check if the request has the file
I have Created the simple handy function to upload the file
Open Your Controller And Paste the code below
private function uploadFile($fileName = '', $destinationPath = '')
{
$fileOriginalName = $fileName->getClientOriginalName();
$timeStringFile = md5(time() . mt_rand(1, 10)) . $fileOriginalName;
$fileName->move($destinationPath, $timeStringFile);
return $timeStringFile;
}
And the store method
Eloquent way
public function store(Request $request)
{
$destinationPath = public_path().'images/';
$fotoFile='';
if ($request->hasFile('foto'))
{
$fotoFile= $this->uploadFile($request->foto,$destinationPath );
}
Admin::create(array_merge($request->all() , ['foto' => $fotoFile]));
return redirect()->route('admin-index')->with('success','Admin Created Successfully');
}
DB Facade Version
if You are using DB use use Illuminate\Support\Facades\DB; in top of your Controller
public function store(Request $request)
{
$admin = $request->all();
$destinationPath = public_path().'images/';
$fotoFile='';
if ($request->hasFile('foto'))
{
$fotoFile = $this->uploadFile($request->foto,$destinationPath );
}
$obj = array (
'foto' => $fotoFile,
'nama_admin' => $admin['nama_admin'],
'email' => $admin['email'],
'jabatan' => $admin['jabatan'],
'password' => $admin['password'],
'confirm_password' => $admin['confirm_password']
);
DB::table('admins')->insert($obj);
return redirect()->route('admin-index');
}
Hope it is clear

No error messages from 422 response on laravel form request from vue component

I'm trying to submit a form request using axios, have it validated, and return errors if the validation fails. The problem is, when I submit the form, no error messages are returned for me to show on the client side. Here's the HTTP request and vue component:
<div class="card">
<div class="card-header">
<h4>Information</h4>
</div>
<div class="card-body">
<p v-if='!isEditMode'><strong>Name:</strong> {{businessData.name}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-name">Name</label></strong>
<input class="form-control" name="business-name" v-model='businessData.name'>
</div>
<p v-if='!isEditMode'><strong>Description:</strong> {{businessData.description}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-description">Description</label></strong>
<textarea class="form-control normal" name="business-description"
placeholder="Enter your services, what you sell, and why your business is awesome"
v-model='businessData.description'></textarea>
</div>
</div>
</div>
<div class="card">
<h4 class="card-header">Address Information</h4>
<div class="card-body">
<p v-if="!isEditMode"><strong>Street Address: </strong> {{businessData.street}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-street">Street Address: </label></strong>
<input type="text" class="form-control" name="business-street" v-model='businessData.street' placeholder="1404 e. Local Food Ave">
</div>
<p v-if="!isEditMode"><strong>City: </strong> {{businessData.city}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-city">City: </label></strong>
<input class="form-control" type="text" name="business-city" v-model='businessData.city'>
</div>
<p v-if="!isEditMode"><strong>State: </strong> {{businessData.state}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-state">State: </label></strong>
<select class="form-control" name="business-state" id="state" v-model="businessData.state" >...</select>
</div>
<p v-if="!isEditMode"><strong>Zip: </strong> {{businessData.zip}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-zip">Zip: </label></strong>
<input class="form-control" type="text" maxlength="5" name="business-zip" v-model='businessData.zip'>
</div>
</div>
</div>
<div class="card">
<h4 class="card-header">Contact Information</h4>
<div class="card-body">
<p v-if="!isEditMode"><strong>Phone: </strong> {{businessData.phone}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-phone">Phone: </label></strong>
<input class="form-control" type="tel" name="business-phone" v-model='businessData.phone'>
</div>
<p v-if="!isEditMode"><strong>Email: </strong> {{businessData.email}}</p>
<div class="form-group" v-if='isEditMode'>
<strong><label for="business-Email">Email: </label></strong>
<input class="form-control" type="email" name="business-email" v-model='businessData.email'>
</div>
</div>
</div>
</div>
<script>
export default {
data () {
return {
isEditMode: false,
businessData: this.business,
userData: this.user,
errors: []
}
},
props: {
business: {},
user: {},
role: {}
},
//Todo - Institute client side validation that prevents submission of faulty data
methods: {
validateData(data) {
},
saveBusinessEdits () {
axios.put('/businesses/' + this.business.id , {updates: this.businessData})
.then(response => {
console.log(response.data)
// this.businessData = response.data;
this.isEditMode = false;
})
.catch (response => {
console.log(response.data)
this.isEditMode = false;
})
},
saveUserEdits () {
axios.put('/profile/' + this.user.id , {updates: this.userData})
.then(response => {
console.log(response.data)
this.userData = response.data;
this.isEditMode = false;
})
.catch (response => {
console.log(response)
this.isEditMode = false;
})
}
}
}
Route
Route::put('/businesses/{id}', 'BusinessesController#update');
BusinessController and update function
public function update(BusinessRequest $request, $id)
{
$business = Business::find($id)->update($request->updates);
$coordinates = GoogleMaps::geocodeAddress($business->street,$business->city,$business->state,$business->zip);
if ($coordinates['lat']) {
$business['latitude'] = $coordinates['lat'];
$business['longitude'] = $coordinates['lng'];
$business->save();
return response()->json($business,200);
} else {
return response()->json('invalid_address',406);
}
$business->save();
return response()->json($business,200);
}
and BusinessRequest class
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'business-name'=> 'required|string|max:255',
'business-description'=> 'required|string',
'business-phone' => 'nullable|phone|numeric',
'business-email' => 'nullable|email',
'business-street'=> 'required|string',
'business-city' => 'required|string',
'business-state' => 'required|string|max:2',
'business-zip' => 'required|min:5|max:5|numeric',
];
}
public function messages() {
return [
'business-zip.min:5' =>'your zip code must be a 5 characters long',
'business-email.email'=>'your email is invalid',
'business-phone.numeric'=>'your phone number is invalid',
];
}
}
I don't understand why, even if input valid data, it responds with a 422 response and absolutely no error messages. Since this is laravel 5.6, the 'web' middleware is automatic in all of the routes in the web.php file. So this isn't the problem. Could anyone help me normalize the validation behavior?
In Laravel a 422 status code means that the form validation has failed.
With axios, the objects that are passed to the then and catch methods are actually different. To see the response of the error you would actually need to have something like:
.catch (error => {
console.log(error.response)
this.isEditMode = false;
})
And then to get the errors (depending on your Laravel version) you would have something like:
console.log(error.response.data.errors)
Going forward it might be worth having a look at Spatie's form-backend-validation package
You can use Vue.js and axios to validate and display the errors. Have a route called /validate-data in a controller to validate the data.
app.js file:
import Vue from 'vue'
window.Vue = require('vue');
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
let token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}
class Errors {
constructor() {
this.errors = {};
}
get(field) {
if (this.errors[field]) {
return this.errors[field][0];
}
}
record(errors) {
this.errors = errors;
}
clear(field) {
delete this.errors[field];
}
has(field) {
return this.errors.hasOwnProperty(field);
}
any() {
return Object.keys(this.errors).length > 0;
}
}
new Vue({
el: '#app',
data:{
errors: new Errors(),
model: {
business-name: '',
business-description: '',
business-phone: ''
},
},
methods: {
onComplete: function(){
axios.post('/validate-data', this.$data.model)
// .then(this.onSuccess)
.catch(error => this.errors.record(error.response.data.errors));
},
}
});
Make a route called /validate-data with a method in the controller, do a standard validate
$this->validate(request(), [
'business-name'=> 'required|string|max:255',
'business-description'=> 'required|string',
'business-phone' => 'nullable|phone|numeric',
'business-email' => 'nullable|email',
'business-street'=> 'required|string',
'business-city' => 'required|string',
'business-state' => 'required|string|max:2',
'business-zip' => 'required|min:5|max:5|numeric'
]
);
Then create your inputs in your view file, using v-model that corresponds to the vue.js data model fields. Underneath it, add a span with an error class (basic red error styling, for example) that only shows up if the errors exist. For example:
<input type="text" name="business-name" v-model="model.business-name" class="input">
<span class="error-text" v-if="errors.has('business-name')" v-text="errors.get('business-name')"></span>
Don't forget to include the app.js file in footer of your view file. Remember to include the tag, and run npm run watch to compile the vue code. This will allow you to validate all errors underneath their input fields.
Forgot to add, have a buttton that has #onclick="onComplete" to run the validate method.

Resources