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

10,555

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.

Share:
10,555
chamberlainpi
Author by

chamberlainpi

Flash / AS3 / Starling veteran, currently self-employed working with various web development tools and technologies such as Haxe, Brunch.io, NPM, NodeJS, CreateJS, PixiJS, HTML5, jQuery, Ajax, JavaScript, CSS, LESS, PHP, XML, JSON. My preferred IDEs are FlashDevelop (for AS3 and Haxe dev) and IntelliJ Ultimate / Webstorm. I also have some experience with Wordpress and run a blog with tutorials covering some of the above technologies.

Updated on June 09, 2022

Comments

  • chamberlainpi
    chamberlainpi almost 2 years

    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:

    • Manually call it like props: ["componentName", ...] and;
    • Refer to it in the template as <form class='{{componentName}}' ...>

    Is this the only feasible way?

    Using VueJS version: 1.0.17

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