0
\$\begingroup\$

The following code works fine. When a user clicks on an element, an AJAX request is made, which will return the query result. The results are being displayed in a view. I read many articles where everyone is doing HTML code in controller when getting data with AJAX and show in view as same I did. Any good suggestions to avoid HTML code in controller make controller view and script separate.

Controller:

public function ajax(Request $request){ 

// $data = $request->all();

$data['products'] = Product::select('products.id', 'products.name', 'products.banner')->get();

foreach ($data['products'] as $product){
    echo $product->name;
}



// dd($data);
// if($request->ajax()){
//     return "AJAX";
// }
// return "HTTP";

// $data['products'] = Product::select('products.id', 'products.name', 'products.banner')->get();
// return $data;

}

Script

 <script type="text/javascript">

    // $.ajaxSetup({ headers: { 'csrftoken' : '{{ csrf_token() }}' } });
        $(document).ready(function(){

        // Load more data
        $('.load-more').click(function(){
            var row = Number($('#row').val());
            var allcount = Number($('#all').val());
            var rowperpage = 3;
            // row = row + rowperpage;
            row = row + 3;

            if(row <= allcount){
                $("#row").val(row);

                $.ajax({
                url: "{{ route('ajax') }}",
                type: 'post',
                datatype: 'JSON',
                headers: {
                    'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
                },
                data: {row:row},
                // error: function(XMLHttpRequest, textStatus, errorThrown) {
                //     alert('hi');
                // }

                success: function(response){

                // Setting little delay while displaying new content
                setTimeout(function() {
                    // appending posts after last post with class="post"
                    $(".post:last").after(response).show().fadeIn("slow");

                    var rowno = row + 3;

                    // checking row value is greater than allcount or not
                    if(rowno > allcount){

                        // Change the text and background
                        $('.load-more').text("show less");
                        $('.load-more').css("background","darkorchid");
                    }else{
                        $(".load-more").text("Load more");
                    }
                }, 2000);


                }

 });

            }else{
        $('.load-more').text("Loading...");

        // Setting little delay while removing contents
        setTimeout(function() {

            // When row is greater than allcount then remove all class='post' element after 3 element
            $('.post:nth-child(3)').nextAll('.post').remove().fadeIn("slow");

            // Reset the value of row
            $("#row").val(0);

            // Change the text and background
            $('.load-more').text("Load more");
            $('.load-more').css("background","#15a9ce");

        }, 2000);


    }

        });

        });
</script>

view

    @foreach($leedManufacturers as $leedsManufacturer)
                    {{-- @foreach($leedManufacturers as $leedsManufacturer)  --}}
                        <div class="post" id="post{{$leedsManufacturer['id']}}">
                            <label class=" my-checkbox gry2" id="manufacturer">{{str_limit($leedsManufacturer['name'], 300)}}
                                    <input type="checkbox">
                                    <span class="checkmark"></span>
                            </label>
                        </div>
                        {{-- for load more script --}}
                    {{-- <input type="hidden" id="row" value="0"> --}}

                    {{-- <input type="hidden" id="all" value="{{$total_manufacturers}}"> --}}
                    @endforeach
\$\endgroup\$
1

2 Answers 2

3
\$\begingroup\$

Your example:

public function ajax(Request $request){ 
$data['products'] = Product::select('products.id', 'products.name', 'products.banner')->get();

foreach ($data['products'] as $product){
    echo $product->name;
}

Attn: I omit commented string.

You do not need to get the query results into $data, especially if before you perform $data = $request->all();. Use another variable, in this case the $products may be okay.

If your 'Product' model is correct, then in the query you not need to use products.id - i.e. table name, need just field name.

Next, when you want pass the result to view, you need to do so as described in Doc:

return view('your_view_name', ['products' => $products]);

As described in official documentation - versions there are from 5.0 up to 5.8, choose any you need.

So, this part of your code becomes:

public function ajax(Request $request){ 
    $products = Product::select('id', 'name', 'banner')->get();
    return view('your_view_name', ['products' => $products]);
}

Remember 2 things:

  1. With that query you'll get all products from DB and there may be a huge number of results.
  2. the view has to be a blade type of template.

In your 'view' I see this line:

@foreach($leedManufacturers as $leedsManufacturer)

but I do not see a variable $leedManufacturers in the controller so you have no data for it.

To show $products result use the same but for $products, like:

<ol>
    @foreach($products as $product)
        <li>
            <div>id: {{$product->id}}, name: {{$product->name}}</div>
            <div>{{$product->banner}}</div>
        </li>
    @endforeach
</ol>

Also, when you need , you may use this (example)

@if (xxxxxxxxx === 1)
    I have one record!
@elseif (yyyyyyyyyy > 1)
    I have multiple records!
@else
    I don't have any records!
@endif

https://laravel.com/docs/5.3/blade#if-statements

And in view you can use even

@php
    pure php code here
@endphp
\$\endgroup\$
0
\$\begingroup\$

Responding to your prompt

Any good suggestions to avoid HTML code in controller make controller view and script separate.

I would suggest you consider using a template on the client-side, and having the AJAX request return data in JSON format. That way the Laravel controller doesn't have to worry about the HTML formatted-data.

Review Feedback

That name ajax seems very non-descriptive for the route and Laravel Controller method name. Obviously it is intended to be used with an AJAX call but what happens when you want to have another AJAX call to load separate data? Perhaps a better name would be something like loadProducts.

As @Vlad suggested in his answer that query will get all results because it doesn't appear to be filtered or limited to any number of results. Perhaps utilizing page number parameters or other filters would be useful.


I see $('.load-more') multiple times in the JavaScript code. How many elements are there with that class name load-more? If there is only one, then perhaps it would be more fitting to use an id attribute instead of a class name to select that element.

Also, it would be wise to store DOM element references instead of querying the DOM each time. For example,

var loadMoreContainer = $('.load-more');

could then be used to simplify code like:

if(rowno > allcount){
    // Change the text and background
    $('.load-more').text("show less");
    $('.load-more').css("background","darkorchid");
}else{
    $(".load-more").text("Load more");
}

To this:

if(rowno > allcount){
    // Change the text and background
    loadMoreContainer.text("show less") //note we are chaining here
        .css("background","darkorchid");
}else{
    loadMoreContainer.text("Load more");
}

Note how the call to .css was chained to the previous line, where the semi-colon was removed from the end of the line.


While that syntax of $(document).ready() still works with the latest jQuery version (i.e. 3.3.1 at the time of typing), it is deprecated and the recommended syntax is simply $(function() {})1.

1https://api.jquery.com/ready/

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.