Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

255
Vistas
Vue: el mejor enfoque para acceder a posibles propiedades anidadas existentes en el objeto de error

Estoy buscando un enfoque bueno y reutilizable para acceder a posibles propiedades anidadas existentes (objeto anidado y matriz de objetos) dentro de un objeto de error sin typeErrors.

Tengo un formulario/página createCompany con los siguientes datos

 data() { return { company: { same_billing_address: true, physical_address: {}, billing_address: {}, contacts: [ { function: '', first_name: '', last_name: '', phone: '', gender: 'female', email: '', language: 'nl', date_of_birth: '', }, ], }, validationErrors: {}, } }

El formulario en sí se ve así

 <form @submit.prevent="createCompany" @keydown.enter="$event.preventDefault()" class="divide-y"> <fieldset class="pb-6"> <header> <h3 class="mb-3 text-lg leading-6 font-medium text-gray-900">{{ $tc('general', 1) }}</h3> </header> <div class="grid grid-cols-12 gap-x-6 gap-y-3"> <div class="col-span-12"> <InputWithButton :label="$tc('enterprise_number', 1)" buttonLabel="Get enterprise data" :onClick="getEnterpriseData" type="text" id="enterprise_number" v-model="company.enterprise_number" :error="validationErrors.enterprise_number" /> </div> <div class="col-span-6"> <Input :label="$tc('business_name', 1)" type="text" id="companyName" v-model="company.business_name" :error="validationErrors.business_name" /> </div> <div class="col-span-6"> <Input :label="$tc('legal_entity_type', 1)" type="text" id="companyType" v-model="company.legal_entity_type" :error="validationErrors.legal_entity_type" /> </div> <div class="col-span-3"> <Input :label="$tc('phone', 1)" type="text" id="phone" v-model="company.phone" :error="validationErrors.phone" /> </div> <div class="col-span-6"> <Input :label="$tc('email_address', 1)" type="text" id="email" v-model="company.email" :error="validationErrors.email" /> </div> </div> </fieldset> <fieldset class="py-6"> <header> <h3 class="mb-3 text-lg leading-6 font-medium text-gray-900">{{ $tc('physical_address', 1) }}</h3> </header> <div class="grid grid-cols-12 gap-x-6 gap-y-3"> <div class="col-span-8"> <Input :label="$tc('street', 1)" type="text" id="street" v-model="company.physical_address.street" :error="validationErrors.physical_address.street" /> </div> <div class="col-span-2"> <Input :label="$tc('number', 1)" type="text" id="number" v-model="company.physical_address.number" :error="validationErrors.physical_address.number" /> </div> <div class="col-span-2"> <Input :label="$tc('addition', 1)" optional type="text" id="addition" v-model="company.physical_address.addition" :error="validationErrors.physical_address.addition" /> </div> <div class="col-span-8"> <SelectWithSearch :label="$tc('city', 1)" id="billing_address_postal_code_id" v-model="company.physical_address.postal_code_id" :options="cityOptions" displayProperty="display_name" valueProperty="id" :minLengthForDropdown="3" :error="validationErrors.physical_address.zip_city" /> </div> <div class="col-span-4"> <Input :label="$tc('country', 1)" type="text" id="country" v-model="company.physical_address.country" :error="validationErrors.physical_address.country" /> </div> </div> </fieldset> <fieldset class="py-6"> <header> <h3 class="mb-3 text-lg leading-6 font-medium text-gray-900">{{ $tc('billing_address', 1) }}</h3> </header> <div class="grid grid-cols-12 gap-x-6 gap-y-3"> <div class="col-span-12"> <Checkbox :label="$tc('billing_same_as_physical', 1)" v-model="company.same_billing_address" :error="validationErrors.same_billing_address" /> </div> <template v-if="!company.same_billing_address"> <div class="col-span-8"> <Input :label="$tc('street', 1)" type="text" id="street" v-model="company.billing_address.street" :error="validationErrors.billing_address.street" /> </div> <div class="col-span-2"> <Input :label="$tc('number', 1)" type="text" id="number" v-model="company.billing_address.number" :error="validationErrors.billing_address.number" /> </div> <div class="col-span-2"> <Input :label="$tc('addition', 1)" type="text" id="addition" v-model="company.billing_address.addition" :error="validationErrors.billing_address.addition" /> </div> <div class="col-span-8"> <SelectWithSearch :label="$tc('city', 1)" id="billing_address_postal_code_id" v-model="company.billing_address.postal_code_id" :options="cityOptions" displayProperty="display_name" valueProperty="id" :minLengthForDropdown="3" :error="validationErrors.billing_address.zip_city" /> </div> <div class="col-span-4"> <Input :label="$tc('country', 1)" type="text" id="country" v-model="company.billing_address.country" :error="validationErrors.billing_address.country" /> </div> </template> </div> </fieldset> <fieldset class="py-6"> <div class="flex justify-between mb-3"> <header> <h3 class="text-lg leading-6 font-medium text-gray-900">{{ $tc('contact', company.contacts.length) }}</h3> </header> <button type="button" class="text-sm leading-6 font-medium text-blue-500 flex items-center" @click="addContact">{{ $tc('add', 1) }} {{ $tc('contact', 1).toLowerCase() }}</button> </div> <section class="space-y-6"> <div v-for="(contact, contactIdx) in company.contacts" :key="contactIdx"> <h4 v-show="company.contacts.length > 1" class="mb-3 text-sm leading-6 font-medium text-gray-500"> {{ $tc('contact', 1) }} {{ contactIdx + 1 }} <span @click="deleteContact(contactIdx)" class="text-blue-500 cursor-pointer select-none">({{ $tc('delete', 1) }})</span> </h4> <div class="grid grid-cols-12 gap-x-6 gap-y-3"> <div class="col-span-12"> <RadioButtonGroup :label="$tc('gender', 1)" :options="genderOptions" v-model="contact.gender" :error="contacts[contactIdx].gender" /> </div> <div class="col-span-6"> <Input :label="$tc('first_name', 1)" type="text" id="first_name" v-model="contact.first_name" :error="contacts[contactIdx].first_name" /> </div> <div class="col-span-6"> <Input :label="$tc('last_name', 1)" type="text" id="last_name" v-model="contact.last_name" :error="contacts[contactIdx].last_name" /> </div> <div class="col-span-3"> <Input :label="$tc('phone', 1)" type="text" id="phone" v-model="contact.phone" :error="contacts[contactIdx].phone" /> </div> <div class="col-span-6"> <Input :label="$tc('email_address', 1)" type="text" id="email" v-model="contact.email" :error="contacts[contactIdx].email" /> </div> <div class="col-span-3"> <Input :label="$tc('date_of_birth', 1)" type="date" id="date_of_birth" v-model="contact.date_of_birth" :error="contacts[contactIdx].date_of_birth" /> </div> <div class="col-span-9"> <Input :label="$tc('function', 1)" type="text" id="function" v-model="contact.function" :error="contacts[contactIdx].function" /> </div> <div class="col-span-3"> <Select :label="$tc('language', 1)" id="languageOfContact" :options="languageOptions" displayProperty="display_name" valueProperty="name" v-model="contact.language" :error="contacts[contactIdx].language" /> </div> </div> </div> </section> </fieldset> <fieldset class="pt-6"> <SubmitButton :label="$tc('create_company', 1)" submittingLabel="Creating company..." /> </fieldset> </form>

Antes de que los datos se envíen al backend, se validan

 async createCompany() { try { await CreateCompanyValidationSchema.validate(this.company, { abortEarly: false }); console.log('all good'); } catch (err) { console.log(err.inner); err.inner.forEach((error) => { this.validationErrors = { ...this.validationErrors, [error.path]: error.message }; }); } }

Estoy usando Yup para validar el formulario. El esquema se ve así

 export const CreateCompanyValidationSchema = yup.object().shape({ enterprise_number: yup.string(), business_name: yup.string(), legal_entity_type: yup.string(), phone: yup.string().required(), email: yup.string().required().email(), language: yup.string().required(), first_name: yup.string(), last_name: yup.string(), date_of_birth: yup.date(), physical_address: yup.object({ street: yup.string().required(), number: yup.string().required(), addition: yup.string(), zip_city: yup.string().required(), country: yup.string().required(), }), same_billing_address: yup.boolean(), billing_address: yup.object().when('same_billing_address', { is: false, then: yup.object({ street: yup.string().required(), number: yup.string().required(), addition: yup.string(), zip_city: yup.string().required(), country: yup.string().required(), }), }), contacts: yup.array().of( yup.object().shape({ gender: yup.string().required().oneOf(['male', 'female', 'other']), first_name: yup.string().required(), last_name: yup.string().required(), phone: yup.string().required(), email: yup.string().required().email(), date_of_birth: yup.date().required(), function: yup.string().required(), language: yup.string().required().oneOf(['nl', 'fr', 'en']), }) ), });

El objeto de datos validationErrors tiene una estructura de objeto physical_address ( dirección_física y billing_address ) y una matriz anidada de objetos ( contacts ). El objeto validationErrors está vacío al principio. Si los campos de dirección anidados o los contactos son válidos, el objeto validationErrors no tendrá ninguna propiedad anidada. Pero en el formulario estoy accediendo a propiedades secundarias como validationErrors.contacts[contactIdx].phone o validationErrors.billing_address.street . Esto provoca errores porque estas propiedades no existen. ¿Cuál es el mejor enfoque para contrarrestar esto? Estoy buscando una solución reutilizable para múltiples formularios con esta estructura.

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

Una opción es utilizar un cortocircuito para acceder de forma segura a las propiedades anidadas, solo si existen.

 if ( validationErrors && validationErrors.billing_address ) { console.log(validationErrors.billing_address.street) }

La declaración if solo es verdadera si la validationErrors.billing_address está definida, pero no generará un error si la validationErrors no está definida.

Si cree que este patrón es demasiado feo y repetitivo, es posible que le interese usar una biblioteca para ayudarlo a acceder a las propiedades anidadas. https://lodash.com/docs/#get

over 4 years ago · Santiago Trujillo Denunciar

0

En Vue 3, el operador de encadenamiento opcional (navegación segura) se puede usar directamente en plantillas para acceder a claves inexistentes:

 :error="contacts?.[contactIdx]?.first_name"

En Vue 2, esto requiere mover este código a un método y probablemente especificar una ruta a la propiedad anidada con cadenas, por ejemplo, con Lodash get o una función auxiliar similar, que también permite especificar el valor predeterminado para claves inexistentes.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda