One Of Those Clever Drop Down Boxes That Fills Things In For You

in Value 4 Value11 months ago (edited)

Building the next v4v.app v2

This is a value for value post: see the explanation in the footer.


A simple tool for selecting Hive accounts from a drop down in Vue 3, Quasar Framework using the Composition API.

This is going to sound stupid to those of you who haven't ever tried to program or learned a new programming skill after years but it's not joke to say that it has taken me a year to properly understand this.

It really shouldn't have been so hard for me to figure it out, but it was. I have something like this working on v4v.app right now but I honestly don't know how I managed to get it working.

For now you can see this selector (and a fancier one) working on this demo page: https://demo.v4v.app/selectdemo

image.png

Only now have I actually built this thing in such a way that I understand every line of code.

The HiveSelectAcc component

I've actually built a simple one and a more complex one but I'm presenting the simple one first because I hope this is easier to understand.

If any of you Javascript wizards can tell me I'm doing this wrong, I'd love to hear from you. In the meantime, this is what I came up with.

Select object for Hive Accounts

This is the extended explanation for the Simple selector for picking Hive Accounts: HiveSelectAcc.

This selector uses the Quasar q-select object and uses autocompletion based on the partial Hive account name entered. It looks up and presents options from the Hive API sorted in descending order of Hive account reputation. If an exact match for the entered Hive account is found, that is returned.

This Component emits the selected Hive account name and displays the selected Hive account's profile picture.

https://github.com/brianoflondon/v4vapp-frontend-v2/blob/f99a30a3cb208da0770497c1cabdf5ab27655690/src/components/SelectHiveAcc.vue

Template

The Template options as set are taken from this example in the Quasar Documentation SelectAfterFiltering.

Unfortunately all the examples in the Quasar documentation use the older Options API and I'm working with the newer Compositions API. I converted this example and you can find the converted version at this link

<template>
  <q-select
    class="hive-select-account"
    v-model="model"
    hide-selected
    use-input
    fill-input
    options-html
    input-debounce="300"
    spellcheck="false"
    :label="label"
    :options="options"
    @filter="filterFnAutoselect"
    @filter-abort="abortFilterFn"
    @keydown.enter="enterFn"
    @keydown.tab="enterFn"
    @keydown.esc="escFn"
    @input-value="inputFn"
  >
    <template v-slot:before>
      <q-avatar rounded size="md">
        <img :src="avatar" @error="handleImageError" />
      </q-avatar>
    </template>
    <template v-slot:no-option>
      <q-item>
        <q-item-section class="text-grey"> No results </q-item-section>
      </q-item>
    </template>
  </q-select>
</template>

Script Setup

You will noticed that this component uses calls from src/use/useHive.js which I will also include below.

The optional props are described in the comment section.

<script setup>
/**
 * SelectHiveAcc
 * A select component for picking Hive accounts
 *
 * @props {string} label - The prompt label to show in the Select box
 * @props {number} maxOptions - Default: 10 - Maximum number of options to show in the dropdown
 * @props {string} size - Default: small - small, medium, large size of the avatar
 * @emits {string} updateValue - Emitted value of selected Hive Account
 */
import { ref, watch } from "vue"
import {
  useLoadHiveAccountsReputation,
  useBlankProfileURL,
  useHiveAvatarURL,
} from "src/use/useHive"

const options = ref([])
const model = ref()
const avatar = ref(useBlankProfileURL())
const emit = defineEmits(["updateValue"])
const props = defineProps({
  label: {
    type: String,
    default: "Hive Account",
  },
  maxOptions: {
    type: Number,
    default: 10,
  },
  size: {
    type: String,
    default: "small",
  },
  fancyOptions: {
    type: Boolean,
    default: false,
  },
})

watch(model, (newValue) => {
  // Watches the model which holds the selected value
  avatar.value = useHiveAvatarURL({ hiveAccname: newValue, size: props.size })
  emit("updateValue", newValue)
})

function enterFn(input) {
  // If Enter or tab is pressed before selecting from the options, the first option is selected
  if (!model.value && options.value.length > 0) {
    model.value = options.value[0]
  }
  emit("updateValue", model.value)
}

function escFn(input) {
  // If Esc is pressed, the model is cleared
  model.value = ""
}

function inputFn(input) {
  // Change the avatar to match the input value
  setHiveAvatar(input)
}

function setHiveAvatar(hiveAccname) {
  avatar.value = useHiveAvatarURL({ hiveAccname, size: props.size })
}

function handleImageError(event) {
  avatar.value = useBlankProfileURL()
}

async function filterFnAutoselect(val, update, abort) {
  // Finds relevant Hive accounts for the options drop down
  update(
    async () => {
      if (val === "") {
        options.value = []
      } else {
        // Fetch the sorted list of Hive accounts after converting
        // the input to lowercase and removing spaces
        const needle = val.toLowerCase().replace(/\s+/g, "")
        options.value = await useLoadHiveAccountsReputation(
          needle,
          props.maxOptions
        )
        // Sets the displayed Hive avatar to the first option in the
        // options list
        if (options.value) {
          setHiveAvatar(options.value[0])
        }
      }
    },
    (ref) => {
      if (val !== "" && ref.options.length > 0 && ref.getOptionIndex() === -1) {
        ref.moveOptionSelection(1, true)
        ref.toggleOption(ref.options[ref.optionIndex], true)
      }
    }
  )
  abort(() => {
    abortFilterFn
  })
}

const abortFilterFn = () => {
  console.log("delayed filter aborted")
}
</script>

<style lang="scss" scoped></style>

Hive Functions

First note is that I'm using the HiveTx library. Hive-tx-js. I was unable to get this to work successfullyy by installing with yarn so I copied the minified js file into my project and I import it like this:

import "src/assets/hive-tx.min.js"

You can see the complete file here: useHive.js

How to use the Template

This should be all you need to put the object in your own project. Once this object is on the page you will have access to the selected Hive account name in the hiveAccname variable.


<template>
  <HiveSelectAcc
    @updateValue="
      (value) => {
        hiveAccname = value
      }
    "
  />
</template>
import { ref } from "vue"
const hiveAccname = ref("")

<script setup>


</script>

Value for Value

For the last few months while building @v4vapp I was generously supported by the DHF. Going forward I have a much more modest support which covers direct server costs and a little of my time.

If you appreciate the work I do on and around Hive, you can express this directly: upvoting posts on Hive is great. Also consider a direct donation (there's a Tip button on Hive or a Lightning Address) on all my posts.

Support Proposal 244 on PeakD
Support Proposal 244 with Hivesigner
Support Proposal 244 on Ecency
Vote for Brianoflondon's Witness KeyChain or HiveSigner


Send Lightning to Me!

Sort:  

Kudos champ you are doing well

Why this post is not opening in ecency mobile app? Everytime I try to open it says try again. Then I copied the link and opened in my browser.

You are doing an amazing job, I also did some coding and programming, when I was studying, and even built software in c# as my final year project, but now I'm not doing anything like this for the past 5 to 6 years, It's hard when you have left something and start doing it after a long break. Just keep doing the good work !!!!

All that matters is that you finally found how this works and you'll be implementing where necessary going forward. Congratulations on the new addition to your coding knowledge. Cheers 🥂

Your really good at this which is quite encouraging for people to learn.

Nice control allowing a quick search along with a select option. Such components bring more usability and allow also a bit of discovery through retrieving data as you type. Keep on building and learning!

The way we use apps etc. the search option is either not working or slow too much which makes the users feel very bad. The way we see your daily post you tell us something new daily special from which we learn a lot.

That will definitely be an amazing tool this will be after been created fully

Congratulations @brianoflondon! You have completed the following achievement on the Hive blockchain And have been rewarded with New badge(s)

You made more than 3500 comments.
Your next target is to reach 4000 comments.

You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word STOP

To support your work, I also upvoted your post!

Check out our last posts:

The Hive Gamification Proposal

PIZZA!
The Hive.Pizza team manually curated this post.

Join us in Discord!