Dale Nguyen
Dale Nguyen

Reputation: 1980

Issue when using Vuejs with computed filter

I am writing a filter application by using Vuejs with checkboxes. It works well when I use single checkbox. However, it removes the results when I check more than than 2 checkboxes.

For example, when I check Green and Red, it should show the Title 1 and Title 2. Or when I check Green, Red, Active, Completed, it should show the Title 1 and Title 2.

You can check my code at: https://jsfiddle.net/dalenguyen/xLcvdy0n/1/

HTML code:

<div class="content">
<div class="row">
    <div class="col-md-3 col-sm-4">
        <div class="box box-info">
            <div class="box-header with-border">
                <h3 class="box-title">Filter by</h3>
            </div>
            <!-- /.box-header -->
            <!-- form start -->
                <div class="box-body">
                    <div class="box box-success box-solid">
                        <div class="box-header with-border">
                            <h3 class="box-title">Health</h3>
                            <!-- /.box-tools -->
                        </div>
                        <!-- /.box-header -->
                        <div class="box-body" style="display: block;">
                            <div class="form-group col-md-12">
                                <input type="checkbox" id="green" value="Green" v-model="checkedHealths" name="Healths">
                                <label for="green">Green</label>

                            </div>
                            <div class="form-group col-md-12">
                                <input type="checkbox" id="red" value="Red" v-model="checkedHealths" name="Healths">
                                <label for="red">Red</label>
                            </div>
                            <div class="form-group col-md-12">
                                <input type="checkbox" id="yellow" value="Yellow" v-model="checkedHealths" name="Healths">
                                <label for="yellow">Yellow</label>
                            </div>
                        </div>
                        <!-- /.box-body -->                      
                    </div>

                    <div class="box box-success box-solid">
                        <div class="box-header with-border">
                            <h3 class="box-title">Status</h3>
                            <!-- /.box-tools -->
                        </div>
                        <!-- /.box-header -->
                        <div class="box-body" style="display: block;">
                            <div class="form-group col-md-12">
                                <input type="checkbox" id="active" value="Active" v-model="checkedStatuses" name="Statuses">
                                <label for="active">Active</label>
                            </div>
                            <div class="form-group col-md-12">
                                <input type="checkbox" id="completed" value="Completed" v-model="checkedStatuses" name="Statuses">
                                <label for="completed">Completed</label>
                            </div>
                            <div class="form-group col-md-12">
                                <input type="checkbox" id="cancelled" value="Cancelled" v-model="checkedStatuses" name="Statuses">
                                <label for="cancelled">Cancelled</label>
                            </div>
                        </div>
                        <!-- /.box-body -->
                    </div>
                    <button type="button" class="btn btn-block btn-info" v-on:click="resetFilter">Reset</button>

                </div>
                <!-- /.box-body -->
        </div>
    </div>
    <div class="col-md-9 col-sm-8">

        <div class="col-md-4" v-for="project in filteredProjects">
            <div class="box collapsed-box">
                <div class="box-header with-border">
                    <h4 class="box-title"><a href="">{{project['title']}}</a></h4>
                    <!-- /.box-tools -->
                </div>
                <!-- /.box-header -->
                <div class="box-body">
                    <table class="table table-striped">
                        <tr>
                            <td>Status</td>
                            <td>{{project['Status']}}</td>
                        </tr>
                         <tr>
                            <td>Health</td>
                            <td>{{project['Health']}}</td>
                        </tr>
                    </table>
                </div>
                <!-- /.box-body -->
            </div>
            <!-- /.box -->
        </div>
    </div>
</div>

</div>

Vuejs code:

var app = new Vue({
            el: '.content',

            data: {
                projects: [
                    {
                      "title": "Title 1",
                      "Status": "Active",
                      "Health": "Green",
                    },
                    {
                      "title": "Title 2",
                      "Status": "Completed",
                      "Health": "Red",
                    },
                    {
                      "title": "Title 3",
                      "Status": "Cancelled",
                      "Health": "Yellow",
                    },                    
                  ]                                
                ,
                checkedHealths: [],
                checkedStatuses: []
            },

            computed: {
                filteredProjects: function(){
                    let filterProjects = this.projects;


                    $.each(this.checkedHealths, function(value, key){                       
                       filterProjects = filterProjects.filter(function(project){                            
                           return project.Health == key;
                       })
                    });

                    $.each(this.checkedStatuses, function(value, key){
                        filterProjects = filterProjects.filter(function(project){
                            return project.Status.includes(key);
                        })
                    });

                    return filterProjects;
                }
            },

            mounted: function(){

                jQuery('input').iCheck({
                    checkboxClass: 'icheckbox_square-green',
                    radioClass: 'iradio_square-green',
                    increaseArea: '20%' // optional
                });

                jQuery('input').on('ifChecked', function(e){

                    if($(this).attr('name') === "Healths")
                        app.$data.checkedHealths.push($(this).val());

                    if($(this).attr('name') === "Statuses")
                        app.$data.checkedStatuses.push($(this).val());

                });

                jQuery('input').on('ifUnchecked', function(e){

                    if($(this).attr('name') === "Healths"){
                        let data = app.$data.checkedHealths;
                        app.$data.checkedHealths.splice(data.indexOf($(this).val()),1);
                    }

                    if($(this).attr('name') === "Statuses"){
                        let data = app.$data.checkedStatuses;
                        app.$data.checkedStatuses.splice(data.indexOf($(this).val()),1);
                    }

                });
            },

            methods: {
                resetFilter: function(){
                    $('input').iCheck('uncheck');
                }
            }
        })

Upvotes: 1

Views: 1372

Answers (1)

Bert
Bert

Reputation: 82449

Your filterProjects method should look something like this.

filteredProjects: function(){
  let filterProjects = this.projects;

  if (this.checkedHealths.length > 0){
    filterProjects = filterProjects.filter(project => {
      return this.checkedHealths.includes(project.Health);
    })
  }

  if (this.checkedStatuses.length > 0){
    filterProjects = filterProjects.filter(project => {
      return this.checkedStatuses.includes(project.Status)
    })
  }

  return filterProjects;
}

Updated fiddle.

Essentially, your old filter code was checking each filter individually, where you needed to handle them all at once. The above code loops through the projects and checks if the project's value is in the selected filter values.

You're also using a lot of jQuery where you could just be using native methods and Vue.

Upvotes: 3

Related Questions