Modifying deeply nested properties in Vue.js

Within my Vue.js application, I've created a method to update the src attribute of images whenever a file is chosen from a file input field. This method is triggered like so:

<input type="file" accept=".jpg,.png" @change="updateSrc($event, 'profile.photo.path')">
<img :src="profile.photo.path">

Here is the implementation of the method:

let app = new Vue({
    el: "#app",
    data: {
        profile: {
            photo: {
                path: "images/profile/no-photo.png"
            },
        }
    },
    methods: {
        updateSrc: function (event, srcPropertyName) {
            let reader = new FileReader();

            reader.onload = readerEvent => {
                srcPropertyName.split(".").reduce((previousValue, currentValue, index, array) => {
                    if (index === array.length - 1) {
                        previousValue[currentValue] = readerEvent.target.result;
                    }

                    return previousValue[currentValue];
                }, this);
            };

            reader.readAsDataURL(event.target.files[0]);
        },
    },
});

While this method works flawlessly, I've been contemplating whether there is a simpler way to update a nested property in Vue.js without resorting to tricks like using array.reduce(). Is there a more straightforward approach to achieve this?

app.$set("profile.photo.path", "james.jpg");

It's clear that the above code snippet won't work. So, I'm left wondering if there is a direct solution to this.

Answer №1

Perhaps consider utilizing a callback function in this scenario.

new Vue({
  el: "#app",
  data: {
    profile: {
      photo: {
        path: "images/profile/no-photo.png"
      },
    }
  },
  methods: {
    changeSrc(event, callback) {
      const reader = new FileReader();

      reader.onload = readerEvent => {
        callback(readerEvent.target.result);
      };

      reader.readAsDataURL(event.target.files[0]);
    }
  }
});
<script src="//unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <input type="file" accept=".jpg,.png" @change="changeSrc($event, (newValue) => profile.photo.path = newValue)">
  <img :src="profile.photo.path">
</div>

Answer №2

You have ingeniously developed a functionality that enhances the basic behavior of an element, resembling a utility function. However, this function is not truly a utility function as it can only be applied to that specific type of element. Essentially, you have created a widget: an element that is extended to possess custom behavior which can be utilized repeatedly. To optimize your solution, the best approach would be to convert it into a component. By doing so, you will be able to utilize v-model for the source name or .sync for a customized attribute name.

Whether the img should be included in the widget template or not remains unclear in your scenario.

new Vue({
  el: "#app",
  data: {
    profile: {
      photo: {
        path: "images/profile/no-photo.png"
      },
    }
  },
  components: {
    readerThing: {
      template: '#reader-thing-template',
      props: ['src'],
      methods: {
        updateSrc() {
          const reader = new FileReader();

          reader.onload = readerEvent => {
            this.$emit('update:src', readerEvent.target.result);
          };

          reader.readAsDataURL(event.target.files[0]);
        }
      }
    }
  }
});
<script src="//unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <reader-thing :src.sync="profile.photo.path"></reader-thing>
  <img :src="profile.photo.path">
</div>

<template id="reader-thing-template">
   <input type="file" accept=".jpg,.png" @change="updateSrc">
</template>

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

Firefox compatibility issue with Angular JS for downloading excel files

I've encountered an issue with my AngularJS code for downloading an Excel file. While it works smoothly in Chrome and Internet Explorer, it fails to function in Firefox. The server response isn't presenting any problems. Here's the code snip ...

A step-by-step guide on accessing a JSON configuration file and configuring the parameter for AJAX requests

I have a configuration file named server.json which contains server details in JSON format. { "server": "127.0.0.1" } My objective is to retrieve the value of 'server' from this configuration file and use it in my jQuery functions. For exa ...

Utilize Set.Attribute prior to entering the for loop

Could someone please clarify why I am unable to declare the var node before the for loop and then simply use appendChild(node) inside the loop? Why is it necessary to declare it for each iteration in order for it to affect all div elements? Otherwise, it w ...

Trigger the parent method by submitting a form when the child emits an event in Vue 2

In my project, I have a structure where App.vue acts as the parent container. Inside App.vue, there is a form element. This form contains a child component called UserInfo.vue, which in turn includes another child component named BaseButton.vue. Within th ...

I believe I may be experiencing an issue with the use of 'style.display' in JavaScript

I'm encountering a small issue. I need a button to reveal more content. Therefore, I require a way to hide this content initially and display it upon clicking, with the ability to reverse this action by hiding it again. Despite my efforts, the conten ...

Django Vue3 encounters access-control-allow-origin restriction

I am currently working on a Django rest-api project that uses Vue on the front-end. Unfortunately, I encountered an error while making requests via Vue: Console output: The following error is displayed: Access to XMLHttpRequest at 'https://api.iyziw ...

Unable to access property 'hasAttribute' of null value

I'm experiencing an issue with Material Design Bootstrap. I installed it using NPM, but when I visit my website, I encounter the following error: Uncaught TypeError: Cannot read property 'hasAttribute' of null at r (app.js:19116) at ...

Place 4 divs within 2 divs, with one aligned to the left and the other to the right

I'm currently working on a small project using Angular 2 for an experiment, where I need to place 4 divs, each containing an image, within 2 divs. However, all the divs (with images) are stacked vertically instead of being placed next to each other, ...

Encountering an issue with React Redux and Typescript involving the AnyAction error while working on implementing

While integrating redux-persist into my React project, I encountered an error. Previously, Redux was working smoothly, but upon the addition of redux-persist, I started receiving this error message: Types of property 'dispatch' are incompatib ...

Filter an array containing objects within objects and use the reduce method to calculate the total value

Here is an array of objects that I'm working with: const data = [ { "order_id":38795, "order_type":"Music", "date":"2021-08-14", "name":"Concert ...

Using AngularJS to filter through multiple criteria within an ng-repeat loop

I need to filter the messages data to exclude certain messages based on the userid. For example, in the scenario below, only messages from Paul (userid: 11) & Kate (userid:12) are displayed. What I want to achieve is to filter out more than just one useri ...

Tips on how to show the image icon in place of the image name

Here is a code snippet for multiuploading images using Vue. Currently, the uploaded images are displayed by their file names. However, I am looking to enhance this functionality by displaying an image icon instead of the file name. If anyone knows how to ...

The onblur function is not being triggered

Recently, I encountered an issue while trying to invoke a JavaScript function onblur of a field. The main problems I faced were: 1) The popup inside the function call was triggered automatically during page load. 2) When attempting to access the functio ...

Identify the moment when a file is being uploaded in a web browser

Could someone guide me on how to use javascript/jQuery to determine if a file is being uploaded by the browser? If not, what is the typical approach for this? Or can I only detect if I am using my custom file uploader and not the browser's? Edit: I ...

Returning a JSON representation of a JavaScript object

In the process of working on a script, I encountered a situation where an $.ajax call had to invoke a function upon success, returning a JavaScript object in JSON format [object object]. However, despite being able to return a well-formatted string, access ...

Building Vertical Tabs with external JS for loading custom visuals

I am trying to figure out how to display the visuals I created in an alternate page within my Vertical tabs. The tabs are already styled, and I have omitted the CSS due to its length. The HTML file I am working with is test.html, and the visuals are in the ...

Using jQuery to replace the content of a div with a delay?

I am attempting to utilize jQuery to create a fade effect on an element, replace its innerHTML content, and then fade it back in once the new content has been added. I have successfully managed to replace the element's content using the .html() method ...

extract non-alphanumeric characters from an array of strings using javascript

I am trying to loop over an array of strings in JavaScript and remove special characters from elements that contain them. I have been successful in achieving this with individual strings, but I am facing some challenges when working with arrays of string ...

Error encountered while uploading image on django through jquery and ajax

Looking for help on posting a cropped image via Jquery and ajax. I've been trying to implement a solution from a question on cropping images using coordinates, but I'm facing issues with receiving the image on Django's end. The CSRF token an ...

Vue 3 required but not found as a peer dependency

Every time I execute npm list -g --depth=0 command in cmd, npm throws this error. +-- @vue/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="086b6461483c263d263e">[email protected]</a> +-- <a href="/cdn-cgi/l/emai ...