# Async items

To load the items asynchronously, listen for the open event then fetch the suggestion items:











 
 
 








 







<script>
export default {
  data () {
    return {
      text: '',
      items: [],
    }
  },

  methods: {
    async loadIssues () {
      this.items = await fetchIssues()
    }
  },
}
</script>

<template>
  <Mentionable
    :keys="['#']"
    :items="items"
    @open="loadIssues()"
  >
    <textarea
      v-model="text"
    />
  </Mentionable>
</template>

# Loading state

Store your loading state in a data property:






 





 

 




export default {
  data () {
    return {
      text: '',
      items: [],
      loading: false,
    }
  },

  methods: {
    async loadIssues () {
      this.loading = true
      this.items = await fetchIssues()
      this.loading = false
    }
  },
}

Then display a different content for the loading state in the no-result slot:











 
 
 



<template>
  <Mentionable
    :keys="['#']"
    :items="items"
    @open="loadIssues()"
  >
    <textarea
      v-model="text"
    />

    <template #no-result>
      {{ loading ? 'Loading...' : 'No result' }}
    </template>
  </Mentionable>
</template>

Listen for the search event to fetch the issues again with an additional searchText parameter:












 

 











 











<script>
export default {
  data () {
    return {
      text: '',
      items: [],
      loading: false,
    }
  },

  methods: {
    async loadIssues (searchText = null) {
      this.loading = true
      this.items = await fetchIssues(searchText)
      this.loading = false
    }
  },
}
</script>

<template>
  <Mentionable
    :keys="['#']"
    :items="items"
    @open="loadIssues()"
    @search="loadIssues($event)"
  >
    <textarea
      v-model="text"
    />

    <template #no-result>
      {{ loading ? 'Loading...' : 'No result' }}
    </template>
  </Mentionable>
</template>

The first payload of the search event is the text entered by the user after the key. In the code above we access it with $event.

Mentionable has a builtin filtering feature that we need to disable since the server will take care of it:





 













<template>
  <Mentionable
    :keys="['#']"
    :items="items"
    filtering-disabled
    @open="loadIssues()"
    @search="loadIssues($event)"
  >
    <textarea
      v-model="text"
    />

    <template #no-result>
      {{ loading ? 'Loading...' : 'No result' }}
    </template>
  </Mentionable>
</template>

# Final demo

This demo fakes the loading of issues with a one second delay:

<script>
import { Mentionable } from 'vue-mention'

const issues = [
  {
    value: 123,
    label: 'Error with foo bar'
  },
  {
    value: 42,
    label: 'Cannot read line'
  },
  {
    value: 77,
    label: 'I have a feature suggestion'
  }
]

function fetchIssues (searchText = null) {
  return new Promise(resolve => {
    setTimeout(() => {
      if (!searchText) {
        resolve(issues)
      } else {
        const reg = new RegExp(searchText, 'i')
        resolve(issues.filter(issue => reg.test(issue.label)))
      }
    }, 1000)
  })
}

export default {
  components: {
    Mentionable,
  },

  data () {
    return {
      text: '',
      items: [],
      loading: false,
    }
  },

  methods: {
    async loadIssues (searchText = null) {
      this.loading = true
      this.items = await fetchIssues(searchText)
      this.loading = false
    }
  },
}
</script>

<template>
  <div
    class="demo"
  >
    <Mentionable
      :keys="['#']"
      :items="items"
      offset="6"
      filtering-disabled
      @open="loadIssues()"
      @search="loadIssues($event)"
    >
      <textarea
        v-model="text"
        rows="6"
        class="input"
        placeholder="Enter text and then type # to trigger the mention"
      />

      <template #no-result>
        <div class="dim">
          {{ loading ? 'Loading...' : 'No result' }}
        </div>
      </template>

      <template #item-#="{ item }">
        <div class="issue">
          <span class="number">
            #{{ item.value }}
          </span>
          <span class="dim">
            {{ item.label }}
          </span>
        </div>
      </template>
    </Mentionable>

    <div class="preview">{{ text }}</div>
  </div>
</template>

<style scoped>
.demo {
  margin: 24px 0;
}

.input {
  width: 100%;
  border: #ccc 1px solid;
  border-radius: 6px;
  resize: vertical;
  min-height: 42px;
  padding: 12px;
  box-sizing: border-box;
  line-height: 1.2em;
  font-size: inherit;
}

.issue {
  padding: 4px 6px;
  border-radius: 4px;
  cursor: pointer;
}

.mention-selected .issue {
  background: rgb(139, 212, 255);
}

.issue .number {
  font-family: monospace;
}

.dim {
  color: #666;
}

.preview {
  font-family: monospace;
  white-space: pre-wrap;
  margin-top: 12px;
  padding: 12px;
  background: #f8f8f8;
  border-radius: 6px;
}
</style>