I'm attempting to create an extensible base model class that will allow for diffing between original and attributes so that I can create a getDirty() method on the child class that will diff between the objects orignal properties and any changed attributes. Here's the class so far:
import Vue from 'vue'
class Model {
constructor (attributes) {
this.original = attributes
this.attributes = attributes
Object.keys(this.attributes).forEach((property) => {
Object.defineProperty(this, property, {
get: () => this.getAttribute(property),
set: (value) => this.setAttribute(property, value)
})
})
}
getAttribute (key) {
return this.attributes[key]
}
setAttribute (key, value) {
this.attributes[key] = value
}
static fetchById (id) {
if (!id) {
throw new Error('Cannot fetch without id')
}
return Vue.prototype.$http
.get(this.endpoint + id)
.then(response => {
return new this(response.data)
})
.catch(error => {
console.error(error)
})
}
}
export default Model
With this code, I am creating an account by extending this Model with an Account model:
import Model from './Model'
import Vue from 'vue'
class Account extends Model {
static endpoint = '/api/accounts/'
getOwner () {
if (this.company_owner_uuid) {
return 'company'
}
return 'person'
}
getDirty = () => {
// This log is showing the changed name from the component input, rather than the original
console.log(this.original.person_owner.first_name)
const diff = Object.keys(this.original).reduce((diff, key) => {
if (this.attributes[key] === this.original[key]) return diff
return {
...diff,
[key]: this.original[key]
}
}, {})
return diff
}
update () {
return Vue.prototype.$http
.put(`${Account.endpoint}/${this.account_uuid}`, this.getDirty())
.then(response => {
console.log(response)
return response.data
})
.catch(error => {
console.error(error)
})
}
}
export default Account
And in my component:
Account.fetchById(this.id).then(account => {
this.account = account
})
.catch(error => {
console.error(error)
})
.then(() => {
// hide loading or whatever after promise is fully resolved...
})
This all works really so far aside from when I make a change to the account, it mutates both this.original and this.attributes. Does anyone have a recommendation for creating an immutable this.original version of the account object that is passed into the constructor that could then be used for comparison to the mutated attributes? My end goal here is to only send any modified attributes to the back-end (I'm using Laravel 5.8). Thanks!