Use your component

Now that your component is configured and ready to use, you have two possibilities to use it:

  1. Import your component manually in an existing Vue app,
  2. Use the VueBuilder provided by Banquette.

VueBuilder

The VueBuilder is a utility class that stores every Vue component and directive created using the @Component or @Directive decorator (assuming the group option is not set to null).

NOTE

Both @Component and @Directive have a group option that controls in which group(s) they will be registered in the builder. You can set it to null so they are not registered at all.

Doing this allows you to do this:

import { VueBuilder } from '@banquette/vue-typescript';

// Here we import what we need.
import '@banquette/vue-ui/button';
import '@banquette/vue-ui/dialog';

// Then we create an app. 
// The component that have been imported are automatically added to the app.
VueBuilder.CreateAppAndMount('#app');

Groups

You can separate your components and directives in different group to better organize your dependencies:

import { Component, VueBuilder } from "@banquette/vue-typescript";

@Component({
    name: 'form-text',
    group: 'form'
})
class FormText {
    [...]
}

// Internally, @Component will call the VueBuilder like this:
VueBuilder.RegisterComponent('form-text', FormText, 'form');

WARNING

You must define a name for your component for it to be registered in the VueBuilder. Otherwise it will be ignored.


Usage

Here are some usage examples of the builder:

// Create an app that will include all components and directives registered in the "default" group.
VueBuilder.CreateApp();

// Same for the "form" group.
VueBuilder.CreateApp('form');

// Or with multiple groups.
VueBuilder.CreateApp(['form', 'modals']);

// Or to use all known components and directives.
VueBuilder.CreateApp('*');

// With options (the second argument is the object you would normally pass to "createApp()").
VueBuilder.CreateApp('form', {
    compilerOptions: {
        comment: true
    }
});

// Same as `VueBuilder.CreateApp(...).mount('#app')`.
VueBuilder.CreateAppAndMount('#app', 'form', {
    compilerOptions: {
        delimiters: ['${', '}']
    }
});

You can also create the app yourself and apply the configuration of the builder afterwards:

import { createApp } from 'vue';
import { VueBuilder } from "@banquette/vue-typescript";

// Create an app.
const app = createApp({...});

// Will merge the global options and register the corresponding components and directives.
VueBuilder.ApplyToExistingApp(app);

Global options

VueBuilder also offers a SetVueOption method allowing you to set an option globally that will then be merged with all apps created with it:

// Will change the delimiters of all apps created using the builder.
VueBuilder.SetVueOptions({compilerOptions: {
    delimiters: ['${', '}']
});

// You can call it multiple times, options will be merged
VueBuilder.SetVueOptions({compilerOptions: {
    comment: true
});

// Will result:
// {
//    compilerOptions: {
//       delimiters: ['${', '}'],
//       comment: true
//    }
// }

TIP

Options passed to the CreateApp or CreateAppAndMount have the priority to these defined globally.

Manual use

You can use the component constructor directly in your Vue instance:

import { createApp } from 'vue';
import { ButtonComponent } from '@banquette/vue-ui/button';

// Here the component name will be "button-component".
createApp({
    components: {ButtonComponent}
}).mount('#app');

// If you want to rename it.
createApp({
    components: {'my-button': ButtonComponent}
}).mount('#app')

TIP

If you register your components or directives this way, the name option of their decorator is not used, so you must name them yourself or do with the default name Vue will give them.

WARNING

BUT BEWARE with directives! You can't register them directly from their constructor like you do with components.

To illustrate, please take the following example:

import { createApp } from 'vue';
import { Button } from './components/button'; // A custom component
import { DemoDirective } from './directives/demo'; // A custom directive

const app = createApp({
    components: {Button}, // Will work
    directives: {DemoDirective} // Will NOT work
});

This is because internally, when Vue sees that a directive is a function, it wraps it into an object defining a mounted and updated callback. This prevents the use of a constructor as a directive definition.

So if you need to create your app manually, you have to use VueBuilder to get the definition of the directive:

import { createApp } from 'vue';
import { Component, VueBuilder } from "@banquette/vue-typescript";
import { Button } from './components/button'; // A custom component
import { DemoDirective } from './directives/demo'; // A custom directive

const app = createApp({
    components: {Button}, // OK
    directives: {'demo': VueBuilder.GetDirectiveDefinition(DemoDirective).directive} // OK
});

Accessing Vue variables

As you can see in all previous examples, components don't have to inherit from any base class to work. This is by design, to make the integration as easy as possible.

But this also prevents you to access Vue specific properties like $attrs, $slots, etc.

If you need these, you have to inherit from the Vue base class of @banquette/vue-typescript:

import { Component, Vue } from '@banquette/vue-typescript';

@Component()
export class MyComponent extends Vue {

    public mounted(): void {
        // Because you inherit from "Vue", `vue-typescript` will automatically
        // make public attributes from Vue available in the component.
        console.log(this.$slots);
    }
}

This class also comes with a few useful utilities:

import { Component, Vue } from '@banquette/vue-typescript';

@Component()
export class MyComponent extends Vue {
    public mounted(): void {
        // Test if a slot named "title" is defined.
        this.hasSlot('title');
        
        // Test if a slot named "title" exists and has content in it.
        // WARNING: this renders the slot.
        this.hasNonEmptySlot('title');
        
        // Test if a slot exists, render it if so and extract is text content.
        // Returns `null` is the slot doesn't exist.
        this.getSlotTextContent('title');
        
        // Try to get a reference on a specific parent component.
        // This method will return the actual TypeScript instance of the component, if found.
        this.getParent(AlertComponent);
        
        // Can also get it by its name.
        // WARNING: the name defined in the @Component() decorator is used here.
        // If you renamed the component on use, you must still reference it with the "`VueTypescript` name".
        this.getParent('bt-form');
        
        // Test if component is found in the parent hierarchy.
        // Same as above for the name.
        this.hasParent('bt-button');
        
        // Gets the whole `VueTypescript` metadata object associated with the current component.
        this.getMetadata();
    }
}