Trying to create a plugin with global mixin which would automatically look for specific element and change its attributes.
export default {
// called by Vue.use(ThisPlugin)
install(Vue, options) {
Vue.mixin({
created() {
console.log($("div").length); // get rid of jQuery and global content
},
});
},
};
As this is called on every vue component I want to limit content mixin accesses with similar like el parameter in directives or like components have element querySelector (this.$el.querySelector("div")) and to replace jquery usage. Is my approach correct and how would I access only components contents in a mixin?
Want to skip directives as those would need to modify tons of existing components, rather introduce a plugin for a component.
Is there a built-in way of determining if the component has mounted in Vue?
I know I could just do mounted() { this.hasMounted = true; } but I would like to know if there already was a property for this.
Found that _isMounted is getting set by Vue.
you can use it to search for your component if it mounted
this.$options.components[findComponentName]
or using v-ref like this one <comp v-ref:comp-name></comp>
and you can use it from the $refs object if(this.$refs.compName)
Suppose I have a prop named message which I want to access from the script section of a .vue file.
I know that it can be accessed using this.$props.message and this.message from the data function.
Which is the preferred way to access props from different lifecycle hooks (created, mounted, etc), and from computed getters, and methods?
Component properties as well as passed in props should always be referenced to by this.propName, because you shouldn't assign a component property with the same name as a passed in prop. In this case Vue will respond with an error.
As Aer0 said, they shouldn't have the same names:
props: ['propMessage'],
data() {
return {
message: ''
};
},
created() {
console.log(this.propMessage);
console.log(this.message);
}
I am trying to get all of the Vue components data properties from within a mixin that I am using for my plugin.
I have got the plugin registering correctly and the mixin is actively working.
I have added a lifecycle hook from within the Vue.mixin which runs on the created() event.
I am trying to loop through all of the components data and assign it to a property within my plugin, this is because I want to manipulate all of the data in every single component in my application.
I have tried to do the following:
Vue.mixin({
created() {
console.log(this.$options.data());
}
})
But i get the result saying that data is not a function. However, calling within the () on the end of the data logs a function out which I can see the data within.
Does anyone have any ideas?
Thank you
Try to use this.$data instead:
Vue.mixin({
created() {
console.log(this.$data);
}
});
>> DEMO on CodeSandbox
Following this tutorial, I'm trying to programmatically create instances of a component on my page.
The main snippet is this:
import Button from 'Button.vue'
import Vue from 'vue'
var ComponentClass = Vue.extend(Button)
var instance = new ComponentClass()
instance.$mount()
this.$refs.container.appendChild(instance.$el)
However I get two errors:
The component I'm trying to instantiate contains references to the store, and these don't work: "TypeError: Cannot read property 'state' of undefined".
For the last line of the snippet (this.$refs.container.appendChild(instance.$el)) I get this error: "Uncaught TypeError: Cannot read property 'container' of undefined"
I'm really not sure how to troubleshoot this, if anyone strong in Vue.js could give me some hint as to why I'm getting these errors and to solve them that would be terrific.
1) Since you're manually instantiating that component and it doesn't belong to your main app's component tree, the store won't be automatically injected into it from your root component. You'll have to manually provide the store to the constructor when you instantiate the component ..
import ProjectRow from "./ProjectRow.vue";
import Vue from "vue";
import store from "../store";
let ProjectRowClass = Vue.extend(ProjectRow);
let ProjectRowInstance = new ProjectRowClass({ store });
2) In a Vue Single File Component (SFC), outside of the default export this doesn't refer to the Vue instance, so you don't have access to $refs or any other Vue instance property/method. To gain access to the Vue instance you'll need to move this line this.$refs.container.appendChild(instance.$el) somewhere inside the default export, for example in the mounted hook or inside one of your methods.
See this CodeSandbox for an example of how you may go about this.
This is another way to instantiate a component in Vue.js, you can use two different root elements.
// Instantiate you main app
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
//
// Then instantiate your component dynamically
//
// Create a component or import it.
const Hello = {
props: ['text'],
template: '<div class="hello">{{ text }}</div>',
};
// Create a componentClass by Vue.
const HelloCtor = Vue.extend(Hello);
// Use componentClass to instantiate your component.
const vm = new HelloCtor({
propsData: {
text: 'HI :)'
}
})
// then mount it to an element.
.$mount('#mount');
It works by assigning "this" to the property "parent". By setting the parent you also have access to the $store in the new instance. (Provided that "this" is another Vue instance/Component and already has access to the store, of course)
new (Vue.extend(YourNewComponent))({
parent: this,
propsData: {
whatever: 'some value',
},
}).$mount(el.querySelector('.some-id'))
If you don't need the reference to the parent, you can just leave "parent: this," out.
Important note: When mounting many (like 500+) items on the page this way you will get a huge performance hit. It is better to only give the new Component the necessary stuff via props instead of giving it the entire "this" object.
I went down this path, following all the examples above, and even this one: https://css-tricks.com/creating-vue-js-component-instances-programmatically/
While I got far, and it works (I made a lot of components this way), at least for my case, it came with drawbacks. For example I'm using Vuetify at the same time, and the dynamically added components didn't belong to the outer form, which meant that while local (per component) validation worked, the form didn't receive the overall status. Another thing that did not work was to disable the form. With more work, passing the form as parent property, some of that got working, but what about removing components. That didn't go well. While they were invisible, they were not really removed (memory leak).
So I changed to use render functions. It is actually much easier, well documented (both Vue 2 and Vue 3), and everything just works. I also had good help from this project: https://koumoul-dev.github.io/vuetify-jsonschema-form/latest/
Basically, to add a function dynamically, just implement the render() function instead of using a template. Works a bit like React. You can implement any logic in here to choose the tag, the options, everything. Just return that, and Vue will build the shadow-DOM and keep the real DOM up to date.
The methods in here seems to manipulate the DOM directly, which I'm glad I no longer have to do.