Skip to content

Metadata Store User Guide

This guide shows you how to use the Metadata Store in your Vue.js components with practical patterns.

Using in Components

<script setup>
import { useMetadataStore } from 'vue-fastedgy'
import { onMounted, computed } from 'vue'

const metadataStore = useMetadataStore()

const userFields = computed(() => {
  const metadata = metadataStore.getMetadata('User')
  return metadata?.fields || {}
})

onMounted(async () => {
  // Load metadata on component mount
  await metadataStore.getMetadatas()
})
</script>

Form Field Discovery

Use metadata to understand what fields are available for a model:

<template>
  <div>
    <h3>User Fields:</h3>
    <ul>
      <li v-for="(field, name) in userFields" :key="name">
        <strong>{{ name }}</strong>: {{ field.type }}
        <span v-if="field.required">(required)</span>
      </li>
    </ul>
  </div>
</template>

<script setup>
import { useMetadataStore } from 'vue-fastedgy'
import { computed, onMounted } from 'vue'

const metadataStore = useMetadataStore()

const userFields = computed(() => {
  const metadata = metadataStore.getMetadata('User')
  return metadata?.fields || {}
})

onMounted(async () => {
  await metadataStore.getMetadatas()
})
</script>

Validation Helper

Build validation rules from metadata:

import { useMetadataStore } from 'vue-fastedgy'

const metadataStore = useMetadataStore()

const validateField = async (modelName, fieldName, value) => {
  const metadata = await metadataStore.getMetadata(modelName)
  const field = metadata?.fields?.[fieldName]

  if (!field) return null

  // Required validation
  if (field.required && (!value || value === '')) {
    return `${fieldName} is required`
  }

  // String length validation
  if (field.type === 'string' && field.max_length && value.length > field.max_length) {
    return `${fieldName} must be ${field.max_length} characters or less`
  }

  // Number range validation
  if (field.type === 'integer' || field.type === 'number') {
    const num = Number(value)
    if (field.minimum !== undefined && num < field.minimum) {
      return `${fieldName} must be at least ${field.minimum}`
    }
    if (field.maximum !== undefined && num > field.maximum) {
      return `${fieldName} must be at most ${field.maximum}`
    }
  }

  return null
}

// Usage in component
const errors = reactive({})

const validateUserForm = async (formData) => {
  errors.email = await validateField('User', 'email', formData.email)
  errors.age = await validateField('User', 'age', formData.age)

  // Remove null errors
  Object.keys(errors).forEach(key => {
    if (errors[key] === null) {
      delete errors[key]
    }
  })

  return Object.keys(errors).length === 0
}

Loading States

Handle loading and error states properly:

<template>
  <div>
    <div v-if="metadataStore.loading">
      Loading metadata...
    </div>

    <div v-else-if="metadataStore.error">
      Error loading metadata: {{ metadataStore.error.message }}
      <button @click="retry">Retry</button>
    </div>

    <div v-else-if="metadata">
      <h3>{{ modelName }} Fields</h3>
      <div v-for="(field, name) in metadata.fields" :key="name">
        {{ name }}: {{ field.type }}
      </div>
    </div>

    <div v-else>
      No metadata available
    </div>
  </div>
</template>

<script setup>
import { useMetadataStore } from 'vue-fastedgy'
import { computed, onMounted } from 'vue'

const props = defineProps(['modelName'])
const metadataStore = useMetadataStore()

const metadata = computed(() =>
  metadataStore.getMetadata(props.modelName)
)

const retry = async () => {
  await metadataStore.fetchMetadatas()
}

onMounted(async () => {
  await metadataStore.getMetadatas()
})
</script>

Model Discovery

List all available models:

<template>
  <div>
    <h3>Available Models</h3>
    <ul>
      <li v-for="modelName in availableModels" :key="modelName">
        <router-link :to="`/models/${modelName}`">
          {{ modelName }}
        </router-link>
      </li>
    </ul>
  </div>
</template>

<script setup>
import { useMetadataStore } from 'vue-fastedgy'
import { computed, onMounted } from 'vue'

const metadataStore = useMetadataStore()

const availableModels = computed(() => {
  const metadata = metadataStore.getMetadatas()
  return metadata ? Object.keys(metadata) : []
})

onMounted(async () => {
  await metadataStore.getMetadatas()
})
</script>

Conditional Field Display

Show/hide fields based on metadata:

<template>
  <form>
    <div
      v-for="(field, name) in visibleFields"
      :key="name"
      class="form-field"
    >
      <label>
        {{ field.label || name }}
        <span v-if="field.required">*</span>
      </label>

      <input
        v-if="field.type === 'string'"
        :type="getInputType(field)"
        :maxlength="field.max_length"
        :required="field.required"
      />

      <input
        v-else-if="field.type === 'integer'"
        type="number"
        :min="field.minimum"
        :max="field.maximum"
        :required="field.required"
      />

      <select
        v-else-if="field.choices"
        :required="field.required"
      >
        <option value="">Choose...</option>
        <option
          v-for="choice in field.choices"
          :key="choice.value"
          :value="choice.value"
        >
          {{ choice.display_name }}
        </option>
      </select>
    </div>
  </form>
</template>

<script setup>
import { useMetadataStore } from 'vue-fastedgy'
import { computed, onMounted } from 'vue'

const props = defineProps(['modelName', 'hideFields'])

const metadataStore = useMetadataStore()

const visibleFields = computed(() => {
  const metadata = metadataStore.getMetadata(props.modelName)
  if (!metadata?.fields) return {}

  const fields = { ...metadata.fields }

  // Hide specified fields
  if (props.hideFields) {
    props.hideFields.forEach(fieldName => {
      delete fields[fieldName]
    })
  }

  return fields
})

const getInputType = (field) => {
  if (field.format === 'email') return 'email'
  if (field.format === 'password') return 'password'
  if (field.format === 'url') return 'url'
  return 'text'
}

onMounted(async () => {
  await metadataStore.getMetadatas()
})
</script>