如何使用knockoutjs中的嵌套视图模型执行动态添加,删除和保存

时间:2015-02-12 00:24:52

标签: c# asp.net-mvc mvvm knockout.js

在MVC中,您可以使用以下视图模型:

public class MyCVViewModel
{
    [Required]
    [StringLength(100, ErrorMessage = "Resume Title cannot exceed 100 characters.")]
    [Display(Name = "Resume Title")]
    public string ResumeTitle { get; set; }
    [Required]
    [StringLength(1000, ErrorMessage = "Personal Statment cannot exceed 1000 characters.")]
    [Display(Name = "Personal Statement")]
    public string Statement { get; set; }

    public List<MyCompanyViewModel> Companies { get; set; }
}

public class MyCompanyViewModel
{
    [Required]
    [StringLength(100, ErrorMessage = "Company Name cannot exceed 100 characters.")]
    [Display(Name = "Company Name")]
    public string CompanyName { get; set; }
    [Required]
    [StringLength(100, ErrorMessage = "Job Title cannot exceed 100 characters.")]
    [Display(Name = "Job Title")]
    public string JobTitle { get; set; }
    [Required]
    [DataType(DataType.Date)]
    [Display(Name = "Start Date")]
    public DateTime JobStartDate { get; set; }
    [Required]
    [DataType(DataType.Date)]
    [Display(Name = "End Date")]
    public DateTime JobEndDate { get; set; }
    [Required]
    [StringLength(1000, ErrorMessage = "Job Description cannot exceed 1000 characters.")]
    [Display(Name = "Job Description")]
    public string JobDescription { get; set; }
}

MyCVViewModel有一个MyCompanyViewModel列表,这非常简单。

我开始学习knockoutjs并尝试在knockoutjs中复制相同的视图模型。

这是我到目前为止所尝试的内容:

//company viewmodel
function Company(data) {
    this.name = ko.observable(data.name);
    //other stuff
}

//cv view model
function CVViewModel() {
    var self = this;

    self.title = ko.oberservable();
    self.statement = ko.oberservalbe();
    //list of company view model
    self.companies = ko.observableArray();

    //add company
    self.addCompany = function () {
        self.companies.push({
            name: ""
        });
    };

    //remove company
    self.removeCompany = function (company) {
        self.companies.remove(company);
    };

    //populate with json
    $.getJSON("/Class/FillCompany", function (allData) {
        var mappedTasks = $.map(allData, function (item) { return new Company(item) });
        self.companies(mappedTasks);
    });
};

// Activate knockout binding
ko.applyBindings(new CVViewModel());

添加和删除工作正常,但我不知道如何保存整个cv viewmodel并将其发布到asp.net mvc中的控制器。

大多数在线教程发布了子视图模型(在我的公司公司列表中)并将其发布到服务器但不发布到父视图模型(在我的情况下是cvviewmdoel)。

所以在我看来,我只能将公司发布到服务器:

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    <textarea name="companies" data-bind="value: ko.toJSON(companies)"></textarea>
    <button type="submit">Save</button>
}

在我的控制器中我希望有一系列公司:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index([FromJson] IEnumerable<Company> companies)
{
    //save to database etc..
}

如何发布整个父视图模型,以便我的控制器看起来更像:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(MyCVViewModel cv)
{
    //save to database etc..
}

其中MyCVViewModel已包含公司列表。

1 个答案:

答案 0 :(得分:2)

通过在客户端进行一些编程,您可以完成这项工作。

首先,您可能希望节省一些时间,除非您需要使用ko.mapping

无法通过订阅者处理每个公司的内容。
ko.mapping.fromJS(allData, {} self.companies)

此外,在添加新公司时,您需要将其保持为可观察状态,因此请使用:

self.companies.push(new Company(name));

您可以将整个模型标题和子项作为json对象发送,以匹配您的服务器端对象。

因此,请将您的视图模型更改为以下内容:

function viewModel()
{
   var self = this;

   self.title = ko.oberservable();
   self.statement = ko.oberservalbe();
   //list of company view model
   self.companies = ko.observableArray();

   //add company
   self.addCompany = function () {
      self.companies.push(new Company(name));
   };

   //remove company
   self.removeCompany = function (company) {
       self.companies.remove(company);
   };

   //populate with json
   $.getJSON("/Class/FillCompany", function (allData) {
       ko.mapping.fromJS(allData, {} self.companies)
   });

   //save
   saveModel = function(){
        var data = ko.mapping.toJS(self);
        $ajax({
        url: 'Class/SaveCompany',
        type: 'POST',
        contentType: 'application/json',
        dataType: 'json',
        data: data,
        success: function (data, textStatus, jqXhr) {
           //do success stuff here.
        }

   }

然后在提交时,将您的点击事件绑定到视图模型保存事件,它将发送一个父模型,其中所有子项都作为单个表单发布。

希望这有帮助。