Vue with Web Component "is" Attribute - vue.js

I am trying to use a web component which extends an existing element using the "is" attribute tag, but vue takes that attribute and converts it into a custom element.
I need vue to still recognize the v-model and business logic, but I also need vue to not change it to a custom component.
Vue turns this:
<textarea v-model="text" is="my-component"></textarea>
into:
<my-component></my-component>
I have tried setting "v-pre" but that keeps vue from tracking the v-model. I have also tried to set ignoredElements, but vue still convert to a custom element. I looked https://github.com/vuejs/vue/issues/2642 and it seems like this is supposed to be a fixed issue, but maybe I am missing something.
Here is a minimal example of what is happening: https://jsfiddle.net/ntkg1xeq/1/
Notice that the textarea turns into real-set in this example.
I would expect vue to disregard the "is" attribute if it does not match any registered components, and to not rewrite the element thus preventing the web component from working.
Is there any way to use vue and web components like this together?

According to the last comment of Web component with "is" attribute not rendered in the view., <textarea v-pre v-model="text" is="my-component"></textarea> would be
render to <textarea is="my-component"> just as your expectation. However, it seems the issue just fixed Vue 1.x ( Vue 1.0.12 example code ), not Vue 2.x ( your example code ).
So. if you want to set is attribute in textarea and make v-model works in Vue 2.x, I thought $refs is another solution ( Vue 2.x example code by using $refs ).

Related

Vue component communication between header component and components in the router-view

Im facing a problem for my VUE app, Im using the vue Router to navigate to my component
In my Header component I use router-link to navigate to a Home component
The problem is :
In my Header component I would like a checkBox (a boolean variable) that change the content of my Home component (rendered in the router-view) like a v-if that would check the boolean variable in the Header
Here is my App.vue template I was trying to solve the problem through emits but Im Kinda stuck for passing data inside a component (inside the router-view)
<template>
<div class="content">
<HeaderComponent #eventCheckBox="handleCheckBox" />
<router-view />
<FooterComponent />
</div>
Do you guys have already faced this issue, is there a way to do it the classic way or should I try plugins like Portal or Teleport ?
Portal and Teleport are the same, just a different name (teleport in Vue3, being the official name).
As of the rest of the question, this explains it very well: https://stackoverflow.com/a/49702934/8816585
Mainly, you need to see if you need to use a store like Pinia (recommended one) and Vuex. Most of the time, you could use a parent/child relationship. Here is another article explaining when you would need something like that: https://markus.oberlehner.net/blog/should-i-store-this-data-in-vuex/#alternatives-to-storing-data-in-vuex
In Vue3, you could even not use a store and rely solely on the singleton pattern + composables (again, a lot of articles are available for that one).
TLDR: use your Vue devtools and inspect the state flowing.
If you need more, reach for more powerful tools.

Vue.js version 2 ignore customElement that extends form using is= syntax

Vue.js version 2 is changing the original syntax of my native customElement and because of the change the browser will not render it on the page.
Expected html on the DOM <form is="esm-justification-form"></form>
Actual html on the DOM <esm-justification-form></esm-justification-form>
In my vue template:
<div v-if="isEsm">
<form is="esm-justification-form"></form>
</div>
In my main app file, I have: Vue.config.ignoredElements = [/^esm-.*/]
In the browser where I register the component defineElement('esm-justification-form', justificationEle, 'form')
I've tested the regex expression outside of the app and it appears to be valid.
I could change from the 'is' syntax, but then 'this' would no longer be the form element. I have quite a few forms. I do not want to add extra code to select the form inside the component for events and such. There should be a way to prevent this.

Rendering HTML with Vue combined inside a Vue component

Im trying to upgrade a project from Vue 2 to Vue 3 and there is a component in there with collections of different Vue components.
The way it worked in Vue 2 is by calling a Twig template (for example: field.twig) in Twig and sending that to Vue to compile using the :is attribute and Vue.compile method (<div :is"compile(element.content) ...").
This is what the Twig templates sends to Vue:
However in Vue 3 this doesnt seem to work anymore. There is nothing getting rendered and if I just use {{ element.content }} in the template it returns the raw code.
I have tried multiple things to get the html mixed with Vue to render (v-html, v-runtime-template) but none of these seemed to fix the issue.
Vue Component: Collections Component
Twig Template: Collections Template
You can try https://markus.oberlehner.net/blog/distributed-vue-applications-loading-components-via-http/ or https://www.npmjs.com/package/vue-runtime-template-compiler but I am not sure if these work in Vue 3 ...

Vue is validating properties in a livewire component

I am using livewire in a Laravel 7 and laravel-ui project.
I created a component with livewire like this:
<livewire:task-steps :steps="$taskCategory->steps" />
This is the only component on the page and I am getting this error from vue:
I don't know why vue is validating that component's property. I tried to install livewire/vue but nothing works.
This is my app.js https://gist.github.com/LTroya/710bfbd95988003b441d533ccbe6106d
I don't know what else to do. I will appreciate any hint
Vue and livewire are competing over who owns the html.
You can tell vue to ignore a block with v-pre: https://v3.vuejs.org/api/directives.html#v-pre
Or you can tell livewire to ignore a block with wire:ignore, the following page will show examples of using it: https://laravel-livewire.com/docs/2.x/alpine-js#creating-a-datepicker
In your case, wrap the code in a div and use v-pre on it.
<div v-pre>
...
</div>

How to get the parent template component in Vue

I know in vue, I can use this.$parent to get the upper component in the vdom tree. But I'm expecting something different: to get the component that rendered the current component.
For instance, I have a component (named comp-container) with template:
<template>
<comp-a>
<comp-b></comp-b>
</comp-a>
</template>
And in comp-b the $parent would be an instance of comp-a not comp-container which I'm expecting.
My current aproach is traversing up with the $parent attribute until I find comp-b exists in $options.components. This method is working for now but seems quite ugly and breaks if comp-b is a globaly registered component. Is there an official way to do this?
Passing the parent template component via props as <comp-b :container="this"></comp-b> may do the job, but it's too verbose to be liked.
I'm not sure about the exact use case, but basically if there are slots involved (which I almost assume, because otherwise $parent will work fine), you can find the rendering component at:
this.$slots.default[0].context;
Basically, the context property of a slot is the rendering context (rendering component - i.e. the component who's template the component was rendered in).
Only tested with Vue 2