0

My issue is that I didn't get how to implement Vue.set and array.splice on my code to avoid Javascript caveats.

Here is what I'm trying to do:

I highlight a text with my mouse or trackpad and on mouseup the highlighted text is stored on an array of objects. Each object contains the selected text.

I wish to loop on that array to be able to display all selection one by one as long as I'm selecting different text.

Basically, I'm storing each selected text to selectionArray. Each selectedText is a string inside an object. So SelectionArray becomes an array of objects like this On the first selection:

[
 {selectedText: '...string...'}
]

On the second selection the array is updated:

[
 {selectedText: '...string...'},
 {selectedText: '...another string...'}
]

And so on... At the end, I loop with v-on on items array which is equal to selectionArray with:

this.items = selectionArray

For the moment I'm almost there but Vue can't detect addition/deletion of array items and object properties. Caveats section of the Vue guide explain it, but I didn't get how to do it as I'm pretty new with Vue js. Any help please?

Here is the code:

<template>
  <main class='wrapper'>
    <section class='wrapper-copy'>
      <div class='copy'>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Omnis sequi dolorum soluta pariatur asperiores. Recusandae atque nesciunt ipsa velit impedit fugit enim, quia explicabo adipisci sunt earum laudantium illo. Tenetur.
Animi magnam corrupti atque mollitia eaque enim, voluptatum magni laboriosam vel possimus reprehenderit aut doloribus inventore repellat aliquam voluptatem esse ut saepe at iusto qui quibusdam doloremque exercitationem ipsam. Dicta.
In animi nobis accusamus nemo repellat dicta a repellendus provident accusantium fugit voluptas minus laudantium reiciendis cumque, amet porro maiores quisquam? Ullam aut voluptatem delectus cum rerum perferendis vero laudantium!
      </div>

    </section>
    <article class="wrapper-select">
      <div class="select">
        <div id='input'
             class='selected-copy'
             v-for='(item, index) in items' 
             :key='item.index'>
          <div class='index'>{{ index }} </div>
          <p class='selection'> {{ item.selectedText }} </p>
        </div>
      </div>
    </article>
  </main>
</template>

<script>
  export default {
    name: 'app',
    data () {
      return {
        items: []
      }
    },
    created () {
      var selectionArray = []
      function storeSelection () {
        var selectedText = window.getSelection().toString()
        if (selectedText.length && selectionArray.indexOf(selectedText) === -1) {
          selectionArray[selectionArray.length] = {selectedText}
        }
        console.log(selectionArray)
      }
      document.addEventListener('mouseup', storeSelection)
      this.items = selectionArray
      console.log(this.items)
    }
  }
</script>

1 Answer 1

1

From the documentation link you provided, you should change the code where you add an array element to:

if (selectedText.length && selectionArray.indexOf(selectedText) === -1) {
     Vue.set(selectionArray, selectionArray.length, {selectedText});
}

By the way, there are 2 flaws in your code:

_selectionArray[selectionArray.length] = {selectedText} should throw an error (unless there is a special Vue syntax i don't know), because you need a property id for the object to be valid (it should be selectionArray[selectionArray.length] = {selectedText: selectedText})

_the problem with storing these texts as objects is that this line won't work: if (selectedText.length && selectionArray.indexOf(selectedText) === -1) {, because the array element is not the text, but an objet with the text in it. Even with indexOf({selectedText: selectedText}) === -1 it won't work, because the comparison of objects is made on their reference, and the stored object and the tested one have different references.

CONCLUSION: to make it work, either store the text in the array without embedding it in an object, either use findIndex function to find your element, like this (i separated the finding function from the condition for more readability):

function findSelectedText(arr, text){
    return arr.findIndex(function(element){
        return element.selectedText === text;
    });
}
if (selectedText.length && findSelectedText(selectionArray, selectedText) === -1) {
     Vue.set(selectionArray, selectionArray.length, {selectedText: selectedText});
}
Sign up to request clarification or add additional context in comments.

3 Comments

Kaddath Thank you very much for your very precise explanations. You are so right and this work perfectly! 5* clap clap!
you're welcome, i see Vue.js questions so often here that i wanted to "throw an eye at it" as we say in my country ;)
And you are on the very good way from what I saw :). I started to learn Vue as well and it's so lean and smooth. I bet in the next 6months/1year maximum it will be the most famous Js framework. Again thank you for your time and your help. Much appreciated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.