Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

adamjhn's avatar

Why are not appearing all conferences that belong to the clicked category?

I have a list that shows some categories:

<ul class="Categories__Menu">
    @foreach($categories->take(6) as $category)
        <li class="active">
            <a href="#" name="category" id="{{$category->id}}" href="#">{{$category->name}}</a>
        </li>
    @endforeach

    <li><a  data-toggle="modal" data-target=".bd-example-modal-lg" href="">More <i class="fa fa-caret-down" aria-hidden="true"></i></a></li>
</ul>

When a user clicks in a category is done an ajax reqquest to get the conferences that belong to that clicked category. The issue is that for example if a category has more than 1 conference associated when the user clicks in that category it appears in the network tab two equal results:

[{id: 7, name: "Conference test", description: "", start_date: "2018-03-08 06:30:00",…}]
0
:
{id: 7, name: "Conference test", description: "", start_date: "2018-03-08 06:30:00",…}

So in the #conferences div it only appear one conference instead of 2. Do you know where is the issue?

Route:

Route::get('conferences/where/category/{id}','ConferenceController@WhereHasCategory')->name('category.conferences');

ConferenceController method:

public function WhereHasCategory(Request $request)
    {
        $conferences = Conference::whereHas('categories', function ($categories) use (&$request) {
            $categories->where('category_conference.id',$request->id);
        })->get();

        return response()->json($conferences);
    }

Ajax:

$("a[name='category']").on('click', function(){

    var category_id = $(this).attr("id");

    $('.Categories__Menu li').removeClass('ative');
    $(this).parent('li').addClass('ative');

    $.ajax({

        url: '{{ route('category.conferences',null) }}/' + category_id,
        type: 'GET',
        success:function(result){
            $('#conferences').empty();
            var newConferences='';
            var placeholder = "{{route('conferences.show', ['id' => '1', 'slug' => 'demo-slug'])}}";
            $.each(result, function(index, conference) {
                var url = placeholder.replace(1, conference.id).replace('demo-slug', conference.slug);

                newConferences += '<div class="col-12 col-sm-6 col-lg-4 col-xl-3 mb-4">\n' +
'                        <div class="card box-shaddow">\n' +
'                            <img class="card-img-top" src='+ conference.image +' alt="Card image cap">\n' +
'                            <div class="card-body">\n' +
'                                <p class="font-size-sm"><i class="fa fa-calendar" aria-hidden="true"></i>  '+conference.start_date+'</p>\n' +
'                                <h5 class="card-title h6 font-weight-bold text-heading-blue">'+conference.name+'</h5>\n' +
'                                <p class="card-text font-size-sm"><i class="fa fa-map-marker" aria-hidden="true"></i> '+conference.place+', '+conference.city+'</p>\n' +
'                            </div>\n' +
'                           <div class="card-footer d-flex justify-content-between align-items-center">\n' +
'                                 <a href="' + url + '" class="btn btn-primary text-white">More</a>' +
                    ' <span class="font-weight-bold font-size-sm text-heading-blue"> </span>\n'+
'                           </div>\n' +
'                    </div></div>';
            });

            $('#conferences').html(newConferenes);

        },
        error: function(error) {
            console.log(error.status)
        }

    });

});

             ```
0 likes
22 replies
jlrdw's avatar

Have you done a dd to see or verify results.

And this

@foreach($categories->take(6) as $category)

the take(6) actually works here, I never used like that before.

1 like
adamjhn's avatar

Thanks, the "dd($conferences);" in WhereHasCategory() shows:


Collection {#264
  #items: array:1 [
    0 => Conference {#273
      #fillable: array:18 [
        0 => "name"
        ...
      ]
      #dates: array:2 [
        0 => "start_date"
        1 => "end_date"
      ]
      #connection: "mysql"
      #table: null
      #primaryKey: "id"
      #keyType: "int"
      +incrementing: true
      #with: []
      #withCount: []
      #perPage: 15
      +exists: true
      +wasRecentlyCreated: false
      #attributes: array:23 [
        "id" => 7
        "name" => "Confernece test"
        ....
      ]
      #original: array:23 [
        "id" => 7
        "name" => "Conference test"
        ...
      ]
      #changes: []
      #casts: []
      #dateFormat: null
      #dispatchesEvents: []
      #observables: []
      #relations: []
      #touches: []
      +timestamps: true
      #hidden: []
      #visible: []
      #guarded: array:1 [
        0 => "*"
      ]
    }
  ]
}

jlrdw's avatar

One looks to be correct, maybe network tab you are seeing two different views of same thing. Is the data correct in the application. Turn your results into an array prior to sending to ajax.

1 like
Cronix's avatar

from your dd() above, you are actually only getting one result.

The attributes section is not the same as the original section. If you were to change a property on a model, the original would show the original values, and the attributes section would show the new updated value. If nothing has changed (no updating), then they are the same.

When you do {{ $something->name }} it's getting the value from the attributes part.

[{id: 7, name: "Conference test", description: "", start_date: "2018-03-08 06:30:00",…}]
0
:
{id: 7, name: "Conference test", description: "", start_date: "2018-03-08 06:30:00",…}

Notice they are the same record, not 2 different records.

1 like
Cronix's avatar

I'd also urge you to start learning to separate your javascript into their own js files and not include them as part of the view. You will lose some of laravels helpers (like route()) and stuff (easy to work around), but it's the correct thing to do. Your pages will load faster as well since your browser will cache the js file and not download it on every single request like it would contained in a view. Views should really contain only html.

1 like
adamjhn's avatar

Thanks, but I didnt understand what it should be the issue. The attributes are different because I just put some attributes and then "..." to reduce the size of the question and comment. They are both the same conference but do you know why? Why is returning two equal conferences instead of 2 different conferences of the clicked category?

Cronix's avatar

As I said above

#attributes: array:23 [
        "id" => 7
        "name" => "Confernece test"
        ....
      ]
      #original: array:23 [
        "id" => 7
        "name" => "Conference test"
        ...
      ]

is the same record, not 2 different records. I explained why they are the same in my first reply. If you haven't altered the record (which you're not, you're just retrieving and displaying them), then attributes and original will be identical. When you {{ $record->some_attribute }} it's retrieving the value from the attributes. Just ignore the original section and pretend it doesn't exist. Just pay attention to the attributes section.

1 like
jlrdw's avatar

Huh? I couldn't help it, sorry.

adamjhn's avatar

Thanks, but do you know why I have a similar scenario but is to get the conferences of a clicked city. I also have a list with some cities and when the user clicks in a category is done an ajax request to get that categories:

public function getConferencesOfCity($slug)
    {

        $conferences = Conference::whereCity($slug)->get();

        return response()->json($conferences);
    }

And it works fine. If the user click in the "Newcastle" city and if there are 2 conferences that column city is "Newcastle" it works fine. It appears the two conferences correctly.

Ajax:

$("a[name='city']").on('click', function(){


                var city = $(this).attr("id");


                $.ajax({

                    url: '{{ route('city.conferences',null) }}/' + city,
                    type: 'GET',
                    success:function(result){
                        console.log(result)

                        alert(result);
                        $('#conferences').empty();
                        var newConferences='';
                        var placeholder = "{{route('conferences.show', ['id' => '1', 'slug' => 'demo-slug'])}}";
                        $.each(result, function(index, conference) {
                            var url = placeholder.replace(1, conference.id).replace('demo-slug', conference.slug);

                            newEvens += '<div class="col-12 col-sm-6 col-lg-4 col-xl-3 mb-4">\n' +
                                '                        <div class="card box-shaddow">\n' +
                                '                            <img class="card-img-top" src='+ conference.image +' alt="Card image cap">\n' +
                                '                            <div class="card-body">\n' +
                                '                                <p class="font-size-sm"><i class="fa fa-calendar" aria-hidden="true"></i>  '+conference.start_date+'</p>\n' +
                                '                                <h5 class="card-title h6 font-weight-bold text-heading-blue">'+conference.name+'</h5>\n' +
                                '                                <p class="card-text font-size-sm"><i class="fa fa-map-marker" aria-hidden="true"></i> '+conference.place+', '+conference.city+'</p>\n' +
                                '                            </div>\n' +
                                '                           <div class="card-footer d-flex justify-content-between align-items-center">\n' +
                                '                                 <a href="' + url + '" class="btn btn-primary text-white">More</a>' +
                                ' <span class="font-weight-bold font-size-sm"></span>\n'
                            '                           </div>\n' +
                            '                    </div>';
                        });

                        $('#conferences').html(newConferences);

                    },
                    error: function(error) {

                        console.log(error.status)
                    }

                });

            });

Route:

Route::get('conferences/where/city/{slug}','ConferenceController@getConferencesOfCity')->name('city.conferences');

In the network tab appears:

[{id: 10, name: "conference test", description: "", start_date: "2018-03-08 06:30:00",…},…]
0
:
{id: 10, name: "conference test", description: "", start_date: "2018-03-08 06:30:00",…}
1
:
{id: 11, name: "conference test 1", description: "", start_date: "2018-05-08 06:30:00",…}

Cronix's avatar

I don't have your data, so hard to say. It's possible that when you are looking by the category there was only actually 1 result for that category, but when you're querying by that particular city, there are 2. No one can really answer why the results are different without seeing all of your actual db data.

adamjhn's avatar

Thanks, but in the database there are 5 conferences that have category_id "2". And when the category with id 2 is clicked the result is what is in the question with only one result. The pivot table category_conference has:

id conference_id   category_id

1             1                       1
2            7                      2
3            8                      2
4            9                     2
5            10                    2
...
11           16                    2
Cronix's avatar

Then it probably has to do with how you defined the categories relationship, which you haven't shown.

$conferences = Conference::whereHas('categories', function ($categories) use (&$request) {
            $categories->where('category_conference.id',$request->id);
})->get();

You probably also don't want to use a whereHas there. You'd just want a with. whereHas will only return a result if there is at least 1 conference.

So what does your categories relationship look like in the Conference model?

adamjhn's avatar

Thanks, its a many to many relationship. A conference can have many categories a category can belong to many categories. Its like:


class Conference extends Model{
     public function categories(){
        return $this->belongsToMany('App\Category');
    }
}

class Category extends Model
{
    public function conferences(){
        return $this->belongsToMany('App\Conference');
    }
}

Then there is a pivot table category_conference.


adamjhn's avatar

Thanks, now it appears:

"SQLSTATE[42S22]: Column not found: 1054 Unknown column 'categories.conference_id' in 'where clause' (SQL: select * from conferences where exists (select * from categories where conferences.id = categories.conference_id and category_conference.id = 2))".

I add "conference_id" to:

  public function categories(){
        return $this->hasMany('App\Category', 'conference_id');
    }

But same error.

Cronix's avatar

Try changing to this

public function WhereHasCategory($id, Request $request)
{
    $conferences = Conference::whereHas('categories', function ($categories) use ($id) {
        $categories->where('category_conference.id', $id);
    })->get();

    return response()->json($conferences);
}

I don't know why you were using $request->id for the ->where(). You're not sending it as data, you're sending $id as part of the url and using it in your route, but you don't use it in the controller. I don't think $request->id even exists.

You could test by doing

public function WhereHasCategory($id, Request $request)
{
    return $request->id;
}

and check your dev tools for the ajax response to see what it gives.

You did it properly for the city and passing the slug, but not the category.

1 like
adamjhn's avatar

Thanks but still appears:

"SQLSTATE[42S22]: Column not found: 1054 Unknown column 'categories.conference_id' in 'where clause' (SQL: select * from conferences where exists (select * from categories where conferences.id = categories.conference_id and category_conference.id = 2))".

The "return $request->id;" shows "2" in the network tab.

Cronix's avatar

That's coming from your where. You're in a relationship, so you don't specify the table name. It will add it in appropriately. Change to

$categories->where('id',$request->id);
adamjhn's avatar

In the WhereHasCategory() method?

Cronix's avatar

yes, that's where you're using it

adamjhn's avatar

Like this:

    public function WhereHasCategory($id, Request $request)
    {
        $conferences = Conference::whereHas('categories', function ($categories) use ($id) {
            $categories->where($id, $request->id);
        })->get();
        
        return response()->json($conferences);
    }

It shows an error in "where($id, $request->id);" undefined variable $request.

Cronix's avatar

Yes, I didn't know you actually changed it, sorry. First 'id' should be in quotes, it's a field name not a variable. The 2nd one is a variable.

$categories->where('id', $id);
1 like
adamjhn's avatar

Thanks but same error:

"SQLSTATE[42S22]: Column not found: 1054 Unknown column 'categories.conference_id' in 'where clause' (SQL: select * from conferences where exists (select * from categories where conferences.id = categories.conference_id and category_conference.id = 2))".

Please or to participate in this conversation.