Maison  >  Questions et réponses  >  le corps du texte

VueJS gère les erreurs dans les appels d'API sur les composants de formulaire

J'ai un point de terminaison d'enregistrement simple que je souhaite permettre aux utilisateurs de s'inscrire dans mon application vue, je souhaite également afficher les erreurs appropriées au client vue depuis mon backend.

La structure JSON de l'erreur ressemble à ceci :

{
    "errors": {
        "Password": [
            "Password is required",
            "Minimum length of 8 characters is required"
        ],
        "UserName": [
            "Username is required",
            "Minimum length of 6 characters is required"
        ],
        "EmailAddress": [
            "Email Address is required",
            "Invalid Email Address"
        ],
        "ConfirmPassword": [
            "Confirm Password is required"
        ]
    }
}

J'ai un composable avec une fonction de registre comme celle-ci :

export default function useAuth() {

    let errors = ref({}) 

    const register = (request) => {

        errors = {}
        AuthService.register(request)
            .then(res => {
                console.log("res: "+ res)
            })
            .catch(err => {
                const errList = err.response.data.errors;
                errors = errList
                // Here i'm getting a reponse
                console.log(errors)

            })
    }
    return {
        register, errors
    }
}

J'ai également un composant de formulaire qui n'est qu'un simple formulaire avec des modèles en V ajoutés :

<script>
// Imports..
export default {
  components: {},
  setup() {

    const { register, errors} = useAuth();

    const request = {
      userName: "",
      emailAddress: "",
      password: "",
      confirmPassword: "",
    };


    const handleSubmit = () => {
        register(request);
        // empty object
        console.log(errors)
      
    };

    return {
      errors,
      request,
      handleSubmit
      
    };
  },
};
</script>

Dans mon composable, je peux déconnecter la réponse d'erreur comme ceci

Réponse d'erreur

J'ai essayé de désenregistrer l'erreur dans le composant formulaire mais maintenant j'obtiens juste un objet vide (j'utilise réactif pour gérer cet objet d'erreur dans le composable)

Réponse d'objet vide à partir d'éléments composables

P粉964682904P粉964682904408 Il y a quelques jours512

répondre à tous(2)je répondrai

  • P粉576184933

    P粉5761849332023-09-07 12:38:14

    On dirait que vous renvoyez un tableau, pas un objet.

    Donc, pour y accéder, vous devez faire errors[0].Password.

    Allez-vous utiliser un objet ou un tableau (cela peut être utile si vous avez plusieurs erreurs) ?

    Si le tableau est attendu et que vous devez vérifier l'attribut Password pour toutes les erreurs, vous feriez quelque chose comme ceci :

    errors.find(err => !!err.Password).Password
    

    répondre
    0
  • P粉180844619

    P粉1808446192023-09-07 09:50:32

    Réfléchissez à votre code

    Il contient plusieurs erreurs, ce qui rend difficile pour moi de fournir une réponse concise qui corresponde à vos besoins. Au lieu de cela, j'ai rapidement créé un extrait de code qui fonctionne selon vos principes. À l’avenir, j’essaierai de mettre en évidence les points à surveiller et de fournir de bons conseils pour l’avenir.

    - Réponse en utilisant async function()可以等待Promise

    Pas bon (actuellement console.log 证明使用async si vous souhaitez utiliser les résultats immédiatement)
    // YOUR CODE
    const handleSubmit = () => {
      register(request); // call PROMISE () 
      // empty object
      console.log(errors)
    };
    

    Cela ne fournit pas de résultats immédiats ; l'exécution sur un thread séparé prend un certain temps. En conséquence, le script JavaScript avance presque immédiatement. Normalement, cela entraînera une erreur si vous souhaitez utiliser le résultat immédiatement car la réponse n'est pas encore arrivée.

    Donc, lorsque vous essayez d'accéder à errors 的新结果时,您会看到它是空的,即使在 console.log 之后,1-2 秒后,它不会再为空,因为 register(), cela a déjà été exécuté.

    D'accord
    // SUCCESSFULLY USING
    const handleSubmit = async () => {
      await register(request); // call PROMISE () AND WAIT response by await
      // empty object
      console.log(errors)
    };
    

    等待 - Attendez la fin du processus - Documentation MDN
    异步函数 - 需要什么await Utilisation de - Documentation MDN

    - Comment utiliser ref() avec VueJS ?

    1.

    Stockez les valeurs enregistrées par ref()reactive()compulated(), reactive(), compulated(), etc. dans des variables non modifiables. Utilisez toujours const lors de la déclaration de ces variables.

    Plus d'informations - Réponses StackOverflow

    Pas bien
    // YOUR CODE
    let errors = ref({})
    
    D'accord
    const errors = ref({})
    
    2.

    Vous utilisez le suffixe .value dans une instance et pas dans une autre. Eh bien, ce qui se passe, c'est que le résultat d'une variable .value 后缀,而在另一实例中则不使用。嗯,情况是 ref() 变量的结果始终存储在 .value est toujours stocké dans .value. Vous pouvez le manipuler en conséquence.

    Pas bien
    // YOUR CODE
    let errors = ref({})
    
    // and...
    errors = {...}
    
    D'accord
    const errors = ref({})
    
    // and...
    errors.value = {...}
    

    Comment utiliser ref() ? - Documentation VueJS



    Exemple de code avec logique décrite

    J'ai commenté ces lignes pour mieux comprendre le code. J'espère que cela est compréhensible.

    /**
     ** Need more function for example
     ** !!! The vue is below !!!
     */
    
    // CDN Vue Import
    const { createApp, ref, computed } = Vue
    
    // isValideEmail() (JUST EXAMPLE FOR SNIPPET)
    // Helper function to validate email address
    function isValidEmail(email) {
      const emailRegex = /^\S+@\S+\.\S+$/;
      return emailRegex.test(email);
    }
    
    // AuthService (JUST EXAMPLE FOR SNIPPET)
    class AuthServiceClass {
      errors
      
      constructor() {
        this.errors = {};
      }
    
      register(inputs) {
        // Reset Errors
        this.errors = {};
        
        console.log(inputs)
        
        // Check the UserName field
        if (!inputs.userName) {
          this.errors.UserName = (this.errors?.UserName ?? []).concat("Username is required");
        }
        if (!inputs.userName || inputs.userName.length < 6) {
          this.errors.UserName = (this.errors?.UserName ?? []).concat("Minimum length of 6 characters is required");
        }
    
        // Check the EmailAddress field
        if (!inputs.emailAddress) {
          this.errors.EmailAddress = (this.errors?.EmailAddress ?? []).concat("Email Address is required");
        }
        if (!inputs.emailAddress || !isValidEmail(inputs.emailAddress)) {
          this.errors.EmailAddress = (this.errors?.EmailAddress ?? []).concat("Invalid Email Address");
        }
    
        // Check the Password field
        if (!inputs.password) {
          this.errors.Password = (this.errors?.Password ?? []).concat("Password is required");
        }
        if (!inputs.password || inputs.password.length < 8) {
          this.errors.Password = (this.errors?.Password ?? []).concat("Minimum length of 8 characters is required");
        }
    
        // Check the ConfirmPassword field
        if (!inputs.confirmPassword) {
          this.errors.ConfirmPassword = (this.errors?.ConfirmPassword ?? []).concat("Confirm Password is required");
        }
        
        // Return with Promise because its just a simulate your really AuthService.register
        return new Promise((resolve, reject) => {
          if (this.errors.length !== 0) {
            reject({ errors: this.errors });
          } else {
            resolve({ success: true, errors: null });
          }
        });
      }
    }
    // Import AuthService (JUST EXAMPLE FOR SNIPPET)
    const AuthService = new AuthServiceClass()
    
    // Declare useAuth() (JUST EXAMPLE FOR SNIPPET)
    function useAuth()
    {
        const errors = ref({}) 
    
        const register = async (request) => {
            await AuthService.register(request)
              .then(res => {
                console.log("AuthService Register Successfully Response", res)
              })
              .catch(err => {
                console.log("AuthService Register Error Response", err)
                const newErrors = err.errors;
                errors.value = newErrors
              })
        }
        
        return { register, errors }
    }
    
    /**
     ** !!!!!!
     ** Here's started vue code snippet
     */
    
    // Component.vue
    const app = createApp({
      setup() {
        // Get register() and errors Ref
        const { register, errors } = useAuth();
    
        // Declare Ref Object for inputs
        const request = ref({
          userName: "",
          emailAddress: "",
          password: "",
          confirmPassword: "",
        });
    
        // Declare Submit Function (async for Promise check !!!)
        const handleSubmit = async () => {
            console.log('') // just log
            console.log('Detect New Handle') // just log
    
            // call register() function with our value of inputs
            // wait answer by "await"
            await register(request.value);
    
            console.log('HandleSubmit - Check Error List', errors.value) // just log
        };
        
        // Just Extra Computed Value, not important
        // return true/false
        const hasError = computed(() => Object.keys(errors.value).length > 0)
        
        return { hasError, errors, request, handleSubmit }
      },
    }).mount('#app')
    .input {
      display: flex;
      flex-direction: column;
      gap: 2px;
      margin-bottom: 10px;
      max-width: 200px;
    }
    
    .error {
      color: red;
    }
    <!-- Component.vue -->
    
    <script src="https://unpkg.com/vue@3.3.4/dist/vue.global.prod.js"></script>
    
    <div id="app">
      <div>
        <!-- Display Errors -->
        <div v-if="hasError">
          <!-- errors is an object, so you can foreach its keys -->
          <div v-for="inputName of Object.keys(errors)">
            <span>{{ inputName }}:</span>
            <!-- name-array pairs can be directly printed as error messages -->
            <div v-for="errorMessage of errors[inputName]" class="error">
              {{ errorMessage }}
            </div>
          </div>
        </div>
        <!-- Inputs -->
        <!-- request is an object, so you can foreach its keys -->
        <div class="input" v-for="inputName of Object.keys(request)">
          <label>{{ inputName }}</label>
          <input v-model="request[inputName]" />
        </div>
        <!-- Submit Button -->
        <button @click="handleSubmit">Submit</button>
      </div>
    </div>

    répondre
    0
  • Annulerrépondre