1
votes

I have been stuck on this for a while, have been on Google, Stack Overflow, read over 100 posts however no luck finding the explanation on what is happening.

I'm new on VUE and still learning but this thing baffles me.

I've got a list of people data objects where v-for code is initiated and rows are represented within the table depending on the data object.

        <tr v-for="person in people" :key="person.id">
          <td>
            <router-link
              :to="{name: 'person-edit', params: { id: person.id }}"
            >{{person | fullName}}</router-link>
          </td>

<!--          Shows No as a result-->
          <td>{{(person | palindrome) ? 'Yes' : 'No'}}</td>
<!--          Shows No as a result-->
          <td v-if="person | palindrome">Yes</td>
          <td v-else>No</td>
<!--          Shows true as a result-->
          <td>{{person | palindrome}}</td>

          <td>{{person.authorised ? 'Yes' : 'No'}}</td>
          <td>{{person.enabled ? 'Yes' : 'No'}}</td>
          <td>{{person.colours | colourNames}}</td>
        </tr>

First and second code examples also prints on a client console this error:

[Vue warn]: Property or method "palindrome" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.

Since {{person | palindrome}} returns true this proves that palindrome function is functioning, however, I'm unable to render Yes or No within HTML code part.

<script lang="ts">
  import Vue from 'vue';
  import {getPeople} from '../api/people-api';

  export default Vue.extend({
  async mounted() {
    this.people = await getPeople();
  },
  data() {
    const people: IPerson[] = [];

    return {
      people,
    };
  },
  filters: {
    colourNames: (colours: IColour[]): string => {

      const coloursString: string[] = [];

      colours.forEach((colour) => {
        coloursString.push(colour.name);
      });

      return coloursString.sort().join();
    },
    fullName: (person: IPerson): string => {
      return `${person.firstName} ${person.lastName}`;
    },
    palindrome: (person: IPerson): boolean => {
      const fullName = `${person.firstName} ${person.lastName}`;
      // TODO: Step 5
      //
      // Implement the palindrome computed field.
      // True should be returned When the FullName is spelt the same
      // forwards as it is backwards. The match should ignore any
      // spaces and should also be case insensitive.
      //
      // Example: "Bo Bob" is a palindrome.

      const nameLowerCase = fullName.toLowerCase().split(' ').join('');
      const nameReversed = nameLowerCase.split('').reverse().join('');
      return nameLowerCase === nameReversed;
    },
  },
});
</script>

I have managed to change the palindrome function to return string if full name is a palindrome, however, task specifically requests to return a boolean value when palindrome function is initiated.

Any hints, advice? Please.

Edit

People dataset:

[
  {
    "id": 1,
    "firstName": "Bo",
    "lastName": "Bob",
    "authorised": true,
    "enabled": false,
    "colours": [
      {
        "id": 1,
        "name": "Red"
      }
    ]
  },
  {
    "id": 2,
    "firstName": "Brian",
    "lastName": "Allen",
    "authorised": true,
    "enabled": true,
    "colours": [
      {
        "id": 1,
        "name": "Red"
      },
      {
        "id": 2,
        "name": "Green"
      },
      {
        "id": 3,
        "name": "Blue"
      }
    ]
  },
  {
    "id": 3,
    "firstName": "Courtney",
    "lastName": "Arnold",
    "authorised": true,
    "enabled": true,
    "colours": [
      {
        "id": 1,
        "name": "Red"
      }
    ]
  },
  {
    "id": 4,
    "firstName": "Gabriel",
    "lastName": "Francis",
    "authorised": false,
    "enabled": false,
    "colours": [
      {
        "id": 2,
        "name": "Green"
      }
    ]
  },
  {
    "id": 5,
    "firstName": "George",
    "lastName": "Edwards",
    "authorised": true,
    "enabled": false,
    "colours": [
      {
        "id": 2,
        "name": "Green"
      },
      {
        "id": 3,
        "name": "Blue"
      }
    ]
  },
  {
    "id": 6,
    "firstName": "Imogen",
    "lastName": "Kent",
    "authorised": false,
    "enabled": false,
    "colours": [
      {
        "id": 1,
        "name": "Red"
      },
      {
        "id": 2,
        "name": "Green"
      }
    ]
  },
  {
    "id": 7,
    "firstName": "Joel",
    "lastName": "Daly",
    "authorised": true,
    "enabled": true,
    "colours": [
      {
        "id": 2,
        "name": "Green"
      }
    ]
  },
  {
    "id": 8,
    "firstName": "Lilly",
    "lastName": "Hale",
    "authorised": false,
    "enabled": false,
    "colours": [
      {
        "id": 1,
        "name": "Red"
      },
      {
        "id": 2,
        "name": "Green"
      },
      {
        "id": 3,
        "name": "Blue"
      }
    ]
  },
  {
    "id": 9,
    "firstName": "Patrick",
    "lastName": "Kerr",
    "authorised": true,
    "enabled": true,
    "colours": [
      {
        "id": 2,
        "name": "Green"
      }
    ]
  },
  {
    "id": 10,
    "firstName": "Sharon",
    "lastName": "Halt",
    "authorised": false,
    "enabled": false,
    "colours": [
      {
        "id": 1,
        "name": "Red"
      },
      {
        "id": 2,
        "name": "Green"
      },
      {
        "id": 3,
        "name": "Blue"
      }
    ]
  },
  {
    "id": 11,
    "firstName": "Willis",
    "lastName": "Tibbs",
    "authorised": true,
    "enabled": false,
    "colours": [
      {
        "id": 1,
        "name": "Red"
      },
      {
        "id": 2,
        "name": "Green"
      },
      {
        "id": 3,
        "name": "Blue"
      }
    ]
  }
]
2

2 Answers

2
votes

Filters can only be used at the end of a template expression. The only things that can come after a filter are its arguments or another, chained filter.

If you use a filter in the middle of an expression, such as (person | palindrome) ? 'Yes' : 'No', the | will just be interpreted as JavaScript's bit-wise OR operator. In this context person and palindrome are both treated as properties of the Vue instance. i.e. this.person and this.palindrome. The latter doesn't exist so you'll see the warning message.

You're inside a loop, so using a computed property would be tricky.

One way to fix this is to make it a method instead of a filter. You can then call it using palindrome(person) ? 'Yes' : 'No'.

If you really want to keep it as a filter and changing it to return strings is not an option then you could use chaining. That'd be something like this:

<td>{{ person | palindrome | toYesNo }}</td>

You'd then define a filter called toYesNo to take a boolean and return the relevant string.

0
votes

I think your issue is with syntax, have you tried making it a computed property instead of a ternary operator in parenthesis? You can access filter like this: this.$options.filters.palindrome make it a computed and you should be good.

In addition I am assuming you are making your filters available globally properly otherwise that may be the cause. In terms of debugging it would be helpful to provide some actual data so it can be tested. The first step would be to console log your filter to see that it is there. console.log(this.$options.filters.palindrome), then see my first comment