What is the best way to set up v-models for complex arrays or nested objects?

I'm looking to efficiently create multiple v-models for random properties within a deep array, where the position of attributes in arrays/objects can change dynamically. While I've managed to achieve my goal with the current setup, I'll need to render several fields in different locations on the page, making the use of v-for impractical. Is there a way to simplify this code?

<template>
  <div class="builder">
    <div class="sidebar">
      <div class="block">
        <input v-model="template[headTagIndex].children[headTagAttributesIndex].children[headTagAttributesAllIndex].attributes['font-family']" placeholder="General Font" type="text">
      </div>
    </div>
    <div class="editor">
      <div v-if="compiledTemplate" v-html="compiledTemplate.html"/>
      <div v-else>Loading</div>
    </div>
    <div class="ads"/>
  </div>
</template>

<script setup>
const {$mjml} = useNuxtApp()

const template = ref([
  {
    "tagName": "mj-head",
    "children": [
      {
        "tagName": "mj-attributes",
        "children": [
          {
            "tagName": "mj-all",
            "attributes": {
              "font-family": "Comic sans-serif"
            }
          }
        ]
      }
    ]
  },
  {
    "tagName": "mj-body",
    "children": [
      {
        "tagName": "mj-section",
        "attributes": {
          "background-color": "red"
        },
        "children": [
          {
            "tagName": "mj-column",
            "attributes": {
              "padding-top": "100px",
              "padding-bottom": "100px"
            },
            "children": [
              {
                "tagName": "mj-text",
                "attributes": {
                  "align": "center",
                  "color": "#F45E43"
                },
                "content": "Testing component"
              }
            ]
          }
        ]
      },
      {
        "tagName": "mj-section",
        "attributes": {
          "full-width": "full-width",
          "background-color": "blue"
        },
        "children": [
          {
            "tagName": "mj-column",
            "attributes": {
              "padding-top": "100px",
              "padding-bottom": "100px"
            },
            "children": [
              {
                "tagName": "mj-text",
                "attributes": {
                  "align": "center",
                  "color": "#F45E43"
                },
                "content": "Testing component"
              }
            ]
          }
        ]
      },
      {
        "tagName": "mj-section",
        "attributes": {
          "background-color": "pink"
        },
        "children": [
          {
            "tagName": "mj-column",
            "attributes": {
              "padding-top": "100px",
              "padding-bottom": "100px"
            },
            "children": [
              {
                "tagName": "mj-text",
                "attributes": {
                  "align": "center",
                  "color": "#F45E43"
                },
                "content": "Testing component"
              }
            ]
          }
        ]
      },
      {
        "tagName": "mj-section",
        "attributes": {
          "full-width": "full-width",
          "background-color": "teal"
        },
        "children": [
          {
            "tagName": "mj-column",
            "attributes": {
              "padding-top": "100px",
              "padding-bottom": "100px"
            },
            "children": [
              {
                "tagName": "mj-text",
                "attributes": {
                  "align": "center",
                  "color": "#F45E43"
                },
                "content": "Testing component"
              }
            ]
          }
        ]
      }
    ]
  }
])

const headTagIndex = indexOfHeadTag(template.value)
console.log(headTagIndex)
const headTagAttributesIndex = indexOfHeadTagAttributes(template.value, headTagIndex)
console.log(headTagAttributesIndex)
const headTagAttributesAllIndex = indexOfHeadTagAttributesAll(template.value, headTagIndex, headTagAttributesIndex)
console.log(headTagAttributesAllIndex)

const compiledTemplate = generateCompiledTemplate($mjml, template.value)
</script>

The areas that require optimization are:

v-model="template[headTagIndex].children[headTagAttributesIndex].children[headTagAttributesAllIndex].attributes['font-family']"

And:

const headTagIndex = indexOfHeadTag(template.value)
console.log(headTagIndex)
const headTagAttributesIndex = indexOfHeadTagAttributes(template.value, headTagIndex)
console.log(headTagAttributesIndex)
const headTagAttributesAllIndex = indexOfHeadTagAttributesAll(template.value, headTagIndex, headTagAttributesIndex)
console.log(headTagAttributesAllIndex)

Answer №1

Discovering attributes can be done in a single line using the .find() method:

const attributes = template.value.find(tag => tag.tagName === 'mj-head')
   ?.children?.find(tag => tag.tagName === 'mj-attributes')
   ?.children?.find(tag => tag.tagName === 'mj-all')
   ?.attributes;

The v-model implementation will then appear as follows:

<input v-model="attributes['font-family']" placeholder="General Font" type="text"/>

Try out the Vue SFC Playground

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How many server queries does a single web application require?

As someone new to web app development, my main goal is to optimize speed as much as possible. I am faced with two options: The first option is to fetch data from the database individually every time a refresh is needed in the app. Alternatively, I c ...

Error in Angular: Trying to access property 'setLng' of a null component variable

Just starting out with Angular and I've come across the error message Cannot read property 'setLng' of null. Can anyone help explain why this is happening? import { Component, OnInit, Input } from '@angular/core'; @Component({ ...

Using Vue.js and Axios to retrieve data and store it in an array

I am currently developing a typeahead feature for my project. The typeahead component accepts an array list like ['Canada', 'USA', 'Mexico']. However, I now have an axios API available to fetch a list of countries, but I am un ...

Leveraging TypeScript enums in conjunction with React to anticipate a string prop

Trying to enforce strict typing for a Button component in React. How can I ensure a prop has a specific string value? The current effort yields Type '"primary"' is not assignable to type 'ButtonLevel' enum ButtonLevel { Primary = ...

Mapping an array within an array and then pushing the result

I am facing a challenge with an empty array that I have: items: [ { item:null, category_id: null, } ] Can anyone help me figure out how to populate this empty array with the data? Here is an example of the data I have: ...

The elegant-admin template's mobile navigation toggle is missing

I recently downloaded an admin theme and added the CSS to my Django static files. However, after doing so, the mobile toggle feature disappeared. I double-checked all the CSS and JS links in the index template, and they are correctly linked to the paths, b ...

How to render in Express.js without overwriting HTML elements (such as <p> tags)

I am currently working on a project that resembles a blog and I have a requirement to display text without altering the HTML tags. ./app.js //app.js ... var text = 'Hello <b>World</b>' app.get('/', (req, res)=>{ res ...

Using a custom font with Next.js and Tailwind: Font applied successfully but not displaying correctly

In my project with Next.js (9.4.4) and Tailwind.css (1.4.6), I am incorporating a custom font named SpaceGrotesk. To ensure its functionality, I stored the font files in public/fonts/spaceGrotesk, and then adjusted my configurations as below: // next.confi ...

Obtaining the "match" object within a Custom Filter Selector on jQuery version 1.8

Here's a helpful resource on Creating a Custom Filter Selector with jQuery for your reference. A Quick Overview: If you're unfamiliar with jQuery's Custom Filter Selectors, they allow you to extend jQuery’s selector expressions by addi ...

Is there a way to retrieve the filename of a file uploaded using a shiny fileInput function?

This shiny app has a feature where users land on the 'Upload data' panel upon launching. To restrict access to the other two 'tabpanels', users must first upload both necessary files in the 'Upload data' tab. The condition for ...

"Trouble arises when dealing with nested object arrays in Formik and handling changes in a child

I am struggling with passing a value to handleChange in formik validation. To address this issue, I created a component whose quantity is dynamically added based on the number of numChild. My goal is to allow users to click an icon and add any number of sk ...

Validating Angular UI without requiring an input field (validating an expression)

Currently, I am utilizing ui-validate utilities available at https://github.com/angular-ui/ui-validate The issue I am facing involves validating an expression on a form without an input field. To illustrate, consider the following object: $scope.item = ...

Is there a way to track the amount a user scrolls once they have reached the bottom of a page using Javascript?

It's a popular UI pattern on mobile devices to have a draggable element containing a scrollable element. Once the user reaches the end of the scrollable content, further scrolling should transition into dragging the outer element. For example, in this ...

Vue modifies the array in the data after creating a duplicate of it

Here is the Vue code snippet I'm working with: export default { name: 'Test', data() { return { test1: ['1', '2', '3'], test2: [{ name: 'Hello' }, { name: &apo ...

Platform designed to simplify integration of high-definition imagery and scalable vector illustrations on websites

In the ever-evolving world of technology, some clients support advanced features like svg while others do not. With the rise of high resolution devices such as iPhone 4+ and iPad 3rd gen., it has become crucial to deliver graphics that can meet these stand ...

How to disable typescript eslint notifications in the terminal for .js and .jsx files within a create-react-app project using VS Code

I'm currently in the process of transitioning from JavaScript to TypeScript within my create-react-app project. I am facing an issue where new ESLint TypeScript warnings are being flagged for my old .js and .jsx files, which is something I want to avo ...

Initiate the Bull Queue Process upon launching the Application

As I develop my API, I am setting up a queue and adding jobs to it. Additionally, I have configured the API to start processing these jobs as soon as they are added. const newQueue = createQueue(queueName, opts); newQueue.add('JokesJob', data, o ...

Select either one checkbox out of two available options

My form includes two checkboxes, allowing users to click on both of them. I'm wondering if it's possible to set it up so that only one checkbox can be selected at a time. For example, clicking on the first checkbox would turn it on while turning ...

When the tooltip is re-rendered, the Vue slot activator causes my v-icon to refresh

I have a v-icon that is randomly assigned a color and I want to add a tooltip to it. The issue is that every time I hover over the v-icon, the color changes. How can I ensure that the color is only set one time and does not change with each hover? <v ...

Center both vertically and horizontally in Bootstrap UI Modal

I'm attempting to create a Bootstrap UI Modal that is centered both vertically and horizontally. While I found this solution that successfully centers the modal vertically, it loses its horizontal centering when applied to my own template with 800px ...