1

I have seen multiple examples where indexOf is used within Vue to select an object from an array of objects like this:

Script:

new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue.js!',
    items: [
        {
        id: 1,
        name: 'test'
      },
      {
        id: 2,
        name: 'hello'
      },
      {
        id: 3,
        name: 'world'
      }
    ]
  },
  methods: {
    deleteItem(item) {
      console.log(this.items.indexOf(item));
      // splice the item.
    }
  }
})

Template:

<script src="https://unpkg.com/vue"></script>

<div id="app">
  <p>{{ message }}</p>

  <ul>
    <li v-for="item in items" @click=deleteItem(item)>
      {{ item.name }}
    </li>
  </ul>
</div>

https://jsfiddle.net/5gwtyv3h/

Now I am wondering this is even possible. If I go into my console and simply do this:

const items = [
    {
        id: 1,
        name: 'test'
    },
    {
        id: 2,
        name: 'hello'
    },
    {
        id: 3,
        name: 'world'
    }
];

items.indexOf({ id: 1, name: 'test'});

I get -1 because the item can not be found. Is Vue doing something that makes this possible or I missing something else here?

Stephan-v
  • 19,255
  • 31
  • 115
  • 201
  • 1
    Your test always returns -1 because the object literal you're passing is not in the items array. Object comparisons don't involve the object *contents*; they're based on the object references. – Pointy Feb 05 '18 at 15:41
  • 1
    Possible duplicate of [Difference Between indexOf and findIndex function of array](https://stackoverflow.com/questions/41443029/difference-between-indexof-and-findindex-function-of-array) – str Feb 05 '18 at 15:41
  • So it works with the object references? I find that extremely hard to find online. Even the mozilla page does not seem to mention anything about it: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf – Stephan-v Feb 05 '18 at 15:43
  • @str the question you marked as a duplicate says nothing about references or looking for objects. – Stephan-v Feb 05 '18 at 15:44
  • @Stephan-v The answer mentions "primitive types" and "non-primitive types (e.g. objects)". – str Feb 05 '18 at 15:49

1 Answers1

3

You will have to cache the object that you add to the Array or do a deep find() or findIndex() comparison.

For Objects compared with indexOf, they have to be the exact same Object, meaning, they must refer to the exact same Object instance.

const a = {
    foo: "bar"
  },
  b = {
    foo: "bar"
  };

console.log(a === b); // false

Consider this:

const a = {
    foo: "bar"
  },
  b = {
    foo: "bar"
  };

const c = [a, b];

console.log(c.indexOf({
  foo: "bar"
})); // -1 since the Object you **just** made won't be in the array

console.log(c.indexOf(a)); // 0 you're looking for the right object by reference

console.log(c.findIndex(i => i.foo === "bar")); // 0 again since it does a deep compare

// Succinct deep compare using lodash
console.log(_.findIndex(c, i => _.isEqual(i, {
  foo: "bar"
}))); // 0 again but deep compare logic is encapsulated
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
zero298
  • 25,467
  • 10
  • 75
  • 100
  • Thanks, I feel this is not explained enough. Documentation about `indexOf` seems to be lacking in this part. – Stephan-v Feb 05 '18 at 15:46