Custom Komponents
Create a beautiful komposition of chained Komponents...

Custom komponents

If you build a cool Komponent, please let us know about it. We may add it to the package and allow everyone in the community to use it!

You may extend the komponents your app can use for different reasons: avoid code repetition, creating combos of komponents that enhance their behavior, or simply building a totally new unexisting Field...

Creating the PHP class

First, you need to extend the relevant class. If you remember, there are 4 types of Komponents

  • A Field has user input and does AJAX - extends `Kompo\Komponents\Field`.
  • A Layout has child Komponents - extends `Kompo\Komponents\Layout`.
  • A Trigger can perform AJAX requests - extends `Kompo\Komponents\Trigger`.
  • A Block is purely decorative - extends `Kompo\Komponents\Block`.

We first need to link the PHP class to the Vue component in the $vueComponent prpperty. Kompo will look for a `Vl{ComponentName}.vue` and will load the PHP class public properties into it.

Data attribute

A convenient method to pass information and configurations to the Front-End component is the `->data()` method which accepts an associative array as argument. Let us take a look at extending a Field for example.

use Kompo\Komponents\Field;

class CustomComponent extends Field
{ 
   //Kompo will look for a VlCustomKomponent.vue
   public $vueComponent = 'CustomKomponent';

   //Pass some information and configurations
   public function vlInitialize($label)
   {
      parent::vlInitialize($label);

      $this->data([
         'defaultWidth' => '60px'
      ]);
   }

   /**
    * Fields have many useful methods to handle the transformation of user inputs.
    */
   public function getValueFromModel($model, $name)
   {
      //how to retrieve the value from the DB.
   }

   public function prepareForFront($komposer)
   {
      //transform the value before it is displayed in the Form
   }

   public function setAttributeFromRequest($requestName, $name, $model, $key = null)
   {
      //Processes and returns the request value when the field is an attribute.
   }

   public function setRelationFromRequest($requestName, $name, $model, $key = null)
   {
      //Processes and returns the request value when the field is a relation.
   }
}
Take a look at the Komponents in the src/Usable folder to better understand how each were built. This will help you a lot while building your own custom komponent.

Creating the Vue component

You should create a `VlCustomComponent.vue` file with the code below. You may add attributes and event bindings by overriding the `$_attributes` and `$_events` methods from the mixin. Let us continue with our example of a Field

<template>
    <vl-form-field v-bind="$_wrapperAttributes">
        <input
            v-model="component.value"
            class="vlFormControl"
            v-bind="$_attributes"
            v-on="$_events"
        />
    </vl-form-field>
</template>

<script>
import Field from 'vue-kompo/js/form/mixins/Field'
export default {
   mixins: [Field],
   computed: {
      $_attributes() {
        return {
          ...this.$_defaultFieldAttributes,
          width: this.$_data('defaultWidth') //accessing info stored in data
        }
      },
      $_events() {
        return {
          ...this.$_defaultFieldEvents,
          mouseup: this.someMethod
        }
      }
   },
   methods: {
      someMethod(){
        console.log('mouse up')
      }
   }
}
</script>
A Field may have a <vl-form-field wrapper that provides a label, errors, comment and help text.

Layout Vue component

A layout is easier to write in Vue. There is no wrapper and you may directly start placing its' child komponents with the `komponents` data attribute. For example:

<template>
    <div>
        <template v-for="(child,index) in komponents">
            <component 
                :width="$_data('defaultWidth')" 
                :is="child.vueComponent"
                />
        </template>
    </div>
</template>

<script>
import Layout from 'vue-kompo/js/form/mixins/Layout'

export default {
    mixins: [Layout],
    computed:{
      //do your thing
    },
    methods:{
      //do your thing
    }
}
</script>