If page is reloaded, if definitely will return to initial state. Ways to handle this can either be that you edit using ajax or have some indicator passed from controller to view that edit was recently performed, so don't hide the div element.
Edit in a hidden div, same view
I am trying to edit an entry that has been persisted to the DB, I put the edit form into a partial and included it inside a hidden div, when the edit button is selected the div will be shown and the user should be able to edit the entry.
hidden div
<div id="hidediv">
<div id="hidediv-container">
<div id="hidediv-content">
<div class="form-horizontal" style="width: 55%" text-align="right">
@include('partials.edit')
</div>
</div>
</div>
</div>
currently when the button is clicked the div shows for a few seconds then disappears, in the controller i am redirecting to the list of entries page and im sure that is why the form hides again.
public function edit($id)
{
$task = Task::findOrFail($id);
$tasks = Task::orderBy('created_at', 'asc')->get();
return view('todos.index', compact('task', 'tasks'));
}
I would like the user to be able to edit without ever leaving the main list page, and edit in the hidden div. submit and see the reflected changes on the list of entries page.
whats your code to activate the button to show the div. If we can see this perhaps we could help a bit more, as there could be the issue within the js or what ever your using to display the div, like onclick your not returning false, or preventDefault() etc, so what ever action(s) you have on this button is then being executed?
here is the button
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="submit" class="btn btn-default" onclick="hide('hidediv')" >
<i class="fa fa-plus"></i>Edit Task
</button>
</div>
</div>
function show(target) {
document.getElementById(target).style.display = 'block';
}
function hide(target) {
document.getElementById(target).style.display = 'none';
}
this is whats showing and hiding the div
@jbowman99 It would be good to get the code that your using for the on click event 'hide('hidediv')' ? Just edit your copy above and add it there , to save posting another one :-)
Whats happening there is that your using a <button type="submit"... so if there is a form on there it will simply submit that form? I would change to at least <button type="button"..., this way it will not cause your form to submit that form.
Would that edit button be onclick="show( to initially display the hidden form, as i would expect the the Edit Task button to open the hidden form, then either switch to submit edit or close form button?
Anyways, within this hidden form you would then have your input edit field and a submit button, then once the submit button is pressed it will update the DB via ajax call, then if successful, re-hide the form or display edit error?
Hope this helps a little for now we can then get to the next issue or question?
<span style="display: inline;">
<a type="button" class="btn btn-success" onclick="show('hidediv')" id="boot-buttons" href="{{ action('TodosController@edit', [$task->id]) }}">
<i class="fa fa-pencil-square-o"></i>Edit</a>
</button>
</span>
here is the button that opens the div
Hi , looks like that anchor tag is firing on clicking. try adding a return false; to it to prevent it going to the set action:
<a type="button" class="btn btn-success" onclick="show('hidediv'); return false;"
Or within your open call something like èvt.preventDefault(); etc if using something like jquery, then you will need to handle the updating within another function once the editing is done.
All I can see at the moment is that on opening the div it will also fire the call to the action you have just attached etc. You need to control the rest via a single form post event of through ajax. Will be going home soon so will try and post something as an example of what i mean :-)
ok now the div stays open until the edit/update button is pressed and the div hides again, nothing is updating in the database though? secondly not sure why, regardless of how many items are in the list, the edit div always shows the first entries information.
thanks for the help!!
Thats probably as mentioned the next stage, of how you have done the solution. In order for the controller to work etc you will need to either have a form post for each item, or use ajax to control each one.
Is there an edit div per list item? or are you using one edit div that will edit which ever is requested?
one edit div is included in the table, a for each loop runs over "tasks" and produces the table data per item.
@foreach ($tasks as $task)
<tr>
<td class="table-text"><div>{{ $task->body }}</div></td>
<!-- Task Delete Button -->
<td>
<form action="/todo/{{ $task->id }}" method="POST">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<span style="display: inline;">
<button id="boot-buttons" type="submit" class="btn btn-danger">
<i class="fa fa-trash"></i>Delete
</button>
</span>
</form>
</td>
<td>
<span style="display: inline;">
<a type="button" class="btn btn-success" onclick="show('hidediv')" id="boot-buttons" href="{{ action('TodosController@edit', [$task->id]) }}">
<i class="fa fa-pencil-square-o"></i>Edit</a>
</button>
</span>
</td>
</tr>
<div id="hidediv">
<div id="hidediv-container">
<div id="hidediv-content">
<div class="form-horizontal" style="width: 55%" text-align="right">
@include('partials.edit')
</div>
</div>
</div>
</div>
@endforeach
Hi @jbowman99 , are you able to supply the hidden div blade include (@include('partials.edit')) details as well. Also have you done a simple echo with in the loop to visibly see the data thats being display for each loop? Say for instance keep the hidden div open so you can see the data thats being populated for each looped item.
Also here a simple example of one method, as mentioned, using a form element for each as you have above for the delete.
http://codepen.io/simondavies/pen/YwOprM
PS also noticed that your hidden div is outside any table tr/td's. purhasp surrounding it in the outer tr will help as well.
<td>
<span style="display: inline;">
<a type="button" class="btn btn-success" onclick="show('hidediv')" id="boot-buttons" href="{{ action('TodosController@edit', [$task->id]) }}">
<i class="fa fa-pencil-square-o"></i>Edit</a>
</button>
</span>
</td>
</td>
<td id="hidediv" >
<div id="hidediv-container">
<div id="hidediv-content">
<div class="form-horizontal" style="width: 55%" text-align="right">
@include('partials.edit')
</div>
</div>
</div>
</td>
</tr>
notice the <td id="hidediv" >within the td and that.
your link is exactly what i was trying to do, ill have a closer look at it. for now here is the edit partial
<div class="form-group">
<label for="body" class="col-sm-3 control-label">Task:</label>
<div class="col-sm-6">
{!! Form::model($task, ['method' => 'PATCH', 'route' => ['todo.update', $task->id ]]) !!}
{!! Form::text('body', null, ['class' => 'form-control']) !!}
{!! Form::close() !!}
</div>
</div>
<!-- Add Task Button -->
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="submit" class="btn btn-default" onclick="hide('hidediv')" >
<i class="fa fa-plus"></i>Edit Task
</button>
</div>
</div>
delete button works like it should, can i run edit and update in the same fashion?
your help is much appreciated
Ah! thought so you are closing the form and then adding the 'submit' button after so there's no form to submit / or which content so try:
{!! Form::model($task, ['method' => 'PATCH', 'route' => ['todo.update', $task->id ]]) !!}
<div class="form-group">
<label for="body" class="col-sm-3 control-label">Task:</label>
<div class="col-sm-6">
{!! Form::text('body', null, ['class' => 'form-control']) !!}
</div>
</div>
<!-- Add Task Button -->
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="submit" class="btn btn-default" onclick="hide('hidediv')" ><i class="fa fa-plus"></i>Edit Task
</button>
</div>
</div>
{!! Form::close() !!}
So encapsulating the whole section within the form so the submit button will then submit that form. PS: you might need to add the access token snippet in there as well.
if I were to wrap a form action around the hidden div much like the delete function, what would i pass to it as the value="" or token?
if i am reading this correct then try the following:
<div class="col-sm-6">
{!! Form::text('body', $task->body, ['class' => 'form-control']) !!}
{{ csrf_field() }}
</div>
so adding the current $task->body value into the tasks body input. Also i have included the csrf token value as well. I hope this is what you mean?
So on clicking update it should post to the set route and update or what ever you do within your class etc.
on inspection to see what value the edit button, it is only getting id="11" yet the delete button is getting the proper values in the loop.
do i need to include the edit button within a form action also?
not sure what you mean about the edit button??
I did notice that your using model form binding for that form, and dont think that will work, so try with in the hidden div the full normal form details
<!-- Hidden form -->
<form action="/todo/{{ $task->id }}" method="POST">
{{ csrf_field() }}
<div class="form-group">
<label for="body" class="col-sm-3 control-label">Task:</label>
<div class="col-sm-6">
<input type="text" name="body" value="{!! $task->body !!}" class="form-control">
</div>
</div>
<!-- Add Task Button -->
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="submit" class="btn btn-default" onclick="hide('hidediv')" ><i class="fa fa-plus"></i>Edit Task
</button>
</div>
</div>
</form>
<!-- end of Hidden form -->
so in theory this should post your form with the body and access token details to the url /todo/{id}
Within the controller for this route/post put a simple dd($request->all()) etc so you can then see what the edit form submitted and if its correct?
currently the hidden div opens only with the first element in the list, and upon submission the element hides but nothing else is happening. the div just disappears, i tried to dd($request->all()) and i don't believe the button is firing a route, it is only closing the div with the script.
not sure if you saw my earlier post but originally the button is outside the form so its got nothing to post/submit. So i did the following:
<!-- Hidden form -->
<form action="/todo/{{ $task->id }}" method="POST">
{{ csrf_field() }}
<div class="form-group">
<label for="body" class="col-sm-3 control-label">Task:</label>
<div class="col-sm-6">
<input type="text" name="body" value="{!! $task->body !!}" class="form-control">
</div>
</div>
<!-- Add Task Button -->
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="submit" class="btn btn-default" ><i class="fa fa-plus"></i>Edit Task</button>
</div>
</div>
</form>
<!-- end of Hidden form -->
I have also removed the close onclick="hide('hidediv')" as if its going to post and reload the page there is no need to close it etc.
notice the Form Close and open section, its outside the submit btn.
Also did you correct what I was sayign about the divs being outside the table structure, and to put it within the 's
I think it is getting closer to being correct, on submit the page begins to refresh, and i am hit with an
route collection error MethodNotAllowed
and when the i select an item to edit, still will only show the first item in the list regardless of which item is selected
Look at your route make sure its got Route::Post instead of Route::get this is normally what that issue might mean?
That might be because the open close is calling the very first div all the time and not the one you are on? Did you move it to within the tags etc.
<div class="panel-body">
<table class="table table-striped task-table">
<thead>
<th>Task</th>
<th> </th>
</thead>
<tbody>
@foreach ($tasks as $task)
<tr>
<td class="table-text"><div>{{ $task->body }}</div></td>
<!-- Task Delete Button -->
<td>
<form action="/todo/{{ $task->id }}" method="POST">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<span style="display: inline;">
<button id="boot-buttons" type="submit" class="btn btn-danger">
<i class="fa fa-trash"></i>Delete
</button>
</span>
</form>
</td>
<td>
<span style="display: inline;">
<a type="button" class="btn btn-success" onclick="show('hidediv')" id="boot-buttons">
<i class="fa fa-pencil-square-o"></i>Edit</a>
</button>
</span>
</td>
<td id="hidediv">
<div id="hidediv-container">
<div id="hidediv-content">
<div class="form-horizontal" style="width: 55%" text-align="right">
@include('partials.edit')
</div>
</div>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
here is the blade
my route is using Route::resource('todo', 'TodosController');
Have you tried to change the edit forms Method, at the moment its set to POST:
<!-- Hidden form -->
<form action="/todo/{{ $task->id }}" method="POST">
{{ csrf_field() }}
Change that to something like:
<!-- Hidden form -->
<form action="{{route('todo.update', $task->id)}}" method="POST">
{{ csrf_field() }}
{{ method_field('PATCH') }}
Something like that?
Also noticed on the table layout you have an extra </button> by the edit a href link and some of the table is a bit messed up, eg 2 *
right i have created a quick laravel project and didi a simple todo app based on what we have been discussing. All seems to work for me. I can list all, my todo's, Delete and also edit them as well.
I have posted the code below to hopefully help. From everything I did to create it. Remember the following is simple working draft, no security, validation etc :-)
ROUTES:
Route::group(['middleware' => ['web']], function () {
Route::get('/', ['as'=>'todo','uses'=>'TodoController@index']);
Route::resource('todo', 'TodoController');
});
CONTROLLER
The todoController.php:
use App\Todo;
class todoController extends Controller
{
private $todos;
function __construct(Todo $todos){
$this->todos = $todos;
}
public function index(){
$todos = $this->todos->all();
//dd($todos);
return view('todo.index', compact('todos'));
}
public function destroy($todo_id){
$todo = $this->todos->findOrFail($todo_id);
$todo->delete();
return redirect()->route('todo');
}
public function update($todo_id, \Request $request){
$current_todo = $this->todos->findOrFail($todo_id);
$todo_body = $request::input('body');
$current_todo->body = $todo_body;
$current_todo->save();
return redirect()->route('todo');
}
PAGE/VIEW:
<!DOCTYPE html>
<html>
<head>
<title>Laravel</title>
<script src="//code.jquery.com/jquery-1.12.0.min.js"></script>
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Lato:100" rel="stylesheet" type="text/css">
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<style>
.list-wrapper {
margin: 20px auto;
padding: 20px;
width: 100%;
max-width: 500px;
}
.list-item {
margin: 10px 0;
padding: 8px 10px;
border-radius: 5px;
border: 1px #ccc solid;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
.title-wrapper {
display: table;
vertical-align: middle;
width: 100%;
}
.title-wrapper .title {
display: table-cell;
vertical-align: middle;
text-transform: uppercase;
width: 80%;
}
.title-wrapper .action {
display: table-cell;
vertical-align: middle;
text-transform: uppercase;
width: 10%;
}
.title-wrapper .delete {
display: table-cell;
vertical-align: middle;
text-transform: uppercase;
width: 10%;
}
.title-wrapper .action a:link,
.title-wrapper .action a:visited,
.title-wrapper .action a:active {
transition: background 400ms;
}
.edit-wrapper {
display: none;
}
.edit-wrapper.show {
display: inline-block;
}
.title-wrapper .action .fa.swop.fa-pencil {display : none}
.title-wrapper .action .fa.fa-times {display : none}
.title-wrapper .action .fa.swop.fa-times {display : inline}
</style>
</head>
<body>
<div class="container">
<div class="title">To Do's</div>
<div class="list-wrapper">
@foreach ($todos as $todo)
<!-- list element -->
<div class="list-item">
<div class="title-wrapper">
<div class="title">
{{ $todo->body}}
</div>
<div class="delete">
{!! Form::open(['before' => 'csrf', 'route' => ['todo.destroy', $todo->id], 'method'=>'post']) !!}
{{ csrf_field() }}
{{ method_field('DELETE') }}
<button type="submit" class="btn btn-primary"><i class="fa fa-trash"></i></button>
{!! Form::close() !!}
</div>
<div class="action">
<a href="#" class="btn btn-default" id="edit-btn"><i class="fa fa-pencil"></i><i class="fa fa-times"></i></a>
</div>
</div>
<!-- Hidden section -->
<div class="edit-wrapper">
{!! Form::open(['before' => 'csrf', 'route' => ['todo.update', $todo->id], 'method'=>'post']) !!}
{{ csrf_field() }}
{{ method_field('PATCH') }}
{!! Form::text('body', $todo->body, ['class'=>'form-control']) !!}
<button type="submit" class="btn btn-primary">Update</button>
{!! Form::close() !!}
</div>
<!-- end of hidden section -->
</div>
<!--end of list element -->
@endforeach
</div>
<!-- end of list-wrapper -->
</div>
<script>
$('.list-wrapper'). on('click','#edit-btn', function(evt){
evt.preventDefault();
var btn = $(this).children(),
listItem = $(this).parent().parent().parent().children('div');
btn.toggleClass('swop');
listItem.toggleClass('show');
})
</script>
</body>
</html>
MIGRATION/SCHEME:
public function up()
{
Schema::create('todos', function (Blueprint $table) {
$table->increments('id');
$table->text('body')->nullable();
$table->timestamps();
});
}
SEEDER:
public function run()
{
factory(App\Todo::class, 20)->create();
}
FACTORY
$factory->define(App\Todo::class, function (Faker\Generator $faker) {
return [
'body' => $faker->sentence,
];
});
Its crude but works for me don't think i have forgotten anything. Hoep this helps
seriously thanks for all of the assistance and samples and examples, you've gone way above and beyond!!! This forum has the best help.
Not a problem, matey. Its keeps my knowledge fresh as well. Hope it works out.
the only issue i'm having now is in the list the delete button selects the proper item and deletes it,
the edit function always grabs the same item, which happens to be the first in the list.
<div class="panel-body">
<table class="table table-striped task-table">
<thead>
<th>Task</th>
<th> </th>
</thead>
<tbody>
@foreach ($tasks as $task)
<tr>
<td class="table-text"><div>{{ $task->body }}</div></td>
<!-- Task Delete Button -->
<td>
<form action="/todo/{{ $task->id }}" method="POST">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<span style="display: inline;">
<button id="boot-buttons" type="submit" class="btn btn-danger">
<i class="fa fa-trash"></i>Delete
</button>
</span>
</form>
</td>
<td>
<span style="display: inline;">
<a type="button" class="btn btn-success" onclick="show('hidediv')" id="boot-buttons"><i class="fa fa-pencil-square-o"></i>Edit</a>
</span>
</td>
<td id="hidediv">
<div id="hidediv-container">
<div id="hidediv-content">
<div class="form-horizontal" style="width: 55%" text-align="right">
@include('partials.edit')
</div>
</div>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
i think this looks fairly accurate. I was comparing it to your examples
cna you try it with the whole @include('partials.edit') included, so just add the ontents into the above so not to use the include.
Also can you post that so i can add it and try with your html as well.
i have copied the exact above and then added in for now the included section from your previous posts, with the various alterations mentioned before. (Below) And then run it and it all worked, i could delete, edit and each visible edit field had its correct value etc
Try disabling the hidediv code so that you can see both with each list item, and you can then see he edit values as well.
<td id="hidediv">
{!! Form::open(['method' => 'PATCH', 'route' => ['todo.update', $todo->id ]]) !!}
<div id="hidediv-container">
<div id="hidediv-content">
<div class="form-horizontal" style="width: 55%" text-align="right">
<div class="form-group">
<label for="body" class="col-sm-3 control-label">Task:</label>
<div class="col-sm-6">
{!! Form::text('body', $todo->body, ['class' => 'form-control']) !!}
</div>
</div>
<!-- Add Task Button -->
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="submit" class="btn btn-default" onclick="hide('hidediv')" >
<i class="fa fa-plus"></i>Edit Task
</button>
</div>
</div>
</div>
</div>
</div>
{!! Form::close() !!}
</td>
If still nothing try posting each section as I have done so we can see further than the loop etc.
PS notice that i am using the Form::open( code and not like your original Form::model(
{!! Form::open(['method' => 'PATCH', 'route' => ['todo.update', $todo->id ]]) !!}
view blade
@extends('layouts.app')
@section('content')
<div class="container">
<div class="col-sm-offset-2 col-sm-8">
<div class="panel panel-default">
<div class="panel-heading">
New Task
</div>
<div class="panel-body">
<!-- Display Validation Errors -->
@include('partials.errors')
<!-- New Task Form -->
<form action="/todo" method="POST" class="form-horizontal">
{{ csrf_field() }}
<!-- Task Name -->
<div class="form-group">
<label for="body" class="col-sm-3 control-label">Task</label>
<div class="col-sm-6">
<input type="text" name="body" id="body" class="form-control" value="{{ old('body') }}">
</div>
</div>
<!-- Add Task Button -->
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="submit" class="btn btn-default">
<i class="fa fa-plus"></i>Add Task
</button>
</div>
</div>
</form>
</div>
</div>
<!-- Current Tasks -->
@if (count($tasks) > 0)
<div class="panel panel-default">
<div class="panel-heading">
Current Tasks
</div>
<div class="panel-body">
<table class="table table-striped task-table">
<thead>
<th>Task</th>
<th> </th>
</thead>
<tbody>
@foreach ($tasks as $task)
<tr>
<td class="table-text"><div>{{ $task->body }}</div></td>
<!-- Task Delete Button -->
<td>
<form action="/todo/{{ $task->id }}" method="POST">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<span style="display: inline;">
<button id="boot-buttons" type="submit" class="btn btn-danger">
<i class="fa fa-trash"></i>Delete
</button>
</span>
</form>
</td>
<td>
<span style="display: inline;">
<a type="button" class="btn btn-success" onclick="show('hidediv')" id="boot-buttons"><i class="fa fa-pencil-square-o"></i>Edit</a>
</span>
</td>
<td id="hidediv">
<div id="hidediv-container">
<div id="hidediv-content">
<div class="form-horizontal" style="width: 55%" text-align="right">
@include('partials.edit')
</div>
</div>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@endif
</div>
</div>
@endsection
edit partial
<!-- Hidden form -->
<form action="/todo/{{ $task->id }}" method="POST">
{{ csrf_field() }}
{{ method_field('PATCH') }}
<div class="form-group">
<label for="body" class="col-sm-3 control-label">Task:</label>
<div class="col-sm-6">
<input type="text" name="body" value="{!! $task->body !!}" class="form-control">
</div>
</div>
<!-- Add Task Button -->
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="submit" class="btn btn-default" ><i class="fa fa-plus"></i>Edit Task</button>
</div>
</div>
</form>
<!-- end of Hidden form -->
Controller
class TodosController extends Controller
{
public function index()
{
$tasks = Task::orderBy('created_at', 'asc')->get();
return view('todos.index', compact('tasks'));
}
public function store(Request $request)
{
$task = new Task;
$task->body = $request->body;
$task->save();
return redirect('/todo');
}
public function edit(Request $request, $id)
{
$task = Task::findOrFail($id);
$tasks = Task::orderBy('created_at', 'asc')->get();
return view('todos.index', compact('task', 'tasks'));
}
public function update(Request $request, $id)
{
$task = Task::findOrFail($id);
$task->body = $request->body;
$task->save();
return redirect('/todo');
}
public function destroy($id)
{
Task::findOrFail($id)->delete();
return redirect('/todo');
}
}
javascript
function show(target) {
event.preventDefault();
document.getElementById(target).style.display = 'block';
}
function hide(target) {
event.preventDefault();
document.getElementById(target).style.display = 'none';
}
i tried to take away the access to the partial and add the hidden div to the view itself, nothing changed, same issue here is all of my sections as you stated above.
Please or to participate in this conversation.