mitomed
mitomed

Reputation: 2066

Update knockout viewmodel when uploading documents via ajax

I'm trying to use knockout for a view where I'm uploading documents and showing a list. For this I'm using jquery.form.js in order to upload them using ajax. I've changed that to use knockout and my viewmodel looks like this

var ViewModel = function (groups) {
    var self = this;

    self.groups = ko.observableArray(ko.utils.arrayMap(groups, function (group) {
        return {
            planName: ko.observable(group.Key),
            documentList: ko.observableArray(ko.utils.arrayMap(group.Values, function (value) {
                return {
                    document: ko.observable(new Document(value))
                };
            }))
        };
    }));

    var options = {
        dataType: 'json',
        success: submissionSuccess
    };

    self.add = function () {
        $('#addForm').ajaxSubmit(options);
        return false;
    };

    function submissionSuccess(result) {
        alert('success');
    }
};

Having one Document function for doing the mapping. I'm stuck when receiving the Json data from the controller. The result is correct, a list of objects in the same format I'm receiving on first load but I don't know how to "refresh" the viewmodel to use this new list.

Don't know if using the ko mapping plugin would make it easier as I have never used it and don't even know if it's applicable for this.

The controller method, in case is relevant, is this (if something else neede let me know althoug won't have access to the code in the next hours)

[HttpPost]
public ActionResult AddDocument(AddDocumentViewModel viewModel)
{
    var partyId = Utils.GetSessionPartyId();

    if (viewModel.File.ContentLength > Utils.GetKBMaxFileSize * 1024)
        ModelState.AddModelError("File", String.Format("The file exceeds the limit of {0} KB", Utils.GetKBMaxFileSize));

    if (ModelState.IsValid)
    {
        _documentsManager.AddDocument(viewModel, partyId);

        if (Request.IsAjaxRequest())
        {
            var vm = _displayBuilder.Build(partyId);
            return Json(vm.Documents);
        }

        return RedirectToAction("Index");
    }

    var newViewModel = _createBuilder.Rebuild(viewModel, partyId);
    return PartialView("_AddDocument", newViewModel);

}

Thanks

EDIT: I came up with this code which seems to work (this function is inside the ViewModel one

function submissionSuccess(result) {
    self.groups(ko.utils.arrayMap(result, function (group) {
        return {
            planName: ko.observable(group.Key),
            documentList: ko.utils.arrayMap(group.Values, function (value) {
                return {
                    document: new Document(value)
                };
            })
        };
    }));
};

Upvotes: 1

Views: 538

Answers (1)

Joan Charmant
Joan Charmant

Reputation: 2031

Are you sure the documentList and document need to be observables themselves ?

To update the list you can push to it as you'd do on a regular array. You could try something like this:

function submissionSuccess(result) {
  self.groups.removeAll();

  $.each(result, function(index, value) {
    var documentList = [];

    $.each(value.Values, function(index, value) {
      documentList.push(new Document(value));
    });

    var group = {
      planName:value.Key,
      documentList: documentList
    };

    self.groups.push(group);
  });
};

Upvotes: 1

Related Questions