Vuelidate TypeError when using with Vue 3 - vuelidate

I'm trying to use Vuelidate with Vue 3. When I try and add some validators to a component I get the following error:
index.js?1dce:614 Uncaught (in promise) TypeError: Cannot read property 'super' of undefined
I believe this is to do with the way I am using Vuelidate with the Vue instance. Here is my main.js file:
import { createApp } from 'vue';
import App from './App.vue';
import Vuelidate from 'vuelidate';
const app = createApp(App);
app.use(Vuelidate);
app.mount('#app');
I will also include the component code:
<template>
<div id="signup">
<div class="signup-form">
<form>
<div class="input">
<label for="email">Mail</label>
<input
type="email"
id="email"
#input="$v.email.$touch()"
v-model="email">
<div>{{ $v }}</div>
</div>
</form>
</div>
</div>
</template>
<script>
import { required, email } from 'vuelidate/lib/validators'
export default {
data () {
return {
email: '',
}
},
validations: {
email: {
required: required,
email: email
}
}
}
}
</script>
Does anyone know how to fix this? If Vue 3 is not compatible with Vuelidate, can anyone recommend and alternative that is?
Thanks

From your example, it looks like you are using Vuelidate for Vue 2. Vuelidate for Vue 3 is in alpha (as at the time of writing 30 Sep 2020) but you can still use it.
Just install the following libraries.
npm install #vuelidate/core #vuelidate/validators
# or
yarn add #vuelidate/core #vuelidate/validators
You can still use the Options API approach that you are using in your example or move to the Composition API approach.
import { ref } from 'vue'
import { useVuelidate } from '#vuelidate/core'
import { required, email } from '#vuelidate/validators'
export default {
setup () {
const email = ref('')
const rules = {
email: { required, email }
}
const $v = useVuelidate(rules, { email })
return { email, $v }
}
}
I haven't tried it myself but I hope this helps you.
Until it hits production-ready, you can find more information from the following links:
Github repo: https://github.com/vuelidate/vuelidate/tree/next
vuelidate#next doco: https://vuelidate-next.netlify.app/
EDIT:
I forgot to mention that if you continue to use the Options API approach you need to change your import statement in main.js to the following:
import { createApp } from 'vue'
import App from './App.vue'
import { VuelidatePlugin } from '#vuelidate/core'
const app = createApp(App)
app.use(VuelidatePlugin)
app.mount('#app')

Related

Polymer/Lit-Element - Braintree gateway integration - Web Component problem

I am trying to integrate Braintree payment gateway to Vaadin 14 which is using Polymer for its frontend.
Basically we have a custom Vaadin front-end view to load script https://js.braintreegateway.com/web/dropin/1.9.4/js/dropin.min.js :
And we call its method dropin.create as below:
import{PolymerElement}from'#polymer/polymer/polymer-element.js';
import'#polymer/iron-icon/iron-icon.js';
import{html}from'#polymer/polymer/lib/utils/html-tag.js';
import '#webcomponents/webcomponentsjs/webcomponents-loader.js';
import'#polymer/polymer/polymer-legacy.js';
import'#polymer/iron-flex-layout/iron-flex-layout.js';
import{mixinBehaviors}from'#polymer/polymer/lib/legacy/class.js';
import{Polymer}from'#polymer/polymer/lib/legacy/polymer-fn.js';
import{setTouchAction}from'#polymer/polymer/lib/utils/gestures.js';
import{afterNextRender}from'#polymer/polymer/lib/utils/render-status.js';
import'#vaadin/vaadin-text-field/vaadin-text-field.js';
import { sharedStyles } from './drop-in.js';
let dropin = require('braintree-web-drop-in');
class BrainTreeVaadin extends PolymerElement {
<vaadin-vertical-layout class="main-div-layout-boder padding5">
<form id="paymentForm" method="post" action="/checkout" class="main-screen-vert-layout-row">
<div id="containPayment" class="main-screen-vert-layout-row">
<div id="btDropin" class="main-screen-vert-layout-row"></div>
</div>
<vaadin-text-field id="nonce" value={{valueNonce}} hidden></vaadin-text-field>
<vaadin-button id="butPayment" theme="theme-button-02" class="button-row">Payment</vaadin-button>
</form>
</vaadin-vertical-layout>
createFormPayment(){
let form = this.$.paymentForm;
let butPayment = this.$.butPayment;
let btDropin = this.$.btDropin;
let textNonce = this.$.nonce;
dropin.create({
authorization: this.clientToken,
container: btDropin,
card: {
cardholderName: {
required: true
}
},
paypal: {
flow: 'vault',
currency: 'USD'
},
paypalCredit: {
flow: 'vault',
currency: 'USD'
}
}
}
}
However we get error as below image:
Reason that internally, the main script dropin.min.js includes other script https://www.paypalobjects.com/api/checkout.min.js and called other methods from this new JS.
Accessing methods in checkout.min.js got error because checkout.min.js can’t get id of html elements (here is buttons) using javascript reference style "#...".
Braintree uses JS style #element_id to pass a html div element as argument to method: braintree.dropin.create(..., container: '#bt-dropin').
Below is Braintree example code (take note on method "braintree.dropin.create", it takes '#bt-dropin' as input):
<div class="bt-drop-in-wrapper">
<div id="bt-dropin"></div>
</div>
<div th:include="fragments/homefooter :: footer"></div>
<script src="https://js.braintreegateway.com/web/dropin/1.9.4/js/dropin.min.js"></script>
<script th:inline="javascript">
/*<![CDATA[*/
var form = document.querySelector('#payment-form');
var client_token = [[${clientToken}]];
braintree.dropin.create({
authorization: client_token,
container: '#bt-dropin',
paypal: {
flow: 'vault'
}
}, function (createErr, instance) {
form.addEventListener('submit', function (event) {
event.preventDefault();
$('#errorDiv').hide();
$('#serverSideErrorDiv').hide();
instance.requestPaymentMethod(function (err, payload) {
if (err) {
console.log('Error', err);
showError(err);
return;
}
// Add the nonce to the form and submit
document.querySelector('#nonce').value = payload.nonce;
form.submit();
});
});
});
And problem that Vaadin form (view) doesn’t understand javascript style: "#bt-dropin" to reference to a div element.
How to make Vaadin view understand JS style: "#element_id" ?
Update:
this is polymer problem, not Vaadin flow problem.
Update 2:
this is braintree problem, not polymer problem :)).
This is a issue of braintree due to lacking of supporting web components.
Below is workaround solution.
Braintree Git Issue
Workaround (remove space .io on URL):
https://codepen .io/braintree/pen/VrYXYW

Problems with using InputMask PrimeVue in Vue3

Im trying to use InputMask from PrimeVue in project on Vue3
I have block in template tag:
<div class="sdf">
<label for="basic">Basic</label>
<InputMask mask="99-999999" v-model="val1" placeholder="99-999999" />
</div>
and i have script:
export default {
data: () => ({
val1: null,
})
}
Everything seems okay, and console doesn't show any errors, but still, input is not visible, only label is shown. What do i do wrong?
It sounds like you didn't register InputMask.
You could register it globally with app.component('InputMask', InputMask):
// main.js
const { createApp } = require('vue')
import PrimeVue from 'primevue/config'
import InputMask from 'primevue/inputmask'
import App from './App.vue'
createApp(App)
.use(PrimeVue)
.component('InputMask', InputMask)
.mount('#app')
demo

why the html content not shown out when running

Now i use visual studio code to do my project. I can build my code without error, but when running, it no show out the content for html file, only have show css like header abd footer. i have click button on header but cannot go to other page.Here is the sample code
code in index.html
<nav>
List
New student
Student feedback
</nav>
Vue router
const router = new VueRouter({
routes: [
{ path: '/home', component: load('home') },
{ path: '/insert', component: load('insert') },
{ path: '/update/:id', component: load('update') },
{ path: '/feedback', component: load('feedback') },
{ path: '*', redirect: '/home' }
]
});
File name and type: _home.html, _insert.html, _update.html, _feedback.html
Can help me see the problem, thank you
I don't think you should edit directly to index.html as Vue is Single Page Application (SPA) framework. Instead, you should use Vue Component for each page.
This video might help you to figure out how to use Vue and Vue Router properly: https://youtu.be/nnVVOe7qdeQ
Edit:
For sake of clarity, Let me build simplified diagram of Vue project for you.
First of all, make sure you create the project via vue cli. It guides you to build your new vue project better.
Let's say we have 3 pages:
Home
About
Another
Each page has its own CSS, HTML (we call it template), and JavaScript in one file, the .vue file. To connect them, we need a first entrance, main.js. Inside of it, we can configure the router.
Inside main.js
import Vue from "vue";
import VueRouter from "vue-router";
import App from "./App.vue";
import HomePage from "./HomePage.vue";
import AboutPage from "./AboutPage.vue";
import AnotherPage from "./AnotherPage.vue";
// This is your router configuration
Vue.use(VueRouter);
const router = new VueRouter({
[
{ path: "/", component: HomePage },
{ path: "/about", component: AboutPage },
{ path: "/another", component: AnotherPage },
],
mode: "history",
});
// Initialize Vue App
new Vue({
router,
render: h => h(App),
}).$mount("#app");
Then, we need to create App.vue and put <router-view /> inside of it.
Inside App.vue source file
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
// Keep this empty. Except if you
// need to add sidebar or any else.
}
</script>
Now you're ready to create those three pages
Every pages looks like this:
<style scoped>
// Your CSS here
</style>
<template>
<div>
<!-- Your HTML here -->
</div>
</template>
<script>
export default {
data() {
return {
// Your reactive data here
}
},
mounted() {
// Your script here
},
methods: {
// Your functions here
},
}
</script>
That's all I can explain, hope it helps. If I missed something, please don't hesitate to tell me. Thank you!

Fetching data from API and using it in JSX is giving string output to the html tag

I am fetching data from an API whose response is:
{
"name": "family: woman, woman, girl, girl",
"unicode": "1F469 200D 1F469 200D 1F467 200D 1F467",
"html": "πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘§"
}
and now I want to use this value in my code using JSX:
import React from 'react';
function Card(props) {
return (
<div>
<p>{props.html}</p>
</div>
);
}
export default Card;
Output I am getting on my page
πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘§
Required Output
πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘§
You could use
<p dangerouslySetInnerHTML={{ __html: props.html }} />
Codesandbox demo
Reference
dangerouslySetInnerHTML
Try this code
import React from 'react';
import Parser from "html-react-parser";
function Card(props) {
return (
<div>
<p>{Parser(props.html)}</p>
</div>
);
}
export default Card

Type '{}' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes

i am currently making a simple react application.
this is my index.tsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './components/App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(
<App />,
document.getElementById('root') as HTMLElement
);
registerServiceWorker();
and here I have my app.tsx
import * as React from 'react';
import SearchBar from '../containers/price_search_bar';
interface Props {
term: string;
}
class App extends React.Component<Props> {
// tslint:disable-next-line:typedef
constructor(props) {
super(props);
this.state = {term: '' };
}
render() {
return (
<div className="App">
<div className="App-header">
<h2>Welcome to React</h2>
</div>
<p className="App-intro">
this is my application.
</p>
<div>
<form>
<SearchBar term={this.props.term} />
</form>
</div>
</div>
);
}
}
export default App;
and also my search bar container:
import * as React from 'react';
interface Props {
term: string;
}
// tslint:disable-next-line:no-any
class SearchBar extends React.Component<Props> {
// tslint:disable-next-line:typedef
constructor(props) {
super(props);
this.state = { term: '' };
}
public render() {
return(
<form>
<input
placeholder="search for base budget"
className="form-control"
value={this.props.term}
/>
<span className="input-group-btn" >
<button type="submit" className="btn btn-secondary" >
Submit
</button>
</span>
</form>
);
}
}
export default SearchBar;
and finally I have my tsconfig.json:
{
"compilerOptions": {
"outDir": "build/dist",
"module": "esnext",
"target": "es5",
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": true,
"jsx": "react",
"moduleResolution": "node",
"rootDir": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": false,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"typeRoots": [
"node_modules/#types"
],
"noUnusedLocals": true
},
"exclude": [
"node_modules",
"build",
"scripts",
"acceptance-tests",
"webpack",
"jest",
"src/setupTests.ts"
]
}
I keep getting different errors after errors and when ever I fix one error another one appears, I am not sure what I have done that make it behave like this.
This is the latest error:
./src/index.tsx
(7,3): error TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<App> & Readonly<{ children?: ReactNode; }> & Reado...'.
Type '{}' is not assignable to type 'Readonly<Props>'.
Property 'term' is missing in type '{}'.
I tried to fix it by modifying my tsconfig.json but the same error still appears, what am I doing wrong and why typescript is bahing like this. I am very new to this and by this example I am trying to udnertand how react works all together.
I solved a lot of "not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes" type of errors (Microsoft closed issue) just by declaring an object that is passed entirely to the component.
With the OP's example, instead of using term={this.props.term}, use {...searchBarProps} to get it working:
render() {
const searchBarProps = { // make sure all required component's inputs/Props keys&types match
term: this.props.term
}
return (
<div className="App">
...
<div>
<form>
<SearchBar {...searchBarProps} />
</form>
</div>
</div>
);
}
All you need is to declare the component type properly to include the props type:
interface IMyProps {
myValue: boolean,
}
const MyComponent: React.FC<IMyProps> = (props: IMyProps) => {
...
}
export default MyComponent;
Then you can use it as:
import MyComponent from '../MyComponent';
...
return <MyComponent myValue={true} />
And voila, typescript is happy. The good thing about it is that typescript is now checking for passing only the parameters they actually exist in the props interface (can prevent typos and so on).
For the standard component it would be something similar to (what's already in Swapnill's example):
class MyComponent extends React.Component<IMyProps, IMyState>{
constructor(props: IMyProps){}
}
export default MyComponent;
The problem here is not with your tslint settings. Look at the following code snippet:
interface SearchBarProps {
term: string;
optionalArgument?: string;
}
interface SearchBarState{
something: number;
}
class SearchBar extends React.Component<SearchBarProps, SearchBarState> {
constructor(props: SearchBarProps){
super(props);
this.state = {
something: 23
};
}
render() {
const {something} = this.state;
return (
<div>{something}</div>
)
}
}
In class SearchBar extends React.Component<SearchBarProps, SearchBarState> {, SearchBarProps and SearchBarState denote type of expected props and type of state for component SearchBar respectively. You must give propTypes and stateType when you use typescript.
You can avoid giving types by using keyword any but I highly suggest you not to follow this "evil" path if you truly want to take advantage of using typescript. In your case it seems that you haven't specified type of state and used it, fixing that will solve this problem.
Edit 1
In interface SearchBarProps, optionalArgument becomes an optional argument as we add a question mark ? in front of it, so <SearchBar term='some term' /> won't show any error even if you don't pass optionalArgument explicitly.
Hope this solves your problem!
Just had this same problem.
You have member called term defined on the Prop inteface for your App class but you're not providing a value when you create your App element.
Try the following:
ReactDOM.render(<App term="Foo" />, document.getElementById('root') as HTMLElement);
I'm not really proud of that but, considering other solutions in this thread, it seems fair enough.
This example shows a custom version of #react-native-community/slider with some default properties but able to receive (and overwrite) from outside:
function CustomSlider(props: SliderProps) {
return (
<Slider
style={{ width: '100%', height: 40, marginTop: 12 }}
minimumValue={0}
minimumTrackTintColor="#000000"
maximumTrackTintColor="#000000"
{...(props as any)}
/>
);
}
I also faced the same problem. Add below code to work with .tsx components.
export interface Props {
term: string;
}
or
export type Props = {
term ?: string;
}
I dont know the exact reason, but i think typescript flag the type error during compilation phase. Let me know if it works for you.
I know my answer is somewhat off-topic, but in an Vue3 application I can reproduce the error by assigning the component the props attribute even if no props are passed:
export default defineComponent({ props:{} .... })
Just by removing the props attribute the compiler do not complains anymore.
The issue is that you are not exporting the interface, you should always export the interface props. So:
export interface Props {
term: string;
}
Is the solution.
For functional components, this syntax solves this error without React.FC boilerplate:
interface FooProps {
foo: FooType
}
function FooComponent({ foo }: FooProps): ReactElement {
...
}
I keep arriving back here because Volar is raising a similar error in my Vue 3 component. The solution is always that I am returning and empty object for props because my component template has it for convenience but I haven't used it.
When the component is used:
<template>
<div>
<MyComponent/> <!-- Squiggly error here -->
</div>
</template>
The component:
export default defineComponent({
name: 'MyComponent',
components: {},
props: {}, // Remove this
setup() {
return {};
},
});
If you're blind like me, you may bump into the following.
Instead of:
interface TimelineProps {
width: number;
}
const Timeline: FC = (props: TimelineProps) => {
...
Do:
const Timeline: FC<TimelineProps> = (props: TimelineProps) => {
^^^
What worked for me is simply changing the child Component type from React.FC to JSX.Element
Before (warning)
const Component: React.FC = () => {
After (no warning)
const Component = (): JSX.Element => {
Insted of <YourComponent product={product} /> use <YourComponent {...product} />
For components, it may be because you wrote your component like this:
<ClearButton
text={"Clear board"}
isAnimationInProgress={isAnimationInProgress}
callSetOptionMethod={clearBoard}
>
// empty space here
</ClearButton>
Instead of this:
<ClearButton
text={"Clear board"}
isAnimationInProgress={isAnimationInProgress}
callSetOptionMethod={clearBoard}
></ClearButton>
Just spread the passing props like {...searchval} .
and in the component use the props and assign the type original type of searchval.This should work