How to binding the value in directive - vuejs2

I want to create a directive for auto add the icon inside the button.
When user click on it.
But How to pass the loading value(it's boolean data) from the parent object?
Vue.directive('loading', {
bind: function (el, binding, vnode) {
if (binding.value) {
var loadingElement = Vue.extend({
props:['isLoading'],
template: '<span class="loading" v-if="isLoading"><fa-icon :icon="[\'fab\', \'facebook-f\']"></fa-icon></span>',
});
var loadingComponent = new loadingElement({
propsData: {
isLoading: binding.value
}
});
loadingComponent.$mount();
el.appendChild(loadingComponent.$el);
}
},
update: function (el, binding, vnode) {
el.disabled = binding.value;
}
});
I want isLoading: binding.value data is bind from the parent.

Related

Vue 3 - How to execute a function on binging instance in custom directive

Im creating a custom directive as follows in main.ts .
let handleOutsideClick: any;
app.directive("closable", {
mounted: (el, binding, vnode) => {
handleOutsideClick = (e: any) => {
e.stopPropagation();
const payload = binding.value;
console.log(`instance: ${Object.getOwnPropertyNames(binding.instance)}`);
};
document.addEventListener("click", handleOutsideClick);
},
unmounted: (el) => {
document.removeEventListener("click", handleOutsideClick);
},
});
Inside the event handler i want to make a call to a function on the component that triggered this directive.
With Vue 2 you could do it with vnode.context'myfunction' but this does not seem to work with binding.instance.
How can i call the function using the binding instance?
Passing the function to be called as the binding's value and then calling it seems to work:
if (typeof binding.value === 'function') {
binding.value()
}
Working example:
const { createApp } = Vue;
const app = createApp({
setup() {
return { test: () => console.log('here') }
}
})
app.component('demo', {
template: `<div>test</div>`
})
let handleOutsideClick;
app.directive("closable", {
mounted: (el, binding, vnode) => {
handleOutsideClick = (e) => {
e.stopPropagation();
const payload = binding.value;
console.log(`instance: ${Object.getOwnPropertyNames(binding.instance)}`);
if (typeof binding.value === 'function') {
binding.value()
}
};
document.addEventListener("click", handleOutsideClick);
},
beforeUnmount: (el) => {
document.removeEventListener("click", handleOutsideClick);
},
});
app.mount('#app')
<script src="https://unpkg.com/vue#3.2.41/dist/vue.global.prod.js"></script>
<div id="app">
<demo v-closable="test"></demo>
</div>
Notes:
vue internal method names change based on environment. For example, if you remove .prod from the vue link in the example above, you'll get more data out of Object.getOwnPropertyNames(binding.instance).
If your app's business logic relies on vue internals method naming:
  a) you're doing it wrong™;
  b) it won't work in production
if the above is not helpful, please provide more details on your specific use-case via a runnable minimal, reproducible example.
If you need a multi-file node-like online editor, note codesandbox.io allows importing local projects using their CLI utility.

How to run vue directive function?

I have this vue 2 cli directive
directives: {
swipe: {
inserted: function runme(el) {
alert(el);
},
},
},
How can I run runme(obj) from methods or another directive
You could factor out the common code into its own standalone method that could be called from anywhere:
function swipeInserted(el, binding, vnode) {
alert(el)
}
export default {
directives: {
swipe: {
inserted: swipeInserted,
},
other: {
inserted(el, binding, vnode) {
swipeInserted(el, binding, vnode)
// other code specific to this directive...
}
}
},
methods: {
runInserted() {
const el = {/*...*/}
const binding = {/*...*/}
const vnode = {/*...*/}
swipeInserted(el, binding, vnode)
}
}
}

How to pass a reactive prop to child in Vuejs

I creating a reusable modal in which I want to pass the prop :loading="loading". But as of now the loading property initialized in data is not reactive. How can I update loading in the parent so it is reactive inside the child component ?
Parent component template:
<child_component :loading="loading"></child_component>
Parent component script:
data() {
return {
loading: false
}
},
onDelete() {
this.loading = true;
setTimeout(function(){ alert("Hello"); }, 3000);
this.loading = false;
},
child :
<v-btn icon
:loading="loading"
<v-icon>{{icon}}</v-icon>
</v-btn>
...
props: { disabled: { Boolean, default: false } }
Move this.loading = false; inside setTimeout and use arrow function as i have used below else you will not get reference to this.
onDelete() {
this.loading = true;
setTimeout(() => { this.loading = false; }, 3000);
}

VueJS Extends Methods and Data

I would like to extend methods. Example:
Vue.extend({
data: function () {
return {
fetcData: 'Test',
}
},
methods: function(){
return {
modal: function(){ alert('Modal') },
}
}
});
Vue.extend({
....
});
I use multiple extends.
// VueJS Instance
new Vue({
el: 'html',
data: {
effect: true
},
methods: {
xhrGet: function () {
alert(this.fetcData); // Undefined
this.modal(); // Undefined
},
xhrPost: function (event) {
alert('xhrPost')
}
}
});
Error Code:
this.fetchData is undefined.
this.modal is not a function
Vue.extend returns a new Vue component definition that can be later on instantiated using new keyword, it doesn't change the global Vue object. So if you want to create a component hierarchy try:
var BaseComponent = Vue.extend({
methods: {
foo: function() { console.log('foo') }
}
})
var MyComponent = BaseComponent.extend({
methods: {
bar: function() {
this.foo()
console.log('bar')
}
}
})
let myComponentInstance = new MyComponent()
Check out that fiddle for a live example.

VueJS - how component gets global data item?

I have code like this :
Vue.component("sample", {
inherit: true,
template: "#sample",
props: {
active : "active",
...
},
methods: {
forceChangeActive: function(){
var activeItem = this.$parent._data.active;
var modalSetup = this.$parent._data.showModal;
console.log("1.before function", this.$parent._data);
this.$parent.$options.methods.baseAction(activeItem, modalSetup);
console.log("2.before function", this.$parent._data);
});
}
});
new Vue({
el: "#app",
data: {
active: 0,
showModal: false,
...
},
methods: {
baseAction: function(activeItem, modalSetup){
console.log("3.modal", modalSetup, "activeItem": activeItem);
modalSetup = true;
activeItem = 2;
console.log("4.modal", modalSetup, "activeItem": activeItem);
}
}
});
There are active and showModal data variables in new Vue. Now I'm getting undefined for both if I use this.active or this.showModal.
And console output is:
before function Object { active=0, showModal=false }
modal false, activeItem 0
modal true, activeItem 2
before function Object { active=0, showModal=false }
How I can change variable`s values in new Vue or in component?
inherit:true is deprecated.
You need to explicitly pass active and showModal to the child component using properties. You can use .sync to make sure they are shared back to the parent as well:
<sample :active.sync="active" :show-modal.sync="showModal"></sample>