Vue/nuxt - How To Access Parents Ref From Child Components
Solution 1:
The short answer is: Don't abuse $ref like that. Ultimately, it will just lead to anti-patterns wrapped in anti-patterns.
More detailed answer related to the exact task you're trying to accomplish: I've tackled this exact same thing (global, promise based confirmation dialogs) on a few Vue projects now, and this is what has worked really well so far:
- Setup the confirm dialog as its own stand-alone 'module' so you can add it to main.js with two lines:
importConfirmModulefrom'./modules/confirm';
Vue.use(ConfirmModule);
(side point: there's a couple other of these 'global modular components' like alerts, etc...)
- Use a JS file to orchestrate the setup process, the promise management, and the component instantiation. For example:
import vuetify from'@/plugins/vuetify';
import confirmDialog from'./confirm-dialog.vue';
exportdefault {
install(Vue) {
const$confirm = (title, text, options) => {
const promise = newPromise((resolve, reject) => {
try {
let dlg = true;
const props = {
title, text, options, dlg,
};
const on = { };
const comp = newVue({
vuetify,
render: (h) =>h(confirmDialog, { props, on }),
});
on.confirmed = (val) => {
dlg = false;
resolve(val);
window.setTimeout(() => comp.$destroy(), 100);
};
comp.$mount();
document.getElementById('app').appendChild(comp.$el);
} catch (err) {
reject(err);
}
});
return promise;
};
Vue.prototype.$confirm = $confirm;
},
};
Mount it to the Vue.prototype, this way you can use it from any component in your app simply by calling:
this.$confirm(...)
When you build your Vue component (confirm-dialog.vue) you need only one-way bind your props for title, text and options, one-way bind the dlg prop to the dialog, or else setup a two-way binding through a computed property with a getter and setter... either way...
emit a "confirmed" event with
true
if the user confirms. So, from the confirm-dialog.vue component:this.$emit('confirmed', true);
If they dismiss the dialog, or click 'no' then emit false so that the promise doesn't hang around:
this.$emit('confirmed', false);
Now, from any component, you can use it like so:
methods: {
confirmTheThing() {
this.$confirm('Do the thing', 'Are you really sure?', { color: 'red' })
.then(confirmed => {
if (confirmed) {
console.log('Well OK then!');
} else {
console.log('Eh, maybe next time...');
}
});
}
}
Solution 2:
In nuxt project's default layout, put the component, say Confirm
like below:
<v-main><v-containerfluid><nuxt /><Confirmref="confirm" /></v-container></v-main>
Then the component's open
method can be used as below:
const confirmed = awaitthis.$root.$children[2].$refs.confirm.open(...)
if (!confirmed) {
return// user cancelled, stop here
}
// user confirmed, proceed
Tricky thing was how to find the component contained in the layout. $root.$children[2]
part seemed working in development phase but once deployed, it had to be $root.$children[1]
.
So I ended up doing below:
// assume default.vue has data called 'COPYRIGHT_TEXT'const child = this.$root.$children.find(x => x.COPYRIGHT_TEXT)
if (child) {
const confirm = child.$refs.confirmif (confirm) {
returnawait confirm.open(...)
}
}
returnfalse
Background: my project is in production but came up with a new requirement to get confirmation before any save in particular mode. I could use one-way event bus
, but to do that, the rest of codes after confirmation would have to be refactored to be passed as a callback in every saving place.
Post a Comment for "Vue/nuxt - How To Access Parents Ref From Child Components"