Laravel pass id to my sql on button click from view

Viewed 156

I am trying to activate or deactivate the products for a form using $product->status

The active button shows if $product->status is 0 and The deactive button shows if $product->status is 1

I want to toggle the value of $product->status in the mysql database every time I click on the button

 <form action="{{route('invetory.create')}}" method="POST">
  @csrf
  <table class="table table-bordered" id="dynamicTable">
    <tr>
      <th>item</th>
      <th>tax</th>
      <th>Action</th>
    </tr>
    @forelse($products as $product)
    <input type="text" name="item" value="{{$product->id}}
    class="form-control" hidden />
    <td>
      <input type="text" name="item" value="{{$product->item}}
      class="form-control" />
    </td>
    <td>
      <input type="text" name="tax" value="{{$product->tax}}
      class="form-control" />
    </td>

   @if($product->status =='0')
    <td>
      <button type="button" data-id="{{ $product->id }}" class="btn btn-success remove-tr active_btn">active</button>
    </td>
  @else
    <td>
      <button type="button" data-id="{{ $product->id }}" class="btn btn-danger remove-tr deactive_btn">Deactive</button>
    </td>
  @endif
  </table>
</form>

here i have given the route i have used web.php

Route::post('/update', 'App\Http\Controllers\InventoryController@update')>name('invetory.update');

here i have added the controler i have used InventoryController.php


public function update(Request $REQUEST){
  dd($REQUEST->all());
  
       Inventory::update( $REQUEST->invetory as $key => $value);
 
    return redirect()->action([InventoryController::class, 'index']);
}

i am geting 500 error when i click button

7 Answers

You could add some data attributes to your buttons, and use them in js to send an ajax request

@if ($product->status =='0')
  <td>
    <button type="button" class="btn btn-success toggle-tr" data-product="{{ $product->id }}" data-status="{{ $product->status }}">active</button>
  </td>
@else
  <td>
    <button type="button" class="btn btn-danger toggle-tr" data-product="{{ $product->id }}" data-status="{{ $product->status }}">Deactive</button>
  </td>
@endif
document.querySelectorAll('.toggle-tr').forEach(el => el.addEventListener('click', e => {
  const product = e.target.dataset.product;
  const status = e.target.dataset.status == 0 ? 1 : 0;
  // send ajax or fetch request passing in product_id. If we're going with a RESTful approach,
  axiox.patch(`/products/${product}`, { status })
    .then(res => { ... })
    .catch(err => { ...});  
}));

You can achieve this using POST request which will refresh the page each time you toggle a product or you can use AJAX to do the change asynchronously. Using Javascript and AJAX would be the preferred way so you don't lose selected filters, pagination etc.

You don't need external packages to implement that, you can use JavaScript's fetch method. Also, instead of having 2 separate functions and routes, I would suggest having one route that would toggle the product's status, i.e. if it is active, make it inactive and vice versa. That method by definition should be a POST request, by I prefer doing GET requests for this in order to avoid CSRF protection and use middleware to protect the request.

Here is the complete code.

  1. Register a web route that toggles the state inside web.php
Route::get('projects/toggle', [ProjectController::class, 'toggle'])->name('projects.toggle');
  1. Implement the toggle method in ProjectController.php
public function toggle(Request $request) {
    $project = Project::find($request->project_id);

    $project->status = !$project->status;

    $project->save();

    return response()->json(['status' => (int) $project->status]);
}

Notice that I am returning a json response which includes the new project status. We will use this in the JavaScript code to dinamically update the column where the status is shown.

  1. Finally, in the blade file, when iterating through the projects, the button click calls a function that will do the AJAX request. Notice that I am also adding an id attribute to the columns that contains the status so I can access it dinamically in order to update it.
 @foreach($projects as $project)
    <tr>
        <td>{{$project->title}}</td>
        <td id="project-status-{{$project->id}}">{{$project->status}}</td>
        <td><button onClick="toggleStatus('{{$project->id}}')">Toggle</button></td>
    </tr>
@endforeach

In this same file, we add the following JavaScript code. It accepts project_id as parameter which is passed from the button click, makes the ajax request to backend which updates the status and then updates the appropriate DOM element to show the new status.

function toggleStatus(project_id) {
    fetch("{{ route('projects.toggle') }}?project_id=" + project_id)
        .then(response => response.json())
        .then(response => {
            document.querySelector("#project-status-" + project_id).innerHTML = response.status;
     })
}

As I mentioned, you can use multiple options in the JavaScript part. Instead of calling a function you can register an event listener to each button, but this approach with function call is a bit quicker. Also, I am passing the project_id as GET parameter, you can define the route to contain it as route parameter, but then you'll need to do some string replacements in order to do in dinamically in JavaScript. All in all, the proposed is a good solution that will serve your purpose.

p.s. For stuff like this, LiveWire is a perfect fit.

Using dd (e.g. in your controller) will throw a 500 error. It literally stands for "dump and die".

check you routes in form use{{route('invetory.create')}} and in routes you given inventory.update

public function Stauts(Request $request)
{
    $product= Product::findOrFail($request->id);
    $product->active == 1 ? $product->active = 0 : $product->active = 1 ;
    $product->update();
    return response()->json(['status' => true,'msg' =>  'Staut updated']);
}

in blade use ajax

 <script>
    $(document).on('click', '.status-product', function (e) {
        e.preventDefault();
        var product_id = $(this).data('id');
        var url ="{{ route('product.status') }}";
        $.ajax({
            type: "post",
            url: url,
             data: {
             '_token': "{{csrf_token()}}",
              'id': product_id 
             },
          success: function (data) {
               if (data.status == true) {
                  $('#deactive_ajax').show();}
              }
       })
    })
</script>

   Route::post('product/stauts/', [productController::class,'Stauts'])->name('product.Stauts');

First of all Using a form with tables is not ideal and some browsers already made changes to prevent that.

Secondly The best way is as DCodeMania said, the ajax request is the best way to solve this, I'll just modify his answer a bit and use Patch instead of PUT, so it'll look like this:

$(document).on('click', '.active_btn', function(e) {
    e.preventDefault();
    let id = $(this).data('id');
    $.ajax({
      url: '{{ route("products.update") }}',
      method: 'PATCH',
      data: {
        id: id,
        _token: '{{ csrf_token() }}'
      },
      success: function(response) {
        console.log(response);
      }
    });
  });

and you'll only be needing one button so no need to make the check for $product->status he added, just a single button for the toggle will make your code cleaner.

As for using PATCH instead of PUT, because you're only updating one single column and not the whole thing getting updated, and no need for the status parameter, you'll just reverse what's inside the database

$product = Product::find($request->id);
Product::where('id', $product->id)->update([
 'status' => $product->status ? 0 : 1,
]);

You'll also need one button with different text based on status like this

<td>
      <button type="button" data-id="{{ $product->id }}" class="btn btn-success remove-tr active_btn">{{ $product->status == 1 ? 'deactivate' : 'activate' }}</button>
</td>

You can use jQuery ajax here:

Pass product id in data-id attribute

@if($product->status =='0')
    <td>
      <button type="button" data-id="{{ $product->id }}" class="btn btn-success remove-tr active_btn">active</button>
    </td>
  @else
    <td>
      <button type="button" data-id="{{ $product->id }}" class="btn btn-danger remove-tr deactive_btn">Deactive</button>
    </td>
  @endif

then use ajax:

$(document).on('click', '.active_btn', function(e) {
      e.preventDefault();
      let id = $(this).data('id');
      $.ajax({
        url: '{{ route("products.update") }}',
        method: 'PUT',
        data: {
          id: id,
          status: 1,
          _token: '{{ csrf_token() }}'
        },
        success: function(response) {
          console.log(response);
        }
      });
    });

    $(document).on('click', '.deactive_btn', function(e) {
      e.preventDefault();
      let id = $(this).data('id');
      $.ajax({
        url: '{{ route("products.update") }}',
        method: 'PUT',
        data: {
          id: id,
          status: 0,
          _token: '{{ csrf_token() }}'
        },
        success: function(response) {
          console.log(response);
        }
      });
    });

Now you can handle the request in the controller.

Related