Azhar Nabil Azhar Nabil - 4 months ago 64
jQuery Question

laravel5.2 convert laravel code to ajax

I developed this shape with laravel code enter image description here

When I click on + the quantity of this product increase by 1.

When I click - the quantity of this product decrease by 1.

cart.blade.php (view):

<div class="cart_quantity_button">
<a class="cart_quantity_up" href='{{url("cart?product_id=$item->id&increment=1")}}'> + </a>
<input class="cart_quantity_input" type="text" name="quantity" value="{{$item->qty}}" autocomplete="off" size="2">
<a class="cart_quantity_down" href='{{url("cart?product_id=$item->id&decrease=1")}}'> - </a>
</div>


Cart function in controller:

public function cart()
{
if (Request::isMethod('POST')) {
$product_id = Request::get('product_id');

$product = Product::find($product_id);

Cart::add(array('id' => $product_id,'name' => $product->name, 'qty' => 1, 'price' => $product->price,'options'=>array('image'=>$product->image)));
}

$id = Request::get('product_id');

//increment the quantity
if ($id && (Request::get('increment')) == 1) {
$p = Request::get('increment');

$rowId = Cart::search(array('id' => $id));
// echo "row id".$rowId."and the p=".$p;
$item = Cart::get($rowId[0]);
// echo "row id".$rowId;

$add = $item->qty + 1;
Cart::update($rowId[0], $add);
}

//decrease the quantity
if ($id && (Request::get('decrease')) == 1) {
$rowId = Cart::search(array('id' => $id));

$item = Cart::get($rowId[0]);
$sub = $item->qty - 1;
echo "item" . $sub;
Cart::update($rowId[0], $sub);
}

if ($id && (Request::get('remove')) == 1) {
$rowId = Cart::search(array('id' => $id));

Cart::remove($rowId[0]);
}

$cart = Cart::content();

return view('cart', array('cart' => $cart,'title' => 'Welcome', 'description' => '', 'page' => 'home','subscribe'=>"",'brands' => $this->brands));

}

public function cart_remove()
{
Cart::destroy();
return Redirect::away('cart');
}


public function checkout()
{
$cart = Cart::content();
return view('checkout', array('cart' => $cart,'title' => 'Welcome', 'description' => '', 'page' => 'home','subscribe'=>"",'brands' => $this->brands));
}


I want to convert this with ajax code, I do simple code for this

<script>
function getMessage($id)
{
$.ajax({
type: 'POST',
url: 'getmsg',
dataType: 'json',
data: {
valu_id: $id
},
success: function(data) {
$("#msg").html(data.msg);
}
});
}
</script>

<?php
$item_id = 3;
echo Form::button('+',['onClick'=>'getMessage($item_id)']);
?>

<div id='msg'>
<input id="msg" type="text" name="quantity" autocomplete="off" size="2">
</div>


Controller function:

public function ajax()
{
$value= $_POST['valu_id']+1;
return response()->json(array('msg'=>$value), 200);
}


I don't know how to complete this code .I have many question about this code.
like


  • How to get the product id from cart.blade.php view and put it in
    getmessage()
    to use it in ajax function?

  • How to put
    getmessage()
    in
    <div class="cart_quantity_button">
    instead of button
    onclick
    to respect of the shape above?

  • How to return the quantity in the input field as the shape above?


Answer

Note: This answer doesn't simply giving you a working solution but an idea on how to handle ajax request/response.

Firstly, even tough event.preventDefault() would prevent default action which is following the URL, I'd rather store the URL to data- attribute.

<div class="cart_quantity_button">
    <a class="cart_quantity_up" href="javascript:void(0)" data-route="{{url('cart?product_id=$item->id&increment=1')}}"> + </a>
    <input class="cart_quantity_input" type="text" name="quantity" value="{{$item->qty}}" autocomplete="off" size="2">
    <a class="cart_quantity_down" href="javascript:void(0)" data-route="{{url('cart?product_id=$item->id&decrease=1')}}"> - </a>
</div>

How to get the product id from cart.blade.php view and put it in getmessage() to use it in ajax function?

It's always better to listen to an event, which is click in this case.

$('.cart_quantity_up').on('click', function(e) {
    //an ajax call here
});

Same code applies for the other one

$('.cart_quantity_down').on('click', function(e) {
    //an ajax call here
});

Now, two click events has been attached to each corresponding element. Then, it's time to wrap the ajax function up.

function updateQty(url){
    var $qty = $('.cart_quantity_input');
    $.ajax({
        type: 'POST',
        url: url,
        dataType: 'json', 
        data: {
            cart_qty: $qty.val()
        },
        success:function(data){
            $qty.val(data.qty);
        }
    });
}

The function above is simply

  1. takes a parameter which is URL for ajax to call to,
  2. does a post request with uri param key 'cart_qty'
  3. returns response which is a value of 'qty' from controller to cart_quantity_input input element

And then, put the ajax function to the first snippets (click event)

$('.cart_quantity_up').on('click', function(e) {
    e.preventDefault();
    //get the data-route
    var url = $(this).data('route');
    //call the ajax function
    updateQty(url);
});

$('.cart_quantity_down').on('click', function(e) {
    e.preventDefault();
    //get the data-route
    var url = $(this).data('route');
    //call the ajax function
    updateQty(url);
});

Actually to make things simpler, you can attach the event from multiple selectors at one go.

$('.cart_quantity_up, .cart_quantity_down').on('click', function(e) {
    e.preventDefault();
    //get the data-route for the 'up'
    var url = $(this).data('route');
    //call the ajax function
    updateQty(url);
});

Now, you get the idea on how to create ajax post and retrieve its response to attach it to the input element afterward.

At this point, I'm going to refactor your code. And oh, all of your questions should have been answered at this stage.


Your controller looks a bit messy as you handle both post and get requests for such simple situation. I would rather do just post. Instead of having bunch of conditions, I'll put the footprint inside the data- attribute (again). In the end, I wrap them inside a form, because CSRF token gives more security on your end.

<form name="cart_form">
    {{ csrf_field() }}
    <input type="hidden" class="item_id" value="{{ $item->id }}">
    <div class="cart_quantity_button">
        <button type="button" class="cart_quantity_up" data-route="{{url('cart')}}" data-increase="1"> + </button>
        <input class="cart_quantity_input" type="text" name="quantity" value="{{$item->qty}}" autocomplete="off" size="2">
        <button class="cart_quantity_down" data-route="{{url('cart')}}" data-increase="0"> - </button>
    </div>
</form>

You're free to design your own view as long as you're going to do a post request (as I'm doing on it). I'll explain a bit above the logic I'm going to make.

  • Hold the $item->id on hidden field
  • Going to make ajax request to url('cart') route and store it to data-route
  • Add data-increase to differentiate each request should increase or decrease

Now listen up on click event

$('.cart_quantity_up, .cart_quantity_down').on('click', function(e) {
    e.preventDefault();
    var $this = $(this),
        url = $this.data('route'),
        increase = $this.data('increase');

    updateQty(url, increase);
});

Below updateQty function is a bit different from the first one I made. It accepts the second parameter increase as (pseudo-)boolean value. Also notice I'm posting the token as request header rather than body.

function updateQty(url, increase){
    var $qty = $('.cart_quantity_input'),
        itemId = $('.item_id').val();
    $.ajax({
        type: 'POST',
        url: url,
        dataType: 'json',
        headers: {
            'X-CSRF-Token' : $('input[name="_token"]').val()
        },
        data: {
            'cart_qty': $qty.val(),
            'item_id': itemId,
            'increase': increase
        },
        success:function(data){
            $qty.val(data.qty);
        }
    });
}

Your controller


namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Cart;
use App\Http\Requests;

class YourController extends Controller
{
    public function cart(Request $request)
    {
        if ($request->ajax()) {
             $id = $request->item_id;
             $cart = Cart::search(['id' => $id]);
             //Note: This code may not working as what you expect
             //      but it should give you the idea that laravel
             //      actually has increment and decrement methods
             //      and else.
             if ($request->increase) {
                 $cart->increment('qty');
             } else {
                 $cart->decrement('qty');
             }
             $qty = $cart->first(['qty']);

             return response()->json(['qty' => $qty]);
        }
        //rest is your code
        //...
    }
}

In the above code, I'm trying to

  • treat ajax request separately from your code,
  • update qty column based on $_POST['increase']
    • If 1, do increment. If 0, decrements it
  • grab the value of qty column (though Im not sure it's going to work)
  • return the value keyed 'qty' as json
  • it will then update your input element based on $qty.val(data.qty)
Comments