chamberlainpi
chamberlainpi

Reputation: 5241

How do you refer to a VueJS component's name within the template's raw HTML / x-referenced ID element?

I'm essentially trying to add a CSS class to my VueJS components based on the component-name it's registered under (to give all those specific types of components the same style).

For example:

Vue.component('dragdropfile', {
    // This refers to a unique template element (see HTML below)
    template: "#dragdropfile-tmp",
    props: ['action']
});

And in the Vue component template:

<template id="dragdropfile-tmp">
    <form action="{{action}}" method="post" enctype="multipart/form-data">
        <div class="fallback">
            <input name="file" type="file" multiple />
        </div>
        <div class="dz-message" data-dz-message>
            <div class="dz-default">
                <!--
                    According to VueJS docs / forums, "slot" gets replaced by any innerHTML
                    passed from the incoming component usage.
                -->
                <slot></slot> 
            </div>
        </div>
    </form>
</template>

And finally, how it's used in the "index.html" page is like this:

<dragdropfile id="someDragDropFiles" action="/upload-please">
  Do you have files to upload?<br/>
  <b>Drop it here!</b>
</dragdropfile>

Now, although I could put in the component-name manually for each component HTML templates, I want to automate this.

Are there any special built-in {{binding}} names that Vue uses internally so that I can inject the component-name into the resulting component on the page?

To result something like so:

<form class="dragdropfile" id="someDragDropFiles" action="/upload-please" ... >
...
</form>

Or do I simply need to pass it myself as a new component property? As in:

Is this the only feasible way?

Using VueJS version: 1.0.17

(https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.17/vue.js)

Upvotes: 7

Views: 21406

Answers (1)

chamberlainpi
chamberlainpi

Reputation: 5241

Solution #1

After a few minutes of inspecting what the object holds using the create: function() { console.log(this); } in the Vue.component(...) registration call, I found the name in it's this.$options.name property.

In other words:

<form class="{{this.$options.name}}" ...> ... </form>

Or even shorter:

<form class="{{$options.name}}" ...> ... </form>

Come to think of it, it's still a bit of manual work to enter on each component templates, but there's probably a way to auto-append the class via the created method.


Solution #2

This is the automated approach I was looking for!

Here it goes, basically I made a wrapper function to call whenever I need to register new components, which internally calls the usual Vue.component(...) method.

NOTE: This example depends on jQuery to add the class and underscore.js for object merging via _.assign, but could probably be replaced by a direct *.classList.addClass() call instead. These are just the helper methods I'm familiar with, use what you like! :)

makeVueComponent(name, params)

/*
 * Creates a Vue Component with a standardized template ID name (ie: #tagname-tmp)
 * combined with given params.
 */
function makeVueComponent(name, params) {
    //Ensure params is assigned something:
    params = params || {};

    //Backup a reference of an existing *.created() method, or just an empty function
    var onCreated = params.created || function(){};

    /*
        Delete the original `created` method so the `_.assign()` call near the end
        doesn't accidentally merge and overwrite our defaultParams.created() method.
     */
    delete params.created; 

    var defaultParams = {
        //Standardized template components to expect a '-tmp' suffix
        // (this gets auto-generated by my NodeJS/Express routing)
        template: "#"+name+"-tmp",

        // This part auto-adds a class name matching the registered component-name
        created: function() {
            var $el = $(this.$options.el);
            $el.addClass(this.$options.name);

            //Then forward this to any potential custom 'created' methods we had in 'params':
            onCreated.apply(this, arguments);
        }
    };

    //Merge default params with given custom params:
    params = _.assign(defaultParams, params);

    Vue.component(name, params);
}

And then just use it like so:

//Register your Vue Components:
makeVueComponent("dragdropfile", {props:['action']});

You can then leave out those {{$options.name}} from your actual component templates that I mentioned in Solution 1.

Upvotes: 18

Related Questions