Laravel delete button with HTML form - php

I'm using the HTML form, not Laravel Collective.
For now I've successfully created a CRUD for a users in my CMS, but one thing bothers me:
How can I set a Delete button in my list of users, instead of the specific edit page?
Also, it will be nice when a user clicks on the Delete button to show up confirmation popup for deleting the specific user.
So, here's my code:
The controller:
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
$user = User::findOrFail($id);
$user->delete();
return redirect('/admin/users');
}
The list of users page:
#extends('layouts.backend')
#section('content')
<h1>Users</h1>
<a class="btn btn-primary" href="/admin/users/create">Create new user</a>
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Email</th>
<th>Role</th>
<th>Status</th>
<th>Created</th>
<th>Updated</th>
<th>Operations</th>
</tr>
</thead>
<tbody>
#if($users)
#foreach($users as $user)
<tr>
<td>{{$user->id}}</td>
<td>{{$user->name}}</td>
<td>{{$user->email}}</td>
<td>{{$user->role ? $user->role->name : 'User has no role'}}</td>
<td>{{$user->status == 1 ? 'Active' : 'Not active'}}</td>
<td>{{$user->created_at->diffForHumans()}}</td>
<td>{{$user->updated_at->diffForHumans()}}</td>
<td>
Edit
<a class="btn btn-danger" href="">Delete</a> // HOW TO ACHIEVE THIS?
</td>
</tr>
#endforeach
#endif
</tbody>
</table>
#endsection
The specific edit user page:
#extends('layouts.backend')
#section('content')
<h1>Edit user</h1>
<form method="POST" action="/admin/users/{{$user->id}}">
{{ csrf_field() }}
{{ method_field('PATCH') }}
<div class="form-group">
<label>Name:</label>
<input type="text" name="name" class="form-control" value="{{$user->name}}">
</div>
<div class="form-group">
<label>Email:</label>
<input type="text" name="email" class="form-control" value="{{$user->email}}">
</div>
<div class="form-group">
<label>Role:</label>
<select name="role_id" class="form-control">
#if($user->role_id == 1)
<option value="1" selected>Administrator</option>
<option value="2">Editor</option>
#else
<option value="1">Administrator</option>
<option value="2" selected>Editor</option>
#endif
</select>
</div>
<div class="form-group">
<label>Status:</label>
<select name="status" class="form-control">
#if($user->status == 1)
<option value="1" selected>Active</option>
<option value="0">Not active</option>
#else
<option value="1">Active</option>
<option value="0" selected>Not active</option>
#endif
</select>
</div>
<div class="form-group">
<label>Password</label>
<input type="password" name="password" class="form-control" value="{{$user->password}}">
</div>
<div class="form-group">
<input type="submit" name="submit" value="Update user" class="btn btn-primary">
</div>
</form>
<form id="delete-form" method="POST" action="/admin/users/{{$user->id}}">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<div class="form-group">
<input type="submit" class="btn btn-danger" value="Delete user">
</div>
</form>
#include('inc.errors')
#endsection
The route:
Route::group(['middleware'=>'admin'], function(){
Route::resource('admin/users', 'AdminUsersController');
Route::get('/admin', function(){
return view('admin.index');
});
// Route::resource('admin/posts', 'AdminPostsController');
});

It's not obvious from the code you posted, but your DELETE route expects DELETE method. As it should!
But on your list you're trying to access it with GET method.
Really you should just reuse the code from the edit page, which fakes DELETE method already.
Something like this:
...
<td>
Edit
<form method="POST" action="/admin/users/{{$user->id}}">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<div class="form-group">
<input type="submit" class="btn btn-danger delete-user" value="Delete user">
</div>
</form>
</td>
...
...
// Mayank Pandeyz's solution for confirmation customized for this implementation
<script>
$('.delete-user').click(function(e){
e.preventDefault() // Don't post the form, unless confirmed
if (confirm('Are you sure?')) {
// Post the form
$(e.target).closest('form').submit() // Post the surrounding form
}
});
</script>

As you have stated it will be nice when a user clicks on the Delete button to show up confirmation popup for deleting the specific user. For this you have to use jquery and ajax. Change the following code:
<a class="btn btn-danger" href="">Delete</a>
to
<a class="btn btn-danger delete_user" href="javascript:void(0);" id="{{$user->id}}">Delete</a>
and put an event listener like:
$('.delete_user').click(function(){
if( confirm('Are you sure?') )
{
var id = $(this).attr('id');
// Make an ajax call to delete the record and pass the id to identify the record
}
});

You can update your code like:
<a class="btn btn-danger" href="/admin/users/{{$user->id}}/delete" >Delete</a>
OR you should delete user using route name like:
Delete

option with "laravel form helper" and jquery
<div class="actions">
<a href="#" class="list-icons-item delete-action">
<i class="icon-trash"></i>
</a>
{{ Form::open(['url' => route('admin.users.destroy', $user), 'method' => 'delete']) }}
{{ Form::close() }}
</div>
<script>
$(document).ready(function () {
$('.delete-action').click(function (e) {
if (confirm('Are you sure?')) {
$(this).siblings('form').submit();
}
return false;
});
});
</script>

Using route closures to delete
show.blade.php
<form>
<h1>Title: {{$tutorial->title}}</h1>
<p>Title Description: {{$tutorial->title_description}}</p>
<p>Video: {{$tutorial->video}}</p>
<form action="{{ route('delete-tutorial', [$tutorial->id])}}"
method="post">
#csrf
#method('DELETE')
<button class="btn btn-primary" onclick="return confirm('Are you sure?')"
type="submit" name="Delete">Delete</button>
</form>
for the route for deleting
Route::delete('tutorial/{id}',function($id){
$tutorial = Tutorial::findOrFail($id)->first();
$tutorial->delete();
return redirect('tutorial');
})->name('delete-tutorial');
Also don't forget to add this on your routes/web.php
use App\Models\Tutorial;

Related

Laravel Form displaying correct data but storing incorrect values in DB

I have come across a bug on my website and I am baffled as to how to fix it.. basically I have a view to create courses, I type a course title and secondly assign an instructor to that course and click save. But when i return to my index page.. the instructor i assigned is completely different. It appears there must be an issue with my select but I am not sure how to go about fixing it.. I am new to laravel so any help is greatly appreciated.
I have added a picture to try to further explain my issue, here i have selected an instructor -
And when i return to my index page, the newly created course 'test' has the admin user assigned... I am very confused -
create.blade.php
#extends('layouts.app')
#section('content')
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Create Course</div>
<div class="card-body">
<form method="POST" action="{{ route('admin.courses.store') }}" enctype="multipart/form-data">
#csrf
<div class="form-group">
<label class="required" for="name">Course Title</label>
<input class="form-control" type="text" name="title" id="id" value="{{ old('title', '') }}" required>
#if($errors->has('name'))
<div class="invalid-feedback">
{{ $errors->first('name') }}
</div>
#endif
</div>
<div class="form-group {{ $errors->has('instructors') ? 'has-error' : '' }}">
<label class="required" for="name">Instructors</label>
<select class="form-control select2" name="instructors[]" id="instructors" multiple>
#foreach($instructors as $id => $instructors)
<option value="{{ $id }}" {{ in_array($id, old('instructors', [])) ? 'selected' : '' }}>{{ $instructors }}</option>
#endforeach
</select>
</div>
<div class="form-group">
<button class="btn btn-danger" type="submit">
Save
</button>
</div>
</div>
</form>
</div>
</div>
#endsection
index.blade.php
#extends('layouts.app')
#section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-10">
<p>
#can('create_courses')
<button type="button" class="btn btn-success">Create Course</button>
#endcan('create_courses')
</p>
<div class="card">
<div class="card-header">Courses</div>
<div class="card-body">
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Course Title</th>
<th>Instructor</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
#foreach($course as $course)
<tr>
<th scope="row">{{ $course->id }}</th>
<td>{{ $course->title}}</td>
<td>{{ implode (', ', $course->instructors()->pluck('name')->toArray()) }}</td>
<td>
#can('edit_courses')
<a class="btn btn-xs btn-secondary" href="{{ route('admin.modules.index', $course->id) }}">
Modules
</a>
#endcan
</td>
<td>
#can('edit_courses')
<a class="btn btn-xs btn-primary" href="{{ route('admin.courses.edit', $course->id) }}">
Edit
</a>
#endcan
</td>
<td>
#can('delete_courses')
<form action="{{ route('admin.courses.destroy', $course->id) }}" method="POST" onsubmit="return confirm('Confirm delete?');" style="display: inline-block;">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<input type="submit" class="btn btn-xs btn-danger" value="Delete">
</form>
#endcan
</td>
</tr>
#endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- <div class="col-md-2 col-lg-2">
<div class="list-unstyled">
Courses
Modules
</div>
</div> -->
</div>
</div>
#endsection
CoursesController;
<?php
namespace App\Http\Controllers\Admin;
use Gate;
use App\User;
use App\Course;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Input;
class CoursesController extends Controller
{
public function __construct()
{
//calling auth middleware to check whether user is logged in, if no logged in user they will be redirected to login page
$this->middleware('auth');
}
public function index()
{
if(Gate::denies('manage_courses')){
return redirect(route('home'));
}
$courses = Course::all();
return view('admin.course.index')->with('course', $courses); //pass data down to view
}
public function create()
{
if(Gate::denies('create_courses')){
return redirect(route('home'));
}
$instructors = User::whereHas('role', function ($query) {
$query->where('role_id', 2); })->get()->pluck('name'); //defining instructor variable to call in create.blade.php. Followed by specifying that only users with role_id:2 can be viewed in the select form by looping through the pivot table to check each role_id
return view('admin.course.create', compact('instructors')); //passing instructor to view
}
public function store(Request $request)
{
$course = Course::create($request->all()); //request all the data fields to store in DB
$course->instructors()->sync($request->input('instructors', [])); //input method retrieves all of the input values as an array
if($course->save()){
$request->session()->flash('success', 'The course ' . $course->title . ' has been created successfully.');
}else{
$request->session()->flash('error', 'There was an error creating the course');
}
return redirect()->route ('admin.courses.index');
}
public function destroy(Course $course)
{
if(Gate::denies('delete_courses'))
{
return redirect (route('admin.course.index'));
}
$course->delete();
return redirect()->route('admin.courses.index');
}
public function edit(Course $course)
{
if(Gate::denies('edit_courses'))
{
return redirect (route('admin.courses.index'));
}
$instructors = User::whereHas('role', function ($query) {
$query->where('role_id', 2); })->get()->pluck('name');
//return view('admin.course.edit', compact('instructors'));
return view('admin.course.edit', compact('instructors'))->with([
'course' => $course
]);
}
public function update(Request $request, Course $course)
{
$course->update($request->all());
if ($course->save()){
$request->session()->flash('success', $course->title . ' has been updated successfully.');
}else{
$request->session()->flash('error', 'There was an error updating ' . $course->title);
}
return redirect()->route('admin.courses.index');
}
public function show(Course $course)
{
return view('admin.course.show', compact('course'));
}
}
Referring to latest comment -
you are updating data with key not id
try this
in controller
$instructors = User::whereHas('role', function ($query) {
$query->where('role_id', 2); })->select('id','name')->get();
in blade
you will need instructors->id to update right value
#foreach($instructors as $id => $instructor)
<option value="{{ $instructor->id }}" {{ in_array($id, old('instructors', [])) ? 'selected' : '' }}>{{ $instructor->name }}
</option>
#endforeach

How to submit form without refreshing?

I am trying to remove the refresh time after I click the end button to submit the form into the database.
I am not that experienced when it comes to jquery and I rely only to video tutorials and forums at this current time but I am on my learning curve. as you can see I already converted the start button into jquery to remove the refresh time when I click start button.
<tbody class="table table-bordered table-striped">
#foreach($user as $task)
<tr class="form-group">
{{-- <form action="{{ route('amber.timestone.home.start') }}" method="POST" class="align-center"> --}}
{{csrf_field()}}
<td class="d-flex">
<input type="hidden" name="id" id="hidden-id_{{$task->id}}" value="{{ $task->id }}">
<button type="button" id="str-btn" data-id="{{$task->id}}" class="btn btn-primary"
#if(!empty($task->start))
disabled
#elseif(!empty($task->duration))
readonly
#endif
>Start</button>
{{-- <span class="btn btn-primary" onclick="myAlert({{$task->id}})">Test</span> --}}
</td>
{{-- </form> --}}
<form action="{{ route('amber.timestone.home.end', $task->id) }}" method="POST">
{{csrf_field()}}
<td>
<input class="my-2" type="text" id="ref_{{$task->id}}" name="ref" value="{{ $task->ref }}"
#if(empty($task->start))
readonly
#elseif(!empty($task->duration))
readonly
#endif
>
{{-- <input class="my-2" type="hidden" name="ref" value="{{ $task->ref }}"> --}}
</td>
<td>
<textarea name="remarks" id="remarks_{{$task->id}}" cols="30" rows="4"
#if(empty($task->start))
readonly
#elseif(!empty($task->duration))
readonly
#endif
>{{ $task->remarks }}</textarea>
</td>
<td>
<select id="campaign_{{$task->id}}" class="custom-select custom-select-lg mb-3" name="campaign"
#if(empty($task->start))
disabled
#elseif(!empty($task->duration))
disabled
#endif
>
<option #if($task->campaign == 'cert') selected #endif value="cert">Cert Focus</option>
<option #if($task->campaign == 'omni') selected #endif value="omni">Omni</option>
<option #if($task->campaign == 'textblast') selected #endif value="textblast">TextBlast</option>
</select>
</td>
<td>
<select id="type_{{$task->id}}" class="custom-select custom-select-lg mb-3" name="type"
#if(empty($task->start))
disabled
#elseif(!empty($task->duration))
disabled
#endif
>
<option #if($task->type == 'cert') selected #endif value="cert">Cert</option>
<option #if($task->type == 'email') selected #endif value="email">Email Support</option>
<option #if($task->type == 'chat') selected #endif value="chat">Chat Support</option>
</select>
</td>
<td>
<p id="startTime"></p>
{{ $task->start }}
</td>
<td>
{{ $task->end }}
</td>
<td>
{{ $task->duration }}
</td>
<td class="d-flex">
<input type="hidden" name="id" value="{{ $task->id }}">
<button type="submit" id="end-btn_{{$task->id}}" class="btn btn-danger float-right ml-3"
#if(!empty($task->end))
disabled
#elseif(empty($task->start))
disabled
#endif
>End</button>
</form>
</td>
</tr>
#endforeach
</tbody>
</table>
</div>
</div>
#endsection
#section('reporter')
<script>
$(document).ready(function() {
$('#report').DataTable( {
"bLengthChange": false,
"lengthMenu": [ 3, 10 ],
searching: false
});
$('#str-btn').click(function(e){
var id = $(this).data('id');
$.ajax({
url: "{{ url('amber/timestone/start') }}"+'/'+id,
type: "GET",
success: function(data){
console.log(data)
$("#startTime").text(data.start)
$("#end-btn_"+id).removeAttr("disabled");
$("#ref_"+id).removeAttr("readonly");
$("#remarks_"+id).removeAttr("readonly");
$("#campaign_"+id).removeAttr("disabled");
$("#type_"+id).removeAttr("disabled");
$("#str-btn").Attr("disabled");
}
})
$(this).prop("disabled", true);
});
});
You can get your form and add listener on submit, then you can call to event.preventDefault() to avoid refreshing.
Would be something like this:
<form action="{{ route('amber.timestone.home.start') }}" method="POST" class=" form-data-table align-center">
...
Javascript part:
$('.form-data-table').on('submit', function(event){
event.preventDefault();
... remaining code
})

How to pass correct data from a dynamic button in Laravel 5.8

I have a dynamic buttons where it produced from my database
My code for that in blade file
<div class="input-group col-sm-12">
<!--start of the form-->
<form class="form-horizontal" method="POST" action="{{ route('call.store') }}">
{{ csrf_field() }}
<!--input type hidden department code below -->
#foreach($departments as $department)
<input type="hidden" id="dept_name" name="dept_name" value="{{ $department->dept_name }}">
<input type="hidden" id="called" name="called" value="NO">
<!--buttons -->
<button type="submit" class="btn btn-success btn-fill pull-right" id="form-button-add">
{{ $department->dept_name }}
</button>
#endforeach
</form>
<!--end-->
</div>
Whenever I click either one, they'all add a data in my call database based on the values per button. My problem is when I click the cashier button, the values that would add would be the assessments.
My code in CallController
public function store(Request $request)
{
$dept_id = Department::select('id')
->where('dept_name', $request->input('dept_name'))
->first();
$let = Department::select('letter')
->where('dept_name', $request->input('dept_name'))
->first();
$number = Department::select('start')
->where('id', $dept_id->id)
->first();
$call = Call::create([
'dept_id' => $dept_id->id,
'letter' => $let->letter,
'number' => $number->start,
'called' => $request->input('called')
]);
Department::where('id', $dept_id->id)
->increment('start');
return redirect()->route('call.index')->with('success' , 'NEW CALL');
}
I also dd each query and found out that the values would get are the values from assessment or the last value from the foreach loop in my blade file. How could I get the value of cashier when I click the cashier button instead of assessment.
I would show my database so that you understand my question
Department Table: id, dept_name, letter, start(int, it'll increment after producing a call)
Counter: id, counter_num, dept_id
Call Table: id, dept_id, letter, number, counter_id, called
When you click either button, they will submit their parent form. Because both are under the same form, the data from the first button will be submitted. You will have to make a separate form for each button in order to have them submit their own data.
<div class="input-group col-sm-12">
#foreach($departments as $department)
<form class="form-horizontal" method="POST" action="{{ route('call.store') }}">
{{ csrf_field() }}
<input type="hidden" id="dept_name" name="dept_name" value="{{ $department->dept_name }}">
<input type="hidden" id="called" name="called" value="NO">
<button type="submit" class="btn btn-success btn-fill pull-right" id="form-button-add">
{{ $department->dept_name }}
</button>
</form>
#endforeach
</div>
You're creating multiple submit buttons in the same form.
Add the tag inside the loop so you have a unique form per case.
When there's multiple submit buttons inside the same form, the loop will finish and only the last results will be mapped to the buttons, thus is will submit the last information in your loop.
#foreach($departments as $department)
<form class="form-horizontal" method="POST" action="{{ route('call.store') }}">
{{ csrf_field() }}
<input type="hidden" id="dept_name" name="dept_name" value="{{ $department->dept_name }}">
<input type="hidden" id="called" name="called" value="NO">
<!--buttons -->
<button type="submit" class="btn btn-success btn-fill pull-right" id="form-button-add">
{{ $department->dept_name }}
</button>
</form>
#endforeach

Laravel - Form Action to Controller Function

I'm trying to create a situation where a user can load a page, select a timesheet number, and then have the system delete all records associated with that timesheet number. This function loads the form page:
public function deletetimesheetLoad()
{
$timesheets = collect(DB::select("SELECT dbo.TIME.Source AS Source
FROM dbo.TIME
GROUP BY dbo.TIME.Source
ORDER BY dbo.TIME.Source ASC"));
return view('utilities/deletetimesheet',['timesheets' => $timesheets]);
}
This is the actual blade template:
<form method="post"
action="{{url('/time/deletetimesheet/process')}}"
enctype="multipart/form-data"
<div class="form-group">
<label class="col-md-12 control-label" for="TIMESHEETNUMBER">Timesheet Number</label>
<div class="col-md-12">
<select required id="TIMESHEETNUMBER" name="TIMESHEETNUMBER" class="form-control select2_field">
<option value=""></option>
#foreach ($timesheets as $row)
<option value="{{ $row->Source }}">{{ $row->Source }}</option>
#endforeach
</select>
</div>
</div>
<div id="saveActions" class="form-group">
<input type="hidden" name="save_action" value="Submit">
<div class="btn-group">
<button type="submit" class="btn btn-success">
<span class="fa fa-save"></span>
<span data-value="Submit">Submit</span>
</button>
</div>
<span class="fa fa-ban"></span> Cancel
</div>
This is the function that the form action is pointing to:
public function deletetimesheetProcess(TimesheetRequest $request)
{
DB::table('TIME')->where('Source', $request->get('TIMESHEETNUMBER'))->delete();
\Alert::success(trans('yay'))->flash();
return view('details/customershow',[]);
}
Here are the defined routes for the two functions:
Route::get('/time/deletetimesheet', 'Admin\TimeCrudController#deletetimesheetLoad');
Route::post('/time/deletetimesheet/process', 'Admin\TimeCrudController#deletetimesheetProcess');
Currently the blade template loads correctly, and does not throw an error on submit - just reloads the current page. What am I doing wrong?

use DELETE method in route with Laravel 5.4

I'm working on a Laravel (v 5.4) project and i did the CRUD to manage categories. Currently, i can create a new category and i would be able to delete.
I created the view (with blade) to delete the categories :
<table class="table">
<thead>
<th>Name</th>
<th>Action</th>
</thead>
<tbody>
#foreach ($categories as $category)
<tr>
<td>$category->name</td>
<td>
<a href="{{ url('/categories', ['id' => $category->id]) }}">
<button class="btn btn-default">
Delete
</button>
</a>
</td>
</tr>
#endforeach
</tbody>
</table>
And in the routing file web.php, i wrote :
Route::delete('/categories/{id}', CategoryController#destroy);
I have a controller CategoryController with a method destroy() who delete category and redirect to list of categories. But when i click on the button to delete, i get an error that explain this route is not define. If i replace Route::delete with Route::get it works. I think the url is called with GET but i would keep that for an other action.
I tried to replace the link with a form and "DELETE" as the value of "method" attribute but it didn't work.
How can i call url with DELETE method to catch it with Route::delete ?
Thanks in advance.
If you click on an url it will always be a GET method.
Since you wish to define it as DELETE, you should remake it into a post form and add
<input type="hidden" name="_method" value="delete" />
in it. Like replace:
<a href="{{ url('/categories', ['id' => $category->id]) }}">
<button class="btn btn-default">Delete</button>
</a>
with:
<form action="{{ url('/categories', ['id' => $category->id]) }}" method="post">
<input class="btn btn-default" type="submit" value="Delete" />
<input type="hidden" name="_method" value="delete" />
<input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>
Same goes for PUT request.
Since Laravel 5.1 method_field:
<form action="{{ url('/categories', ['id' => $category->id]) }}" method="post">
<input class="btn btn-default" type="submit" value="Delete" />
{!! method_field('delete') !!}
{!! csrf_field() !!}
</form>
Since Laravel 5.6 just with # tag:
<form action="{{ url('/categories', ['id' => $category->id]) }}" method="post">
<input class="btn btn-default" type="submit" value="Delete" />
#method('delete')
#csrf
</form>
For laravel 5.7 please look my example:
<form action="{{route('statuses.destroy',[$order_status->id_order_status])}}" method="POST">
#method('DELETE')
#csrf
<button type="submit">Delete</button>
</form>
Any method other than GET and POST requires you to specify the method type using a hidden form input. That's how laravel detects them. In your case you need to send the delete action using a form. Do this.
<table class="table">
<thead>
<th>Name</th>
<th>Action</th>
</thead>
<tbody>
#foreach ($categories as $category)
<tr>
<td>$category->name</td>
<td>
<form action="/categories/{{ $category->id }}" method="post">
{{ method_field('delete') }}
<button class="btn btn-default" type="submit">Delete</button>
</form>
</td>
</tr>
#endforeach
</tbody>
</table>

Categories