<p>In the end I found a solution which doesn't require creating my own controller. I am not sure it is possible to post directly to the <code>$_FILES</code> array in Craft but by using the native <a href="https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData" rel="nofollow noreferrer">FormData</a> object in Javascript you can basically pass all the form fields in the correct format to the vue-resource post method. I found <a href="http://losstopschade.de/post/144063268923" rel="nofollow noreferrer">this article</a> useful on my search for solving what I needed. In doing this it kind of bypasses the Vue data model which is not exactly what I was after but it works well and keeps things simple. One caveat is that support for the FileData object is only on modern browsers but you can polyfill for older browsers.</p>

<p>Here is my final test form code:</p>

<pre class="lang-html prettyprint-override"><code>&lt;form method="post" action="" enctype="multipart/form-data" accept-charset="UTF-8" @submit.prevent="submitForm" id="imageForm"&gt;
  {{ getCsrfInput() }}
  &lt;input type="hidden" name="action" value="users/saveUser"&gt;
  &lt;input type="hidden" name="redirect" value="members/profile/{% include '_includes/helpers/user_profile_link' %}"&gt;
  &lt;input type="hidden" name="userId" value="{{ currentUser.id }}"&gt;

  {% if currentUser.photoUrl %}
    &lt;transition name="fade"&gt;
      &lt;img src="{{ currentUser.photoUrl }}" alt="{{ currentUser.fullName }}" v-if="showImage"&gt;
    &lt;/transition&gt;

    &lt;a href="#" id="userPhoto" v-on:click.prevent="deletePhoto" v-if="showImage"&gt;Delete&lt;/a&gt;

    &lt;input type="hidden" name="deleteUserPhoto" id="deleteUserPhotoInput" value="" v-model="user.deleteUserPhoto"&gt;

    &lt;div class="control"&gt;
      &lt;label for="avatar" class="label"&gt;Member Image&lt;/label&gt;
      &lt;input id="avatar" type="file" name="userPhoto"&gt;
    &lt;/div&gt;
  {% else %}
    &lt;div class="control"&gt;
      &lt;label for="avatar" class="label"&gt;Member Image&lt;/label&gt;
      &lt;input id="avatar" type="file" name="userPhoto"&gt;
    &lt;/div&gt;
  {% endif %}

  &lt;button type="submit" class="button is-primary"&gt;Save Profile&lt;/button&gt;
&lt;/form&gt;
</code></pre>

<p>Here is my final Vue.js code:</p>

<pre class="lang-js prettyprint-override"><code>Vue.http.options.emulateJSON = true;
Vue.http.options.emulateHTTP = true;

var app = new Vue({
  delimiters: ['@{', '}'],
  el: '#app',
  data: {
    user: {
      deleteUserPhoto: '',
      userId: '{{ currentUser.id }}',
      action: 'users/saveUser'
    },
    showImage: true
  },
  methods: {
    submitForm: function() {
      var form = document.getElementById('imageForm');
      var formData = new FormData(form);

      this.$http.post('/', formData)
        .then(function(response) {
          //this.updated = true;
        });
    },
    deletePhoto: function () {
      this.user.deleteUserPhoto = 'noMorePhoto';

      var data = this.user;

      data[window.csrfTokenName] = window.csrfTokenValue; // Append CSRF Token

      this.$http.post('/', data)
        .then(function(response) {
          this.showImage = false;
        });
    }
  }
});
</code></pre>

CC BY-SA 3.0
2017-02-24T06:33:35.030Z
2017-02-24T06:33:35.030Z
Gareth
<p>Following on from <a href="https://craftcms.stackexchange.com/questions/19061/updating-a-user-on-the-front-end-with-vue-js-and-axios">this question</a> I am now looking at adding, deleting and updating a user's image on the front end using Vue.js and vue-resource. I have the delete functionality working no problem but I am having an issue with how I add and upddate a users' image.</p>

<p>Here is my test form code:</p>

<pre class="lang-html prettyprint-override"><code>&lt;form method="post" action="" enctype="multipart/form-data" accept-charset="UTF-8" @submit.prevent="submitForm"&gt;
  {{ getCsrfInput() }}
  &lt;input type="hidden" name="action" value="users/saveUser"&gt;
  &lt;input type="hidden" name="redirect" value="/"&gt;
  &lt;input type="hidden" name="userId" value="{{ currentUser.id }}"&gt;

    &lt;div class="control"&gt;
      &lt;label for="avatar" class="label"&gt;Member Image&lt;/label&gt;
      &lt;input id="avatar" type="file" name="userPhoto"&gt;
    &lt;/div&gt;

  &lt;button type="submit" class="button is-primary"&gt;Save Profile&lt;/button&gt;
&lt;/form&gt;
</code></pre>

<p>Looking at the Craft log when you submit the form without Ajax it works successfully and this is the log:</p>

<pre><code>$_POST=array (
  'CRAFT_CSRF_TOKEN' =&gt; 'Vq_qS8xUX_Z0d09MHA_n3lFLCse3hLuc5Vx0sREE|b95a7c106acaa1e421d409d2eb708ac2beb18b96',
  'action' =&gt; 'users/saveUser',
  'redirect' =&gt; 'members/profile/gareth
',
  'userId' =&gt; '39',
)

$_FILES=array (
  'userPhoto' =&gt; 
  array (
    'name' =&gt; 'new-me.jpg',
    'type' =&gt; 'image/jpeg',
    'tmp_name' =&gt; '/Applications/MAMP/tmp/php/phpfDqUNQ',
    'error' =&gt; 0,
    'size' =&gt; 395885,
  ),
)
</code></pre>

<p>My main question is how do I submit to the <code>$_FILES</code> array using ajax? When I post my form using ajax I get the following Craft log:</p>

<pre><code>$_POST=array (
  'userPhoto' =&gt; 
  array (
    'name' =&gt; 'me.jpg',
    'type' =&gt; 'image/jpeg',
    'tmp_name' =&gt; '/Applications/MAMP/tmp/php/phpLha7Uh',
    'error' =&gt; '0',
    'size' =&gt; '117463',
  ),
  'deleteUserPhoto' =&gt; '',
  'userId' =&gt; '39',
  'action' =&gt; 'users/saveUser',
  'CRAFT_CSRF_TOKEN' =&gt; 'Vq_qS8xUX_Z0d09MHA_n3lFLCse3hLuc5Vx0sREE|b95a7c106acaa1e421d409d2eb708ac2beb18b96',
)
</code></pre>

<p>Is the only way to handle file uploads on the front end to create your own controller and work things out through that or can I set something within my ajax post that will add to the <code>$_FILES</code> array?</p>

<p>Here is my Vue.js code for review:</p>

<pre class="lang-js prettyprint-override"><code>Vue.http.options.emulateJSON = true;
Vue.http.options.emulateHTTP = true;

var app = new Vue({
  delimiters: ['@{', '}'],
  el: '#app',
  data: {
    user: {
      userPhoto: {
        'name': 'me.jpg',
        'type': 'image/jpeg',
        'tmp_name': '/Applications/MAMP/tmp/php/phpLha7Uh',
        'error': 0,
        'size': 117463
      },
      userId: '{{ currentUser.id }}',
      action: 'users/saveUser'
    },
  },
  methods: {
    submitForm: function() {

      var data = this.user;

      data[window.csrfTokenName] = window.csrfTokenValue; // Append CSRF Token

      this.$http.post('/', data)
        .then(function(response) {
          // success stuff here
        });
    }

  }
});
</code></pre>

<ajax><frontend><user-profile>
Update a user image on the front end using Vue.js and Ajax
# Update a user image on the front end using Vue.js and Ajax

(Asked by: username_0 on 2017-02-22)

Following on from this question I am now looking at adding, deleting and updating a user's image on the front end using Vue.js and vue-resource. I have the delete functionality working no problem but I am having an issue with how I add and upddate a users' image.
Here is my test form code:

  {{ getCsrfInput() }}
  
  
  

    
      Member Image
      
    

  Save Profile


Looking at the Craft log when you submit the form without Ajax it works successfully and this is the log:
$_POST=array (
  'CRAFT_CSRF_TOKEN' => 'Vq_qS8xUX_Z0d09MHA_n3lFLCse3hLuc5Vx0sREE|b95a7c106acaa1e421d409d2eb708ac2beb18b96',
  'action' => 'users/saveUser',
  'redirect' => 'members/profile/gareth
',
  'userId' => '39',
)

$_FILES=array (
  'userPhoto' => 
  array (
    'name' => 'new-me.jpg',
    'type' => 'image/jpeg',
    'tmp_name' => '/Applications/MAMP/tmp/php/phpfDqUNQ',
    'error' => 0,
    'size' => 395885,
  ),
)

My main question is how do I submit to the $_FILES array using ajax? When I post my form using ajax I get the following Craft log:
$_POST=array (
  'userPhoto' => 
  array (
    'name' => 'me.jpg',
    'type' => 'image/jpeg',
    'tmp_name' => '/Applications/MAMP/tmp/php/phpLha7Uh',
    'error' => '0',
    'size' => '117463',
  ),
  'deleteUserPhoto' => '',
  'userId' => '39',
  'action' => 'users/saveUser',
  'CRAFT_CSRF_TOKEN' => 'Vq_qS8xUX_Z0d09MHA_n3lFLCse3hLuc5Vx0sREE|b95a7c106acaa1e421d409d2eb708ac2beb18b96',
)

Is the only way to handle file uploads on the front end to create your own controller and work things out through that or can I set something within my ajax post that will add to the $_FILES array?
Here is my Vue.js code for review:
Vue.http.options.emulateJSON = true;
Vue.http.options.emulateHTTP = true;

var app = new Vue({
  delimiters: ['@{', '}'],
  el: '#app',
  data: {
    user: {
      userPhoto: {
        'name': 'me.jpg',
        'type': 'image/jpeg',
        'tmp_name': '/Applications/MAMP/tmp/php/phpLha7Uh',
        'error': 0,
        'size': 117463
      },
      userId: '{{ currentUser.id }}',
      action: 'users/saveUser'
    },
  },
  methods: {
    submitForm: function() {

      var data = this.user;

      data[window.csrfTokenName] = window.csrfTokenValue; // Append CSRF Token

      this.$http.post('/', data)
        .then(function(response) {
          // success stuff here
        });
    }

  }
});

**Tags:** ajax, frontend, user-profile


---

## 1 answers

### Answer by username_0 on 2017-02-24. Score: 0 | Accepted answer

In the end I found a solution which doesn't require creating my own controller. I am not sure it is possible to post directly to the $_FILES array in Craft but by using the native FormData object in Javascript you can basically pass all the form fields in the correct format to the vue-resource post method. I found this article useful on my search for solving what I needed. In doing this it kind of bypasses the Vue data model which is not exactly what I was after but it works well and keeps things simple. One caveat is that support for the FileData object is only on modern browsers but you can polyfill for older browsers.
Here is my final test form code:

  {{ getCsrfInput() }}
  
  
  

  {% if currentUser.photoUrl %}
    
      
    

    Delete

    

    
      Member Image
      
    
  {% else %}
    
      Member Image
      
    
  {% endif %}

  Save Profile


Here is my final Vue.js code:
Vue.http.options.emulateJSON = true;
Vue.http.options.emulateHTTP = true;

var app = new Vue({
  delimiters: ['@{', '}'],
  el: '#app',
  data: {
    user: {
      deleteUserPhoto: '',
      userId: '{{ currentUser.id }}',
      action: 'users/saveUser'
    },
    showImage: true
  },
  methods: {
    submitForm: function() {
      var form = document.getElementById('imageForm');
      var formData = new FormData(form);

      this.$http.post('/', formData)
        .then(function(response) {
          //this.updated = true;
        });
    },
    deletePhoto: function () {
      this.user.deleteUserPhoto = 'noMorePhoto';

      var data = this.user;

      data[window.csrfTokenName] = window.csrfTokenValue; // Append CSRF Token

      this.$http.post('/', data)
        .then(function(response) {
          this.showImage = false;
        });
    }
  }
});


---

