0

I have made a simple Datatable with search input,

Student.js

Vue.component('student-list',{
    props: ['students'],
    template:`

<div class="table-responsive">
<table class="table table-hover mails m-0 table table-actions-bar">
<thead>
    <tr>
        <th>10</th>
        <th>9</th>
        <th>8</th>
        <th>7</th>
        <th>6</th>
        <th>5</th>
        <th>4</th>
        <th>3</th>
        <th>2</th>
        <th>1</th>
    </tr>
</thead>
<tbody>
    <student v-for="student in searchResults" :student="student"></student>
</tbody>
</table>
</div>
    `,
    computed: 
    {
        searchResults: function(student){
            var self = this;
            return this.students.filter(
                function(student){
                    if(this.searchQuery == '' || this.searchQuery == null) { return true; }
                    console.log(this.searchQuery);
                    return (student.toString().indexOf(this.searchQuery) != -1);
                }
                );
        }
    },

//  v-if="searchResults(student)"

});

Vue.component('student',{
    props: ['student'],
    template:`
        <tr>
            <td>
                {{ student.name }} {{ student.lname }}
            </td>
            <td>
                <a href="tel:{{ student.phone }}" title="התקשר" class="table-action-btn"><i class="md-phone"></i></a>
                <a href="tel:{{ student.momPhone }}" title="התקשר לאמא" class="table-action-btn"><i class="ion-woman"></i></a>
                <a href="tel:{{ student.dadPhone }}" title="התקשר לאבא" class="table-action-btn"><i class="ion-man"></i></a>
                <a href="/users/{{ student.id }}" title="ערוך" class="table-action-btn"><i class="ion-android-settings"></i></a>
            </td>
            <td>
                {{ student.address }}
            </td>  
            <td>
                {{ student.totalTopay }}
            </td>
            <td>
                {{ student.lessonsTaken }}
            </td>
            <td>
                {{ student.cancelCount }}
            </td>    
            <td>
                {{ student.phone }}
            </td>
            <td>
                {{ student.momPhone }}
            </td>
            <td>
                {{ student.dadPhone }}
            </td>
            <td>
                {{ student.email }}
            </td>
        </tr>
    `

});

new Vue({
    el: '#content-page',
    data: {
        'searchQuery': ''
    }
});

HTML

....
<div id="content-page">
        <input type="text" id="search" class="form-control" placeholder="Search..." v-model="searchQuery">
</div>
....
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="{{ asset('js/students.js') }}"></script>
...

Now, for some reason whenever I leave the search blank it works as needed, but when I change the input field by typing in the text box(which his v-model is attached to the searchQuery variable), nothing changes, and when I call it (this.searchQuery) on the Dev Tools console, it says undefined. What am I missing? Thanks in advance everyone!

Raymond Camden
  • 10,661
  • 3
  • 34
  • 68
CodingCode
  • 123
  • 2
  • 12
  • 1
    You have `id="#content-page"` instead of `id="content-page"`. – Roy J Jan 17 '18 at 21:23
  • Thanks @RoyJ but sadly it was a mistake which was just on Stack Overflow. – CodingCode Jan 17 '18 at 21:39
  • try setting `searchResults` as a `method` instead of `computed`. Also try removing the parameter from the function, I don't think computed properties are allowed to take arguments. – Brian Glaz Jan 17 '18 at 22:01

1 Answers1

1

I've edited your code a little bit to make it work and removed some lines of code, because I don't want to recreate the whole student object. I passed the search-query as prop and added <student-list /> to your template. In your filter function I replaced toString with JSON.stringify, because student is an object and toString prints out [object Object]. Also, I changed the props object and added their types.

And one last tiny error:

Interpolation inside attributes has been deprecated. Use v-bind or the colon shorthand instead.

Don't use href="tel:{{ student.phone }}" use something like this instead :href="'tel:' + student.phone".

Vue.component('student-list',{
  props: {
    students: {
      type: Array
    },
    searchQuery: {
      type: String
    }
  },
  template:`<div class="table-responsive">
searchQuery: {{searchQuery}}
<table class="table table-hover mails m-0 table table-actions-bar">
<thead>
<tr>
<th>10</th>
<th>9</th>
<th>8</th>
<th>7</th>
<th>6</th>
<th>5</th>
<th>4</th>
<th>3</th>
<th>2</th>
<th>1</th>
</tr>
</thead>
<student v-for="student in searchResults" :student="student"></student>
</tbody>
</table>
</div>`,
  computed:  {
    searchResults() {
      return this.students.filter(student => JSON.stringify(student).indexOf(this.searchQuery) != -1);
    }
  },
});

Vue.component('student',{
  props: {
    student: {
      type: Object
    }
  },
  template:`<tr>
<td>
{{ student.name }} {{ student.lname }}
</td>
<td>
<a :href="'tel:' + student.phone" title="התקשר" class="table-action-btn">tel-icon</a>
</td>
</tr>`
});

new Vue({
  el: '#content-page',
  data: {
    'searchQuery': ''
  }
});
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
  </head>
  <body>
    <div id="content-page">
      <student-list :search-query="searchQuery" :students="[{
                                                           id: 1,
                                                           name: 'Peter',
                                                           lname: 'Parker',
                                                           phone: 12345
                                                           },{
                                                           id: 2,
                                                           name: 'Bat',
                                                           lname: 'Man',
                                                           phone: 1234
                                                           }]"></student-list>

      <input type="text" id="search" class="form-control" placeholder="Search..." v-model="searchQuery">
    </div>
  </body>
</html>

And my second solution

Add this to your computed:

computed:  {
  searchQuery() {
     return this.$parent.searchQuery || '';
  },
  ...
}
...

You access the parent of student-list, but I think this is not a nice way, because you can't see from where do you get this data.

Hope this will help you a little bit.

Philip
  • 3,486
  • 1
  • 24
  • 37
  • Thank you so much! I have actually noticed the 'tel'+ problem later on and fixed it, but haven't noticed the searchQuery problem. Huge thanks, great tips! – CodingCode Jan 18 '18 at 17:41
  • 1
    Your welcome (: one more thing. I recommend to read this small section about the data object in components, if you don‘t know it already. Maybe this will help you to avoid errors in the future. https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function – Philip Jan 18 '18 at 17:51