Reputation: 5241
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:
props: ["componentName", ...]
and;<form class='{{componentName}}' ...>
Is this the only feasible way?
(https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.17/vue.js)
Upvotes: 7
Views: 21406
Reputation: 5241
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.
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! :)
/*
* 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