Today I was building a profile page for a client’s app. The form has classic fields like first name, last name, email address, etc.. but also an “Avatar” field.

The Avatar must be picked amongst a few avatars that I uploaded in a static folder.
I want my app to list all those files and render them as a list of avatar components and when the user clicks on one of the avatar it should update the selected avatar.
Here’s what I started with. A simple Profile form with all the fields, the current avatar and a button “Change Avatar”.

When the user clicks on “Change Avatar” I want to open a dialog with all the available avatars. When the user clicks an avatar it should close the dialog & replace the current avatar with the new one.
Here’s the code for this view. I’m using Nuxt by the way.
Now let’s create an AvatarPicker component. As I said, this will be a dialog so we can start by creating a dialog component.
<template>
<v-dialog :fullscreen="$vuetify.breakpoint.xs" width="500" transition="dialog-bottom-transition" v-model="show">
<v-card>
<v-toolbar dark color="primary">
<v-btn icon dark @click="show = false">
<v-icon>close</v-icon>
</v-btn>
<v-toolbar-title>Select an Avatar</v-toolbar-title>
<v-spacer></v-spacer>
</v-toolbar>
<v-layout>
... Avatars will be here
</v-layout>
</v-card>
</v-dialog>
</template>
Now this component will accept 2 props: `currentAvatar` which will let us style the current avatar as we want and `value` which will make the dialog open or closed.
export default {
props: {
currentAvatar: {
type: String,
required: true
},
value: Boolean
}
}
Now we need to take care of the `show` property that’s used as the dialog’s v-model.
export default {
...,
computed: {
show: {
get () {
return this.value
},
set (value) {
this.$emit('input', value)
}
}
}
}
This is a trick that makes it possible to open a dialog component from another component. Here’s more info.
Now we need to list all avatars from my `~/static/avatars/` directory. For this I found a useful snippet in the Laravel Framework. They use it for auto registering all components.
I am not sure if this is a really good method, but I find it useful and it works. Feel free to PM me if you have a better alternative.
So basically here’s how it works:
let files = require.context('~/static/avatars', true, /\.png$/i)
files.keys() returns an array of all the files found in the directory we passed (~/static/avatars) if we console.dir the result we should see something like this.

Now that we have an array, we can easily work with it to return the results we want.
In my case I want an `avatars` object that is formatted like this:
let avatars = {
'FEMALE_AFRO_AMERICAN_BLACK_ATTACHED_HAIR': {
id: 'FEMALE_AFRO_AMERICAN_BLACK_ATTACHED_HAIR',
path: 'avatar_female_afro_american_black_attached_hair.png'
},
...
}
This way in my database, my user will have an avatar value of FEMALE_AFRO_AMERICAN_BLACK_ATTACHED_HAIR and I’ll be able to retrieve it’s path using something like avatars[profile.avatar].path.
Let’s do it. We work a little on the key to generate the id and the path.
let avatars = {}
let files = require.context('~/static/avatars', true, /\.png$/i)
files.keys().map((key) => {
let id = key.split('/').pop().split('.')[0].substring(7).toUpperCase()
avatars[id] = {
path: key.split('/').pop(),
id: id
}
})
If you console.table the avatars you should see something like this.

Now that we have the avatars, let’s display them in the dialog.
<v-layout row wrap>
<v-flex
v-for="avatar in avatars"
:key="avatar.id"
xs4 sm3
d-flex>
<v-card tile flat class="d-flex">
<v-card-text class="d-flex">
<v-avatar
size="96"
@click="selectAvatar(avatar)"
class="avatar-picker-avatar"
:class="{ 'current': avatar.id === currentAvatar }">
<img :src="'/avatars/' + (avatar.path)">
</v-avatar>
</v-card-text>
</v-card>
</v-flex>
</v-layout>
Now it should look like this.

Now we just need to add the logic to replace the current avatar.
First in the AvatarPicker.vue we’ll add the `selectAvatar` method that’ll emit the `selected` event.
export default {
...,
methods: {
selectAvatar (avatar) {
this.$emit('selected', avatar.id)
this.show = false
}
}
}
In the profile.vue page we’ll now catch this event and replace the avatar in the form.
export default {
...,
methods: {
selectAvatar (avatar) {
this.form.avatar = avatar
}
}
}
VoilĂ !
You can check out the full code on this gist.
https://gist.github.com/depsimon/66edd89939f6700c50b5946d4e129460