Clicking non Vuetify button does not update data in v-data-table - vue.js

In the code pen I have two buttons. One Vuetify and the other not. both should call the updateData() function but only the Vuetify component is able to run it succesfully. How can I call the method defined in the component from outside the app div?
https://codepen.io/entropy283/pen/rNxMXGX?editors=1010

You are trying to trigger updateData method, which is accessible only inside the HTML element that Vue is mounted on. I assume you are mounting Vue to the element with id="app".
You have to put the button inside the <div id="app">:
<div id="app">
<button #click="updateData()">Button</button>
...
Or, if you don't need to access any Vue properties, you can just create a function inside script and trigger it with onclick event. Keep in mind that #click is also not accessible outside of Vue:
<button onclick="updateData()">Button</button>
<div id="app">
...
<script>
function updateData() {
console.log('test')
}
</script>

Related

Add event on slot

I'm trying to implement generic modal component with Vue 3.
And I want to close modal window on click outside the modal's content.
So I added 'close' event on modalWrapper and 'contentClick' to prevent closing (bubbling) when content is clicked:
contentClick(event:Event){
event.stopPropagation();
}
Modal:
<template>
<teleport to="body">
<div class="modal-window" v-on:click="close" v-show="isOpened">
<slot class="modal-window__content" v-on:click="contentClick($event)"></slot>
</div>
</teleport>
</template>
The problem is that contentClick(event:Event) is not fired for some reason. I can wrap slot into another div and put contentClick event on it, but not sure that it's a good solution

Vue component within code block, Vue attempting to render the template

i'm trying to display example Vue component's within my documentation, however Vue is also recognizing the template within my Vue component.
vehicle-documents is not a registered component, and is also put into the following code:
Vue.config.ignoredElements = ['slide', 'slider', 'vehicle-documents'];
So Vue is ignoring the component itself:
If you want the modal make sure you add the click event and call the `open` function, and pass the `document` into this function call, as seen below.
```html
<vehicle-documents class="app" vehicle-id="">
<template v-slot:default="slotProps">
<button #click="slotProps.open(slotProps.document)">
{{ slotProps.document.name }}
</button>
</template>
</vehicle-documents>
```
How can I make Vue ignore the template block? I need Vue on this page, so it's not a simple case of just removing Vue.
Try this, add v-pre and type="text/x-template"
<vehicle-documents class="app" vehicle-id="">
<template v-pre type="text/x-template">
<button #click="slotProps.open(slotProps.document)">
{{ slotProps.document.name }}
</button>
</template>
</vehicle-documents>

Single file component - re mount component on changing a value from navbar

This is the structure of my vuejs application.
<template>
<div class="page-body-wrapper">
<Sidebar/>
<div class="main-panel">
<Header/>
<div class="content-wrapper">
<router-view></router-view>
</div>
</div>
</div>
</template>
<script>
import Header from '../header/header';
import Sidebar from '../sidebar/sidebar';
export default {
name: 'Layout',
components: {
Header,
Sidebar
}
}
</script>
In all the routes that are rendered inside <router-view>, i am calling various functions and api calls based on a store variable 'myValue'. And, I have a dropdown in my <Header/> component ( which is common for all routes). Whenever I select a value from the dropdown in header, the store variable 'myValue' changes. Now, I need to remount whatever component is rendered inside <router-view> whenever the store variable 'myValue' changes. Using watch will be a last option since I will have to do the same in a number of components. I cannot use computed, since I have to fetch all data in either 'created' or 'mounted' hook. Is there any option to remount the entire <router-view> when a store variable changes? Note: I am using vuex for state management.
Just pass a key to <router-view :key="myValue"></router-view>, or in your case <router-view :key="$store.state.myValue"></router-view>.
Also check out this answer.

Vue mounted jquery code not working on DOM re-render

I'm trying to use jqueryui datapicker with vue. The input for the datepicker is inside a template if-else condition.
The datepicker works just fine initially but after flipping back and forth using the template if-else it stops working.
It seems the jquery code is no longer mounted after a DOM re-render.
<template v-if="...">
<input name="startdate" id="startdate" v-model="date" type="text">
</template>
<template v-else>
<div>Some other display</div>
</template>
mounted: function() {
$('#startdate').datepicker({
onSelect:function(selectedDate, datePicker) {
this.date = selectedDate;
}
});
I placed the jquery code instead inside "updated" and it works now, but this code gets called every single time there is a DOM change.
I'm wondering it there is a better way to accomplish this?
updated: function () {
this.$nextTick(function () {
....
....
You might use v-show instead. This will only toggle the display value of the element, not remove from or add to the DOM, so any event handlers attached won't be affected. From the Vue docs: https://v2.vuejs.org/v2/guide/conditional.html#v-show
That said, #Imre_G is probably right about finding a Vue datepicker to use.
Try this: use your component with mouted() hook and just add to your component the v-once directive. Like this: <input name="start date" ... v-once>
But, as mentioned in Imre_G comment, consider to use some premaded Vue datepicker component. It is far more better idea as mixing Vue with jQuery.

vue.js Mount component to app root

I have a modal.vue component as follows:
<template>
<transition name="modal-transition">
<div class="modal-body" v-if="displayed">
<div class="modal-overlay" #click="displayed = false"></div>
<div class="modal-content">
<slot/>
</div>
</div>
</transition>
</template>
How do I mount this component to the applications root element rather than in place?
For crude inaccurate example:
<body>
<div id="app">
<div class="header"></div>
<div class="nav"></div>
<div class="stage">
<div class="sub-nav"></div>
<div class="content">
<modal :display.sync="display">MY MODAL</modal> <-- Don't mount here...
</div>
</div>
<-- Mount here instead...
</div>
</body>
The current issue is that my sites header and navigation is layered on top of my modal and it's darkened full screen overlay instead of layered behind the modal overlay.
Update for Vue 3
There is now a built in feature called teleport which allows mounting parts of your component template to any DOM element.
The example from the OP would look like something like this
<!-- MyModal.vue -->
<template>
<transition name="modal-transition">
<div class="modal-body" v-if="displayed">
<div class="modal-overlay" #click="displayed = false"></div>
<div class="modal-content">
<slot/>
</div>
</div>
</transition>
</template>
<!-- SomeDeeplyNestedComponent.vue -->
<template>
<teleport to="#app">
<!-- Can still receive props from parent -->
<MyModal :my-prop="foo">
<!-- slot content -->
</MyModal>
</teleport>
</template>
Vue 2
Move the elements own self to the element of applications root may be achieved in two ways, Using a portal as a preferred solution or using an append.
Using a Portal (Preferred Method)
PortalVue is a set of two components that allow you to render a
component's template (or a part of it) anywhere in the document - even
outside the part controlled by your Vue App!
https://portal-vue.linusb.org/
Using an Append (Not best practice)
If adding a portal library is too heavy, using an append is allowed but lightly discouraged officially in the VUE docs.
Typically this particular mount position will satisfy a z-index overlay for your own modal or dialog popup that you require to render over the top of the entire app. You can always substitute this.$root.$el in this example for a different element target using standard getElementBy or querySelector functions.
Here the element is being moved not destroyed and re-added, all reactive functionality will remain in tact.
<script>
export default {
name: 'modal',
...
mounted: function() {
this.$root.$el.append(this.$el);
},
destroyed: function() {
this.$el.parentNode.removeChild(this.$el);
}
}
</script>
On mounted the element is moved inside of where the top level VUE app instance is mounted.
On destroyed removes the placeholder DOM comment for the migrated component from the new parent to prevent orphaned duplication each time the component remounts it's self.
VUE officially states not to destroy an element outside of VUE so this is not to be confused with that statement, here the component has already been destroyed.
This DOM comment duplication will typically happen when for example switching views with vue-router as this mechanism mounts and dismounts all components in a router view each time vue-router view state changes.
This behaviour is a bug cause by vue-router, the object is destroyed properly by VUE render manager but an index reference remains by mistake, using a portal package resolves this issue.
Here is the result: