0
votes

I am trying to populate knockoutjs viewmodel with some initial values from the server, I am using ASP.Net MVC so the way I am doing it is passing a mvc viewmodel to the view:

public ActionResult Edit(int cvId)
{
    CV cv = repository.FindCV(cvId);

    //auto mapper mapping
    Mapper.CreateMap<CV, MyCVViewModel>();
    Mapper.CreateMap<Company, MyCompanyViewModel>();
    Mapper.CreateMap<Education, MyEducationViewModel>();
    Mapper.CreateMap<Reference, MyReferenceViewModel>();
    var model = Mapper.Map<CV, MyCVViewModel>(cv);

    return View(model);
}

Inside the view I convert the viewmodel into json string and bind it to knockoutjs viewmodel, so it gets populated with data:

//mvc viewmodel
@model Taw.WebUI.Models.MyCVViewModel
//convert
@{
    var json = @Html.Raw(Model.ToJson());
}

//lastly bind
<script type="text/javascript">
    // Activate knockout binding
    var viewModel = new CVViewModel(@json);
    ko.applyBindings(viewModel);
</script>

and inside my knockout javascript, i populate knockout viewmodel with the data:

var CVViewModel = function (data) {
    var self = this;

    //list view model
    self.title = ko.observable(data.title);
    self.statement = ko.observable(data.statement);
    self.reference = ko.observable(data.reference);
    self.companies = ko.observableArray(data.companies);
    self.educations = ko.observableArray(data.educations);
    self.references = ko.observableArray(data.references);
}

Everything gets populated at this stage:

enter image description here

and the resulting json string is:

enter image description here

Questions:

1. The problem is that some values don't bind when I change them, only title and statement changes:

enter image description here

Resulting json, as you can see, only title and statement changes, and values inside company don't change enter image description here

2. When saving this data again, how can I let server side know what has been edited and what has been deleted, how to keep track of them using MVC and entity framework, and change database accordingly

Update

My knockout javascript, I already have these observables defined, how do define them in the observablearray

function Company() {
    this.companyName = ko.observable();
    this.jobTitle = ko.observable();
    this.description = ko.observable();
    this.startDate = ko.observable();
    this.endDate = ko.observable();
}
2

2 Answers

2
votes

For your first question:

The problem is you need to use ko.observable for each array item.

For example: jsfiddle

function CVViewModel(data) {
    var self = this;

    //list view model
    self.title = ko.observable(data.title);
    self.companies = ko.observableArray(data.companies.map(Company));
}

function Company(data) {
    if (!(this instanceof Company)){
        return new Company(data);
    }
    this.companyName = ko.observable(data.companyName || '');
    this.jobTitle = ko.observable(data.jobTitle || '');
    this.description = ko.observable(data.description || '');
    this.startDate = ko.observable(new Date(data.startDate) || '');
    this.endDate = ko.observable(new Date(data.endDate) || '');
}

Now when you bind the company observables to the UI each array element on the viewmodel will stay synced.

Regarding your second question I recommend using an ORM like breeze.js which does the change tracking for you. Breeze.js has a tutorial that uses knockout.js.

0
votes

The problem is that you are trying to update Items in the ObservableArray. where all ObservableArray does is to maintain the array model for you meaning if you add or remove something in your companies observable it will be reflected in the array. In order to make the changes in the array items, you need to make each item in your ObservableArray as Observable.

take a look at this post here: https://www.airpair.com/knockout/posts/top-10-mistakes-knockoutjs#8-observable-arrays-don-t-automatically-have-observable-members