Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Having redudant data passed to an object makes it so the second reference of the same object is not updated #222

Open
JeffreyDevloo opened this issue Mar 8, 2018 · 0 comments

Comments

@JeffreyDevloo
Copy link

JeffreyDevloo commented Mar 8, 2018

Problem description

Updating a viewModel with a computed property from propertyA and propertyA at the same time ensures that either one will be fetched from the cache and it won't get updated

function DerivedViewModel(data) {
  var self = this;
  ko.mapping.fromJS(data, {}, self);
}

var mapping = {
  bundlemodels: {
    key: function(data) {
      return ko.utils.unwrapObservable(data.id)
    },
    create: function(options) {
      debugger
      return new DerivedViewModel(options.data)
    }
  }
}

function ViewModel(data) {
  var self = this;

  // Bundle is a JS object
  // Say we want to unpack the bundle data to create a list of viewmodels instead of creatng a viewmodel
  data = Object.assign(data, {
    'bundlemodels': self.extractFromBundle(data.bundle || {})
  })
  var vmData = Object.assign({
    bundle: {}
  }, data)
  ko.mapping.fromJS(vmData, mapping, self);
}
ViewModel.prototype = {
  /**
   * Return an Array of data from the bundledata to track all updates in an observableArray
   */
  'extractFromBundle': function(bundleData) {
    return Object.values(bundleData)
  },
  /**
   * Since the Object was created with the bundle extracted, the update flow should do the same
   * The issue here is that the bundle data contains the very same data as the items that would 
   * be extracted from it. This triggers the alreadyMapped line inthe updateViewModel of the ko.mapping
   * causing my mapped item not to be updated
   */
  update: function(data) {
    var self = this;
    data = Object.assign(data, {
      'bundlemodels': self.extractFromBundle(data.bundle || {})
    })
    ko.mapping.fromJS(data, self)
  }
}
var viewModelData = {
  bundle: {
    id1: {
      name: 'Amazing name',
      id: 'id1'
    },
    id2: {
      name: 'Amazing name2',
      id: 'id2'
    }
  }
}
var updatedViewModelData = {
  bundle: {
    id1: {
      name: 'Amazing name',
      id: 'id1'
    },
    id2: {
      name: 'Amazing namechanged',
      id: 'id2'
    }
  }
}
var initialViewModel = new ViewModel(viewModelData)
var updatedViewModel = new ViewModel(viewModelData)
updatedViewModel.update(updatedViewModelData)

Following my explanation:
updatedViewModel.bundle and updatedViewModel.bundlemodels contain the same data. When bundle is checked for updating: this model data is cached.
When updating the bundlemodels, it retrieves the cacheddata and says it no longer has to update it.
This leaves updatedViewModel behind with only one of the two properties being properly updated

Calling the update function:

  • Loops over the bundle object, makes everything observable and caches all these values within the simpleobject
  • Loops over the bundlemodels array, checks if the objects currently exist within the cache (it does, because the same model was applied for the bundle object) and it does not update the bundlemodels
    The reason for the 'computed' of the bundle object is to have an array with models that are persistent (checking on the key function). The bundle object can not be used to achieve this...

It is an issue that I'm currently facing in my code

Workaround:
The only solution for me is to skip making the bundle object observable. Specifying it within the copy array of the mapping solves my caching issue.

Other solution:
If you'd require both properties to be observable, the copy cannot be used. For that, you'd need to derive the other property from the copy of the original one (they won't reference the same instance then)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant