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

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.

Related

Update Vue Web Component attribute from parent onMounted

Because of consuming logic from a separate, server-side templating engine, I find myself working with native Web Components / Custom Elements (built in Vue v3) rather than a more "normal" Vue app.
TL/DR: If I override child CustomElement attributes during parent $onMounted() (or shortly after), it breaks the child's reactivity, but if I wait 1sec everything's fine... Is there a way to get it working properly?
The setup is something like the below, where the HTML is generated at run-time:
<!-- Runtime-generated index.html -->
<outer-custom-element>
<!-- Content populated dynamically by a separate SSR templating engine -->
<inner-custom-element myboolprop otherprop="5" />
<inner-custom-element otherprop="5" />
</outer-custom-element>
Both inner and outer components are Vue-implemented Custom Elements, and the outer component uses a <slot> to transclude the content in its template:
<!-- OuterCustomElement Vue template -->
<div class="outer-el">
<div class="everybody-loves-divs">
<slot></slot>
</div>
</div>
Because the server templating engine controls the inner content, these InnerVueCustomElements are not (and as far as I know cannot be) bound directly to Vue data on the OuterVueCustomElement: If the parent component needs to know what's inside it, we'll have to hack around with DOM and HTMLSlotElement.assignedElements() to interact with the inner components. Yes it's ugly and limiting, but seems pretty unavoidable to me if we have to accept something other than Vue controls the layout of this section of the HTML?
So anyway the problem arises if we try to update inner component props immediately after outer component mount, something like this:
/* OuterCustomElement Vue script */
function $onMounted(props) {
// (Some combination of querySelectorAll and slot assignedElements)
const innerEls: HTMLElement[] = listInnerCustomElements();
// This will permanently break otherprop reactivity on the element:
// innerEls[0].setAttribute("otherprop", "0");
// This will not (works fine):
setTimeout(() => innerEls[0].setAttribute("otherprop", "0"), 1000);
}
setTimeout(..., 10) and Vue's nextTick(...) suffer from the same problem as the immediate call: The inner component will not respond to the change. However if we wait a decent amount of time, this update goes through fine and nothing breaks.
I know this is a long way removed from normal state/render lifecycle management good practice within an all-Vue app, but for a Web Component / Custom Element it should be possible right?
Can anybody suggest what's breaking here and how to avoid it?

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>

Vue with Web Component "is" Attribute

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 ).

Vue app with Netlify form throws error binding to events

I am trying to hide/show a div if a form-input has a value. This works just fine with a regular form but if I implement it with netlify-forms I get the following error:
Unhandled promise rejection TypeError: "setting getter-only property "message""
<form name="newsletter" method="POST" data-netlify="true">
<input #input="email = $event.target.value" type="email" name="email">
<div :class="{'hidden': email === ''}">
<div data-netlify-recaptcha="true" />
</div>
</form>
I also tried #focus and #blur instead of #input but the error is always the same.
Without the data-netlify="true" it works as expected so I suspect it to have something to do with Netlify injecting something into the form.
In Netlify's guide on Netlify Forms + Vue, they say that the way SPAs are rendered can prevent Netlify's bots from HTML-editing the form to link it with their services.
By default Vue renders client side but the Netlify post processing bots expect HTML on site deploy. Any netlify form attribute tags included in a Vue app would only be inserted into the DOM client-side, rather than in the HTML and thereby runs the risk of being totally overlooked by the build bots.
To handle this, you have two options. You can either pre-render your application or add the netlify form to your static HTML file in your public folder.
So either pre-render your HTML (which gives an added speed and SEO bonus), or give netlify a static form to attach itself to, which you can then hide and replace with your nice Vue form on the client.

How to disable replacing the app root div with the component HTML while using templates

So basically, when using components - the app root passed to the Vue instance gets replaced by whatever HTML is in the component. Is there a way to disable this and just nest the stuff Vue renders inside the app root instead?
for example - if index.html has a wrapper of
<div id="myVueApp"></div>
and I set el: "#myVueApp" on the Vue instance, the whole node will get removed and replaced by whatever I have in my template resulting in
<div id="myComponent">...</div>
Is there a way to make it into
<div id="myVueApp">
<div id="myComponent">...</div>
</div>
Should work. From what I understand, you want to have multiple parts of your Vue app to be splitted up in the rendered HTML output as well, more specifically into multiple divs.
I think this should work if you use multiple Vue instances.
Set up a structure in your HTML file and give them appropriate id's.
Then, create the Vue instances you want and assign each of them to their specific div using el.
However, I can't tell you if this is a good idea and follows the best practice..
Hope this helps!