Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

fercho's avatar

how to access the value of a file input in Vue?

I need to make a Required Computed property with a text field and an image field, but I cant access the value of that image field I tried

if (!this.title && !this.$$.image.value) return true;
and
if (!this.title && !this.$$.image.files) return true;

it works only for the title, but as soon I fill it the submit button gets activated, even if the image value is empty.

<input type="file" name="image" accept="image/*">
0 likes
16 replies
bobbybouwmann's avatar

You can find everything in the documentation: http://vuejs.org/guide/forms.htm

You probably need a data object first

var vm = new Vue({
    data: {
        firstName: '',
        lastName: ''
    },
    computed: {
        fullName: function () {
            return this.firstName + ' ' + this.lastName
        }
    }
})

And your form might look like this

<input type="text" v-model="firstName">
<input type="text" v-model="lastName">

Just read the documentation, that will make a lot clear for you!

fercho's avatar

@bobbybouwmann , Hello, My question involves an Image File because textfields are easy to trace, btw in http://vuejs.org/guide/forms.html isnt nothing about "Input Files" sadly. I didnt include the js thing because the important part would be an accessor to the Image (file) value

bobbybouwmann's avatar

You can simply do something like this

<div id="demo">
    <input type="text" v-model="text"> text: {{text}}

    <input type="file" v-model="file"> file: {{file}}
</div>
var vue = new Vue({
    el: '#demo',
  
    // default values
    data: {
        text: '',
        file: ''
    },

    ready: function() {
        // watch for file input on bootstrap
        this.watchFileInput();
    },
        
    methods: {
        watchFileInput: function() {
            // will notify a file input
            $('input[type="file"]').change(this.notifyFileInput.bind(this));
        },
        
        notifyFileInput: function(event) {
            var fileName = event.target.files[0].name;
            // update file name value
            this.file = fileName;
        }
    }
});
fercho's avatar

@bobbybouwmann Im trying to prevent In a Modal Form from data to be submitted with no content, check please this image http://postimg.org/image/ityvri59p/9cb09a80/ you will see a modal with 2 inputs, the text and the file. So I want a Computed property which checks if the two fields have been populated, If not the submit button will be disabled. My problem is when I try

computed:{
      blankInput:function(){
         if (!this.mensaje && !this.$$.slide.value) return true;
         return false;
      }

    },

only this.mensaje complies to check if the field has a value, the image input field is being ignored, like if it has a value, so the submit button is enabled, but as the image states, the image file has a "no file selected"

 <button type="submit" class="btn btn-primary" v-attr="disabled:blankInput">Crear</button>
thomaskim's avatar

@fercho I don't think you can use v-model for files. Here is a simple example that you can follow.

http://jsfiddle.net/s05ebqn0/

You listen for a "submit" event on the form. When a user tries to submit the form, we do a check to see if there is a file. If there is no file (length of 0), then you reject it by running e.preventDefault(). Otherwise, you don't have to do anything and let it submit. However, in the example above, I added an alert so you can see the differences.

fercho's avatar

@thomaskim , very good, it would be the solution to my problem, Because as far I can try

if (!this.$$.image.files.length ==0)
               return true;

doesnt work

if (!this.$$.image.files)
               return true;

doesnt work

if (!this.$$.image.files[0])
               return true;

doesnt work

Thank you for your help !!

thomaskim's avatar

If you look at my example, I used the v-el directive to register a reference to the input file element. As far as I can tell, you didn't do that.

fercho's avatar

I didnt, I just used the name of the file, which is the same as using v-el I think

fercho's avatar

I did with v-el but it is the same result.

thomaskim's avatar

It isn't the same, and without seeing any code or letting us know of the error you are getting, we can't help you any further.

  1. Register a reference to the dom element, which in this case is the input file type. I did that by using the v-el directive.
  2. Register a listener to the form so that we can listen for when the user submits the form. This was done by using the v-on directive and listening to the "submit" event. The v-on directive also specified the specific function that we will trigger, which I named "onSubmit".
  3. When the user does submit the form, we trigger the necessary function aka "onSubmit". We accept the event (notice the "e" argument that it accepts). Then, if there is no file, we trigger e.preventDefault() to prevent the form submission.
jimmck's avatar

This Blade implements a view form that is extended by Vue 1.0 Beta 4. The form cannot post unless BOTH long name and short name are filled.

@extends('coverage::layouts.coverage_category')
@section('cat-content')
    <div id="app-container">
        <h2>Coverage Categories</h2>

        <form name="form1" action="">
            <div id="select">
                <select v-model="selected" v-on:change="onListSelect" id="list_box" size="10">
                    <option v-for="opt in selectOptions" v-bind:value="opt">@{{opt.text}}</option>
                </select>
            </div>
            <div id="input-area">
                <div id="short-name">
                    Short Name:
                    <input v-model="shortName" v-on:change="textChange" lazy
                           type="text" id="shortName" class="req" maxlength="8" size="10">
                </div>
                <div id="long-name">
                    Long Name:
                    <input v-model="longName" v-on:change="textChange" lazy
                           type="text" id="longName" class="req" size="32" maxlength="30">
                </div>
                <div id="btns">
                    <button v-on:click="execCommand" class="btn" id="save">Save</button>
                    <button v-on:click="execClear" class="btn" id="clear">Clear</button>
                </div>
            </div>
        </form>
        <p>Short name: <strong>@{{shortName}}</strong></p>

        <p>Long name: <strong>@{{longName}}</strong></p>

        <p>Selected: <strong>@{{selected.value}}</strong></p>
    </div>
@stop

Here is the Vue model to control the Save/Update button.

    app = new Vue({
        el: '#app-container',

        data: {
            shortName: "",
            longName: "",
            selectOptions: [],
            selected: -1,
        },
        methods: {
            addOption: function (opt) {
                this.selectOptions.push(opt);
            },

            onListSelect: function (e) {
                fyi('selcted ' + this.selected.value);
                find(this.selected.value);
            },

            clearList: function () {
                this.selectOptions = [];
                this.selected = -1;
            },

            setShortName: function (name) {
                this.shortName = name;
            },

            setLongName: function (name) {
                this.longName = name;
            },

            getShortName: function () {
                return this.shortName;
            },

            getLongName: function () {
                return this.longName;
            },

            setSelected: function (s) {
                this.selected = this.selectOptions[s];
            },

            getSelected: function () {
                if (this.selected != -1) {
                    return this.selected.value;
                }

                return -1;
            },

            execCommand: function (e) {
                sqlBusy = true;
                if (e != undefined) {
                    e.preventDefault();
                }

                var postData = {
                    id: this.getSelected(),
                    shortName: this.getShortName().toUpperCase(),  // Each entry is a separate $_POST['id'] item on backend.
                    longName: this.getLongName().toUpperCase()
                };
                if (cmd == INSERT) {
                    url = 'create';
                } else if (cmd == UPDATE) {
                    url = 'update';
                }

                payLoad
                    //.setOnRecover(this.execCommand)
                    .setOnPayload(null)
                    .call(url, postData);
            },
            textChange: function (e) {
                //alert("on change...");
                controlButtons();
            },

            execClear: function (e) {
                if (e != undefined) {
                    e.preventDefault();
                }
                this.setShortName("");
                this.setLongName("");
                cmd = INSERT;
                setCmdButton(cmd);
                controlButtons();
                clearSelection();
                fieldShortName.focus();
            }
        }
    });

    btnClear.prop('disabled', true);
    btnSave.prop('disabled', true);
    //fyi("event setup...");

   $('.req').bind('keyup', function(event) {
        controlButtons();
    });
}

External Methods...

function requiredFields() {
    var count = 0;

    if (fieldShortName.val().length > 0)
    {
        ++ count;
        fieldShortName.css("border", "1px solid #00FF00");
    } else {
        fieldShortName.css("border", " 1px solid #FF0100");
    }

    if (fieldLongName.val().length > 0)
    {
        ++ count;
        fieldLongName.css("border", "1px solid #00FF00");
    } else {
        fieldLongName.css("border", "1px solid #FF0100");
    }

    return count;
}

function setBorderColors() {
    if (fieldShortName.val().length > 0)
    {
        fieldShortName.css("border", "1px solid #00FF00");
    } else {
        fieldShortName.css("border", " 1px solid #FF0100");
    }

    if (fieldLongName.val().length > 0)
    {
        fieldLongName.css("border", "1px solid #00FF00");
    } else {
        fieldLongName.css("border", "1px solid #FF0100");
    }

}

function clearSelection() {
    list.val("");
}

function controlButtons() {

    switch (requiredFields()) {
        case 1:
            btnClear.prop('disabled', false);
            btnSave.prop('disabled', true);
            break;
        case 2:
            btnClear.prop('disabled', false);
            btnSave.prop('disabled', false);
            break;
        default:
            btnClear.prop('disabled', true);
            btnSave.prop('disabled', true);
            break;
    }
}

function Option(t, v) {
    this.text = t;
    this.value = v;
};

// Lets snag some jQuery Selectors.
var cmdButton = $("#save");
var fieldShortName = $("#shortName");
var fieldLongName = $("#longName");
var btnClear = $('#clear');
var btnSave = $('#save');
var list = $("#list_box");

setCmdButton(INSERT);

// Set Network SQL flag to not busy.
var sqlBusy = false;

function msgPayload(p) {
    fyiMsg(p);
    index();
}

function errPayload(p) {
    fyiErr(p);
}

var that = this;

// Setup Vue Model

var app = null;

function setCmdButton(_cmd) {
    cmd = _cmd;
    cmdButton.text(cmdText[cmd]);
}


1 like
fercho's avatar

@thomaskim ,

I will try to explain, the problem but you can check the screen i sent http://postimg.org/image/ityvri59p/9cb09a80 Problem

  1. A modal Form is presented to the user for letting him/her fill the fields which are : MESSAGE, File (upload)
  2. The user only fills the text and submits the form with no image upload. My solution im willing to achieve. create a computed property which disables the submit button until the user has filled the 2 required fields with:
computed:{
      blankInput:function(){

         if (!this.mensaje && !this.$$.image.files)
               return true;

         return false;
      }

app.js.

  <input type="text" name="mensaje" id="mensaje" class="form-control" v-model="mensaje">
<input type="file" name="slide" accept="image/*" v-el="image"> //v-el added
 <button type="submit" class="btn btn-primary" v-attr="disabled:blankInput">Crear</button>

html

But. My solution doesnt work because the if statement isnt working because only the $this.mensaje is being tracked if it is or isnt populated, and the file, even if it doesnt have a file makes the Submit button to activate.

jekinney's avatar

What I do is the length check. Put on your post method have it check for errors. In your Laravel validation return a specific error for the file and then you can display the error issue with vue. I do that with any forms I submit with Ajax as a double check. Remember JavaScript is client side and validation should solely rely on JavaScript.

fercho's avatar

@jekinney Im coding that right now, because as @thomaskim gave me the answer, It made me realize I need a way to present an elegant response from server which would be all the errors commited by the user. Also if the text field wasnt supplied. Thank you for your comment.

Please or to participate in this conversation.