Use v-model to bind to a javascript class

Hi everyone,

I have got some generated code from https://openapi-generator.tech using the javascript generator. This generator has generated a model for me like this:

/**
 * The version of the OpenAPI document: 1.0
 *
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */

import ApiClient from '../ApiClient';

/**
 * The User model module.
 * @module model/User
 * @version 1.0
 */
class User {
    /**
     * Constructs a new <code>User</code>.
     * @alias module:model/User
     */
    constructor() { 
        
        User.initialize(this);
    }

    /**
     * Initializes the fields of this object.
     * This method is used by the constructors of any subclasses, in order to implement multiple inheritance (mix-ins).
     * Only for internal use.
     */
    static initialize(obj) { 
    }

    /**
     * Constructs a <code>User</code> from a plain JavaScript object, optionally creating a new instance.
     * Copies all relevant properties from <code>data</code> to <code>obj</code> if supplied or a new instance if not.
     * @param {Object} data The plain JavaScript object bearing properties of interest.
     * @param {module:model/User} obj Optional instance to populate.
     * @return {module:model/User} The populated <code>User</code> instance.
     */
    static constructFromObject(data, obj) {
        if (data) {
            obj = obj || new User();

            if (data.hasOwnProperty('id')) {
                obj['id'] = ApiClient.convertToType(data['id'], 'Number');
            }
            if (data.hasOwnProperty('name')) {
                obj['name'] = ApiClient.convertToType(data['name'], 'String');
            }
            if (data.hasOwnProperty('email')) {
                obj['email'] = ApiClient.convertToType(data['email'], 'String');
            }
        }
        return obj;
    }
}

/**
 * @member {Number} id
 */
User.prototype['id'] = undefined;

/**
 * @member {String} name
 */
User.prototype['name'] = undefined;

/**
 * @member {String} email
 */
User.prototype['email'] = undefined;



export default User;

I am able to use the generated User class in this way:

<template>
  ...
    <input v-model="user.name" />
    <input v-model="user.email" />
  ...
</template>

<script>
var Api = require('path/to/api')

export default {
  data () {
    return {
      user: { name: 'naam', email: 'mail' }  // for v-model binding
    }
  },
  methods: {
    submitForm () {
      var body = new Api.User() // create new User via Api and copy values from the user data property
      body.name = this.user.name
      body.email = this.user.email
     
      Api.createUser(body, (error, data, response) => {
        if (error) {
          this.$q.notify({ message: error, color: 'red' })
        } else {
          this.$q.notify({ message: data })
        }
      })
    }
  }
}
</script>

It would be very nice if I could use it this way:

<template>
  ...
    <input v-model="user.name" />
    <input v-model="user.email" />
  ...
</template>

<script>
var Api = require('path/to/api')

export default {
  data () {
    return {
      user: new Api.User()   // use model class from the Api
    }
  },
  methods: {
    submitForm () {
    
                            // I don't like to copy the values
      //var body = new Api.User()  
      //body.name = this.user.name
      //body.email = this.user.email

      body = user
      
      Api.createUser(body, (error, data, response) => {
        if (error) {
          this.$q.notify({ message: error, color: 'red' })
        } else {
          this.$q.notify({ message: data })
        }
      })
    }
  }
}
</script>

The attempt above does not work. When typing the name input the value will be cleared when the focus blurs. I think it is because it cannot bind to the Users field name.

Is something like this possible?

Thanks in advance

You could modifiy your API class.

You could remove those prototype properties

/**
 * @member {Number} id
 */
User.prototype['id'] = undefined;

/**
 * @member {String} name
 */
User.prototype['name'] = undefined;

/**
 * @member {String} email
 */
User.prototype['email'] = undefined;

and deliver any data through your constructor

   // The user object contains your email and name field
    constructor(user) { 
        User.initialize(user);
    }

Then you could provide your data in just one line

const body = new Api.User({ ...this.user })

Hi suben,

I don’t think you understand my question. The user class has got some generated fields like name and email. I would like to bind them to a v-model. I don’t think i is a good idea to modify any generated source.

Is it possible to bind the User class fields to a input v-model someway?

Hi,

I want to bind an input to a javascript class field.
Below I have got a template which prints the typed text using v-model="user.name"

I rather want to use the User class from the generated model. So instead of user: { name: 'name' } I want to use this user: new Api.User(). But, it doesn’t bind to the input: the typed value is not printed. Is it possible to use my generated User class somehow?

<template>
  <div>
    <p>Your name:</p>
    <input v-model="user.name" label="Name" />
    <p>You typed: {{ user.name }}</p>
  </div>
</template>

<script>
var Api = require('path/to/api')

export default {
  data () {
    return {
      user: { name: 'name' }  //  I don't want to initiate the user like this
      // user: new Api.User() //  I actually want to use this class. Is this possible somehow?
    }
  },
  mounted () {
    this.user.name = 'test'
  }
}
</script>

I think the problem may be because of

data () {
    return {
      user: new Api.User()   // use model class from the Api
    }
}

Maybe you can try with something like:

data () {
    return {
      user: {}
    },
    created() {
      this.user = new Api.User()   // use model class from the Api
    }
}

this way user should be initialized only once, and then if you need to reset the user object, you can call new Api.User() inside a method, for example in case of a click or something.

Hi Zeek,

Thanks for you suggestion, saddly it doesn’t work either.

I have made a single file test case. In this test case the ‘intital value’ goes to the input and the {{ user.name }}. But when typing in the input, the value does n’t update the {{ user.name }}.

<template>
  <div>
    <p>Your name:</p>
    <input v-model="user.name" label="Name" />
    <p>You typed: {{ user.name }}</p>

    <button @click="btnClick">test</button>
  </div>
</template>

<script>
// Dummy model class from Api
class User {

}
User.prototype['name'] = ''

export default {
  data () {
    return {
      user: {}
    }
  },
  created () {
    this.user = new User() // use model class from the Api
    this.user.name = 'initial value'
  },
  methods: {
    btnClick: function (event) {
      alert(this.user.name)
    }
  }
}
</script>

The button click method works fine. The inputed text gets alerted. Strange isn’t it?

I gave a look at -> https://vuejs.org/v2/guide/reactivity.html

my best bet is that user doesn’t have property name in the first place, so it is not reactive.

with this code in the created method it works

created() {
    var user = new User();
    for(let p in user){
      this.$set(this.user, p, user[p]);
    }

  }

not sure this is elegant though.

this should be an example: https://jsfiddle.net/nxbjc9vp/

Actually this is probably not a good solution as you’re not really assigning a js class to an object of your model, you’re more creatina a new object with the dame properties of that class.
The thing is: as far as I know a model should only expose data properties but in your class you’re probably exposing also methods. As of now I can’t think of a good solution, sorry.

Hi Zeek,

I think I understand it now.
When I create a class like this it works also:

class User {
    name = ''
    getName () {
      return this.name
    }
    setName (name) {
      this.name = name
    }
}
// User.prototype['name'] = ''

I also must remove User.prototype[‘name’] = ‘’.
So perhaps I should look for an other way of creating the model from our api.

Do you have any suggestions?
I now have used openapi-generator using the javascript generator.