Updating Sub Properties in Knockout JS mapping plu

2019-07-20 13:44发布

I'm having an issue with knockout js and mapping plugin with a hierarchical view model

My viewmodel is structured somewhat like this:

VM = {
    members:[
        {
            name:"name 1",
            volunteering:[{...},{...},{...}]
        },
        {
            name:"name 1",
            volunteering:[{...},{...},{...}]
        }
    ]
}

Each member is in a tab, and each tab has a grid of volunteering activities. Clicking on an item in the grid pops up a dialog box to edit the volunteering activity. At this point I clone the object to facilitate 'cancel edit' functionality

var Volunteer = {};
var koContext=ko.contextFor(this);
Volunteer = ko.mapping.toJS(koContext.$data);  //plain js volunteer
Volunteer.index=koContext.$parent.EventVolunteers().indexOf(koContext.$data);  //index of volunteer in member volunteer array
ko.applyBindings(ko.mapping.fromJS(Volunteer),$("#dialog-EditVolunteer")[0]); //bind new volunteer obj to dialog

Up to this point seems ok, clicking save on the dialog causes the issue.

var volunteer = ko.mapping.toJS(ko.contextFor(this).$data);
ko.mapping.fromJS(volunteer,{},ko.contextFor(currentTab).$data.EventVolunteers()[volunteer.index]);

At this point the properties get updated in the viewmodel, but not in the grid on the main screen.

It appears ko.mapping.fromJS is replacing the observable rather than updating it.

3条回答
乱世女痞
2楼-- · 2019-07-20 14:11

My eventual solution in this case was to set the properties on the original VM, with the edited values from the 'cloned' viewmodel.

For new projects however, I now use a knockout plugin

查看更多
Fickle 薄情
3楼-- · 2019-07-20 14:18

I'm not certain I wholly understand exactly what you're doing.

But I was attempting to do undo functionality in a list of items, and I used this on the array:

observableArray.replace(newData, ko.mapping.fromJS(original))

I get the new data as an argument of the click handler.

When I store the original, I basically have this:

        //Dupe check
        self.undoCache.Emails.pop(jQuery.grep(self.undoCache.Emails, function (element, index) { return element.Id == data.Id(); })[0]);
        //Store original
        self.undoCache.Emails.push(ko.mapping.toJS(data));

The "Emails" are the objects I'm editing. I only store the original data, not the observable. That allowed me to use replace. I'm not certain how correct that is, per se, but canceling works for me.

查看更多
Anthone
4楼-- · 2019-07-20 14:21

Personally I'm a fan of creating models like so. The abstraction here just makes more sense.

function VolunteerInfo(data){
  var self = this;
  self.activitiesName = ko.observable(data.name);
  // any other info not all of it has to be mapped 
  // unless you plan on sending it back.
}
function MembersInfo(data){
  var self = this;
  self.name = ko.observable(data.name)// w.e it is labeled as under json
  self.volunteering = ko.observableArray([]);
  var mappedVolunteers = $.map(data.volunterring, function(item){
    var volunteer = new VolunteerInfo(item);
    return volunteer;
  });
  self.volunterring(mappedVolunteers);
}
function VM(){
  var self = this;
  self.members = ko.o
  var request = $.getJSON("webservice address");
  request.done(function () {
    var mappedMembers = $.map(data.volunterring, function(item){
      var member = new MemberInfo(item);
      return member;
    });
    self.members(mappedMembers);
  }
}
// apply bindings to VM ect ect.
查看更多
登录 后发表回答