这是我的vue comp,我正在尝试验证表单,Zod已经生成了错误,只需要在对应元素中显示错误,这里验证正确完成,错误进入'error'数组,该数组在'中定义data',所以,需要从错误数组中获取正确的错误并将其显示在'span'中
<template>
<div id="basic" class="w-full details-model relative hidden rounded-md mx-auto mt-2 py-3 px-3 bg-white border border-gray-300 opend-src" style="animation-name: animat-top;animation-duration: 0.4s;box-shadow: rgb(82 63 104 / 12%) 0px 0px 10px 0px;">
<span class="absolute inline-block w-4 h-4 bg-white top-[-.5rem] sm:left-20 sm:mr-4 sm:rotate-45"></span>
<form id="rank-form" class="mainpower-form flex flex-wrap gap-y-3 gap-x-4 pt-4 justify-between" enctype="multipart/form-data" >
<div class="flex-100 addrs-ctrl relative rounded-md mb-6">
<button class="inline-flex openDisBtn group relative w-full border !border-gray-300 items-center px-3 py-2.7 text-sm font-medium text-gray-400 rounded-md focus:!border-blue-500 focus:outline-none peer-focus:!text-blue-500 focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" type="button">
<span v-if="selectedRank" class="font-normal" >{{selectedRank}} </span>
<span v-else class="text-sm text-gray-400 font-normal">Selecet Rank</span>
<svg class="w-2.5 h-2.5 ml-auto" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
</svg>
<label class="px-2 bg-white ml-2 z-20 font-medium absolute text-md text-gray-600 -translate-y-6 scale-76 top-[0.74rem] origin-[0] left-0 peer-focus:text-blue-500">Ranks</label>
</button>
<div class="z-50 dtls-menu absolute top-12 hidden bg-white rounded-md border !border-gray-300 shadow w-full mt-2 dark:bg-gray-700" style="box-shadow: rgb(0 0 0 / 3%) 0px 12.5px 10px, rgb(0 0 0 / 6%) 0px 100px 80px">
<div v-if="ranks.length" class="h-48 px-2 pb-3 pt-1 overflow-y-auto text-sm text-gray-700 dark:text-gray-200" >
<div v-for="rank in ranks" :key="rank.id" class="flex py-2.5 px-2 border-b items-center border-b-gray-300 bg-gry-100 hover:bg-gray-200 dark:hover:bg-gray-600">
<input :id="rank.id" type="radio" name="rank_name" v-model="selectedRank" :value="rank.rank_name" class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
<label :for="rank.id" class="w-full ml-2 mb-0 text-sm font-medium text-gray-900 capitalize rounded dark:text-gray-300">{{rank.rank_name}}</label>
</div>
</div>
<div v-else>
Loading disciplines...
</div>
</div>
</div>
<div class="flex-48">
<div class="relative z-0 mb-6 border border-gray-200 group rounded-md focus-within:!border-blue-400 ">
<input type="text" name="rank" id="rank " v-model="rank" class="placeholder:font-normal placeholder:text-sm block py-2.7 font-normal pl-3 w-full text-md text-gray-900 bg-transparent appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:!pl-4 focus:border-blue-600 peer" placeholder="rnking in selecetd year" required />
<label for="rank" class="px-2 bg-white ml-2 font-medium absolute text-sm text-gray-700 duration-300 transform -translate-y-6 scale-76 top-[0.74rem] -z-10 origin-[0] left-0 peer-focus:text-blue-500">Ranking</label>
</div>
</div>
<div class="flex-48">
<div class="relative z-0 mb-6 border border-gray-200 group rounded-md focus-within:!border-blue-400 ">
<input type="text" name="research" id="research" class="block py-2.7 font-normal pl-3 w-full text-md text-gray-900 bg-transparent appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:!pl-4 focus:border-blue-600 peer" placeholder="university research number .... " required />
<label for="research" class="px-2 bg-white ml-2 font-medium absolute text-sm text-gray-700 duration-300 transform -translate-y-6 scale-76 top-[0.74rem] -z-10 origin-[0] left-0 peer-focus:text-blue-500">Research Output</label>
</div>
</div>
<div class="flex-100 addrs-ctrl relative rounded-md mb-6">
<button class="inline-flex openDisBtn group relative w-full border !border-gray-300 items-center px-3 py-2.7 text-sm font-medium text-gray-400 rounded-md focus:!border-blue-500 focus:outline-none peer-focus:!text-blue-500 focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" type="button">
<span v-if="selectedYear" class="font-normal" >{{selectedYear}} </span>
<span v-else class="text-sm text-gray-400 font-normal">Selecet Year</span>
<svg class="w-2.5 h-2.5 ml-auto" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
</svg>
<label class="px-2 bg-white ml-2 z-20 font-medium absolute text-sm text-gray-600 -translate-y-6 scale-76 top-[0.74rem] origin-[0] left-0 peer-focus:text-blue-500">Disciplines</label>
</button>
<div class="z-10 dtls-menu absolute top-12 hidden bg-white rounded-md border !border-gray-300 shadow w-full mt-2 dark:bg-gray-700" style="box-shadow: rgb(0 0 0 / 3%) 0px 12.5px 10px, rgb(0 0 0 / 6%) 0px 100px 80px">
<div v-if="rankingYears.length" class="h-48 px-2 pb-3 pt-1 overflow-y-auto text-sm text-gray-700 dark:text-gray-200" >
<div v-for="year in rankingYears" :key="year" class="flex py-2.5 px-2 border-b items-center border-b-gray-300 bg-gry-100 hover:bg-gray-200 dark:hover:bg-gray-600">
<input :id="year" type="radio" name="year" v-model="selectedYear" :value="year" class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
<label :for="year" class="w-full ml-2 mb-0 text-sm font-medium text-gray-900 capitalize rounded dark:text-gray-300">{{year}}</label>
</div>
</div>
<div v-else>
Loading disciplines...
</div>
</div>
</div>
<div class="form-group flex-100">
<button type="button" id="basicId" class="w-full mt-4 text-white bg-gradient-to-r from-blue-500 via-blue-600 to-blue-700 hover:bg-gradient-to-br focus:ring-4 focus:outline-none focus:ring-blue-300 dark:focus:ring-blue-800 shadow-lg shadow-blue-500/50 dark:shadow-lg dark:shadow-blue-800/80 font-medium rounded-lg text-sm px-5 py-2.5 text-center" @click=" (event) => addRank(event)">Save Basic Info</button >
</div>
</form>
</div>
</template>
<script>
import { object, string, array } from "zod";
const schema = object({
rank_name: string().min(1).max(255),
rank: string().min(1).max(255),
research: string().min(1).max(255),
year: string().min(1).max(4),
});
export default {
name:'RanksInfo',
props:{
ranks :{
type: Array,
required: true
},
university_id:String
},
mounted() {
},
data(){
return{
selectedYear : '' ,
selectedLevel : [],
scholarship :{},
rankingYears : ['2020','2021'],
selectedRank : 'selecte rank',
id:'',
errors: null,
rank: '',
research: '',
}
},
methods:{
addRank(event){
alert("efrg")
const formElem = document.getElementById("rank-form");
const formData = new FormData(formElem);
const csrfToken = document.head.querySelector('meta[name="csrf-token"]').content;
formData.append('uni_id', this.university_id);
formData.append('_token', csrfToken);
const formDataObject = Object.fromEntries(formData.entries());
try{
schema.parse(formDataObject);
if (formData.get('rank_name') == '') {
if(formData.get('rank_name') == '' ){
}
else{
event.preventDefault();
fetch("/admin/university-rank/save", {
method: "POST",
body: formData,
})
.then(response => response.json())
.then(data => {
if(data.result){
}
if(data.error){
console.log("error--->" + data.error);
}
})
.catch(error => {
});
}
}
}catch (error) {
this.errors = error.errors;
}
},
},
};
</script>
我建议使用
schema.parse(formDataObject);
,而不是使用 schema.safeParse(formDataObject);
。
safeParse
方法不会抛出错误,而是返回一个带有success
字段的对象。
const validatedSchema = schema.safeParse(formDataObject);
if (!validatedSchema.success) {
// the error object should give you access to specific field errors if you dig into it. Its only a matter of assigning this to a reactive and using it in your template now
const error = validatedSchema.error.format();
return;
}
// correct data
const data = validatedSchema.data;