使用 knockout 将 List 绑定到 Viewmodel

Binding a List to a Viewmodel using knockout

我是 MVC 和 Knockout 以及 JS 的新手。 我正在尝试使用 Knockout 显示提供者列表。 我有以下代码来获取提供者列表

        public ActionResult Index()
       {
            Provider providerList = new Provider();
            IList<Provider> providers = DAL.GetListofProviders.ToList();
            return View(providers);
       }

我有以下观点

   @model List<DEMO_JAN14.Models.Provider>
   @{
       Layout = "~/Views/Shared/_Layout.cshtml";
    }
 <head>
     <title>LIST OF PROVIDERS</title>
 </head>
 <body>
      <table class="table table-striped table-bordered table-hover">
    <tr>     
        <th>Provider Type</th>
        <th>First Name</th>
        <th>Last Name</th>
        <th>Certification</th>
        <th>Specialization</th>
        <th>SSN</th>
        <th>Facility Name</th>
        <th>Contact No</th>
        <th>Contact Email</th>
        <th></th>  
    </tr>

<tbody data-bind="foreach:viewmodel">
  <tr>
        <td class="col-lg-2" data-bind="text: ProviderType"></td>
        <td class="col-lg-1" data-bind="text: FirstName"></td>
        <td class="col-lg-1" data-bind="text: LastName"></td>
        <td class="col-lg-1" data-bind="text: Certification"></>
        <td class="col-lg-1" data-bind="text: Specialization"></td>
        <td class="col-lg-1" data-bind="text: SSN"></td>
        <td class="col-lg-4" data-bind="text: FacilityName"></td>
        <td class="col-lg-4" data-bind="text: ContactNumber"></td>
        <td class="col-lg-1" data-bind="text: ContactEmail"></td>
        <td><a class="btn btn-danger" id="del" onclick = "return confirm('Are you sure, you want to delete');" data-bind="attr: { href: '/Provider/Delete/' + ProviderID }"> Delete </a>
        </td>
    </tr> 
</tbody>           
  </table>
  </body>

我已经编写了一个脚本来将模型数据转换为 Json 数据。

  <script type="text/javascript">
    $.ajax({
       url: '/Provider/jsonview',
       dataType: "json",
    type: "GET",
    contentType: 'application/json; charset=utf-8',
    async: false,
    processData: false,
    cache: false,
    success: function (data) {
        viewmodel = ko.utils.parseJson(data);
        ko.applyBindings(viewmodel);
    },
    error: function (xhr) {
        alert('error');
    }
});
  </script>

我在controller里写了jsonview action

     public ActionResult jsonview()
    {
        Provider providerList = new Provider();
        List<Provider> providers = DAL.GetListofProviders.ToList();
        var json = JsonConvert.SerializeObject(providers);
        return Json(json, JsonRequestBehavior.AllowGet);
    }

但是 table 没有显示 providers.Could 的列表,你们指引我正确的方向吗?

我在 _layout 页面中引用了一个 JS 文件 "Additional Scripts",如图所示。

       <link rel="stylesheet" href="../../Content/bootstrap-theme.min.css"/>
       <link rel="stylesheet" href="../../Content/bootstrap.min.css"/>

       <title>@ViewBag.Title</title>
       @Styles.Render("~/Content/css")
       @Scripts.Render("~/bundles/modernizr")

     <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
     <script type="text/javascript" src="../../Scripts/bootstrap.min.js"></script>
      <script type="text/javascript" src="../../Scripts/jquery-2.1.3.min.js"></script>
      <script type="text/javascript" src="../../Scripts/jquery.unobtrusive-ajax.min.js"></script>
      <script type="text/javascript" src="../../Scripts/jquery.validate.min.js"></script>
      <script type="text/javascript" src="../../Scripts/knockout-3.2.0.js"></script>


    </head>
    <body>
        @RenderBody()
     <script type="text/javascript" src="../../Scripts/AdditionalScripts.js"></script>
      </body>
      </html>

JS文件中的代码如图所示

    $(document).ready(function () {

//alert("document ready");

var Provider =
          {
              ProviderID: ko.observable(""),
              ProviderType: ko.observable(""),
              FirstName: ko.observable(""),
              LastName: ko.observable(""),
              Certification: ko.observable(""),
              Specialization: ko.observable(""),
              SSN: ko.observable(""),
              ContactNumber: ko.observable(""),
              ContactEmail: ko.observable(""),
              FacilityName: ko.observable(""),
          }
              ko.applyBindings(Provider);

//A function to check if all the fields have been filled before posting the form.
function ValidatethisForm() {
    if (Provider.ProviderType() === "")
        return false;
    else if (Provider.FirstName() === "")
        return false;
    else if (Provider.LastName() === "")
        return false;
    else if (Provider.Certification() === "")
        return false
    else if (Provider.Specialization() === "")
        return false;
    else if (Provider.ContactNumber() === "")
        return false;
    else if (Provider.ContactEmail() === "")
        return false;
    else if (Provider.FacilityName() === "")
        return false;
    else
        return true;
   }

   //Post the form on clicking the Submit Button.
    $("#Submit").on("click", function () {
    if (ValidatethisForm()) {
        $.ajax({
            type: "POST",
            url: "/Provider/Create",
            data: Provider
        });
    }
    });

$("#ProviderType").blur(function () {
    if ($('#ProviderType :selected').text() == "Select a Provider Type")
        alert("Please choose a Provider");
     });

   //Scripts for the First Name
      $("#FirstName").blur(function () {
    if ($(this).val().trim().length == 0) {
        $(this).addClass('borderclass');
        $("#Err_FirstName").show();
    }
    else {
        $("#Err_FirstName").hide();
        $(this).removeClass('borderclass');
    }
          });

     $("#FirstName").focusin(function () {
    if ($("#Err_FirstName").is(":visible"))
        $(this).addClass('borderclass');
});

$("#FirstName").keydown(function (event) {
    //$("#Err_FirstName").hide();
    //var inputVal = $(this).val();
    //var reg = /^[A-Za-z]+$/
        });

//Scripts for the Last Name
$("#LastName").blur(function () {
    if ($(this).val().trim().length == 0) {
        $(this).addClass('borderclass');
        $("#Err_LastName").show();
    }
    else {
        $("#Err_LastName").hide();
        $(this).removeClass('borderclass');
    }
         });

      $("#LastName").keypress(function () {
    //$("#Err_LastName").hide();
          });

     //Scripts for the Certification
      $("#Certification option:selected").blur(function () {
    if ($('#Certification :selected').text() == "Select a Certification")
        alert("Please choose a Certification");
         });

     //Scripts for the Specialization
        $("#Specialization option:selected").blur(function () {
        if ($('#Specialization :selected').text() == "Select a Specialization")
        alert("Please choose a Specialization");
         });

     //Scripts for SSN
     $("#SSN").blur(function () {
       if ($(this).val().trim().length == 0) {
        $("#Err_SSN").show();
        $(this).addClass('borderclass');
    }
      else {
        $("#Err_SSN").hide();
        var SSN = $(this).val();
        $(this).val(SSN.substring(0, 3) + "-" + SSN.substring(3, 5) + "-" + SSN.substring(5));
        $(this).removeClass('borderclass');
    }
       });

   $("#SSN").keypress(function () {
    //$("#Err_SSN").hide();
     });

   //Scripts for the Facility Name
     $("#FacilityName").blur(function () {
       if ($(this).val().trim().length == 0) {
        $("#Err_FacName").show();
        $(this).addClass('borderclass');
    }
      else {
        $("#Err_FacName").hide();
        $(this).removeClass('borderclass');
    }
       });

   $("#FacilityName").keypress(function () {
      //$("#Err_FacName").hide();
      });

      //Scripts for the Contact Number
      $("#ContactNumber").blur(function () {
     if ($(this).val().trim().length == 0) {
        $("#Err_ContactNum").show();
        $(this).addClass('borderclass');
    }
    else {
        $("#Err_ContactNum").hide();
        var ContactNum = $(this).val();
        $(this).val("(" + ContactNum.substring(0, 3) + ")" + ContactNum.substring(3, 6) + "-" +      ContactNum.substring(6));
        $(this).removeClass('borderclass');
    }
      });

     $("#ContactNumber").keypress(function () {
    //$("#Err_ContactNum").hide();
     });

//Scripts for the Email Address
     $("#EmailAddress").blur(function () {
    if ($(this).val().trim().length == 0) {
        $("#Err_EmailAddress").show();
        $(this).addClass('borderclass');
    }
    else {
        $("#Err_EmailAddress").hide();
        var re = /^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
        var email = $('#EmailAddress').val();
        $(this).removeClass('borderclass');
        if (!re.test(email)) {
            $("#Err_EmailAddress").show();
            $(this).addClass('borderclass');
        }
    }
    });

    $("#EmailAddress").keypress(function () {
    //$("#Err_EmailAddress").hide();
    });

      //$(function () {
     //    $('#SuccessMessage').delay(2000).fadeOut(500);
    //});
     })

     function onlyAlphabets(evt) {
   var charCode;
   if (window.event)
    charCode = window.event.keyCode;  //for IE
   else
    charCode = evt.which;  //for firefox
  if (charCode == 32) //for &lt;space&gt; symbol
    return false;
if (charCode > 31 && charCode < 65) //for characters before 'A' in ASCII Table
    return false;
if (charCode > 90 && charCode < 97) //for characters between 'Z' and 'a' in ASCII Table
    return false;
if (charCode > 122) //for characters beyond 'z' in ASCII Table
    return false;
return true;
      }

      function onlyNumbers(evt) {
var charCode;
if (window.event)
    charCode = window.event.keyCode;   //if IE
else
    charCode = evt.which; //if firefox
if (charCode > 31 && (charCode < 48 || charCode > 57))
    return false;
return true;
    }

      function validateEmail() {
var re = /^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
var email = $('#EmailAddress').val();
return re.test(email)
        }

您不需要手动序列化提供程序,尝试 return 原始数据,JsonResult 会处理序列化。

return Json(DAL.GetListofProviders.ToList(), JsonRequestBehavior.AllowGet);

还有其他错误,比如 - 你不需要重新创建和重新绑定你的 viewModel - 你不需要解析结果

var viewmodel = {
    providers: ko.observableArray()
};
ko.applyBindings(viewmodel);

$.ajax({
 url: '/Provider/jsonview',
   dataType: "json",
   type: "GET",
   contentType: 'application/json; charset=utf-8',
   success: function (data) {
      viewmodel.providers(data);        
   },
   error: function (xhr) {
     alert('error');
   }
 });

Working JsFiddle

为了使其正常工作,您需要将模型绑定到敲除。所有数据都已传递到视图,因此您无需执行 AJAX 请求

控制器代码:

public ActionResult Index()
{
    Provider providerList = new Provider();
    IList<Provider> providers = DAL.GetListofProviders.ToList();
    return View(providers);
}

视图接收 IList 类型的模型

查看代码:

@model List<DEMO_JAN14.Models.Provider>
@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<head>
    <title>LIST OF PROVIDERS</title>
</head>
<body>
<table class="table table-striped table-bordered table-hover">
    <tr>     
        <th>Provider Type</th>
        <th>First Name</th>
        <th>Last Name</th>
        <th>Certification</th>
        <th>Specialization</th>
        <th>SSN</th>
        <th>Facility Name</th>
        <th>Contact No</th>
        <th>Contact Email</th>
        <th></th>  
    </tr>
<tbody data-bind="foreach: viewModel"> <-- Bind it to the viewModel
<tr>
    <td class="col-lg-2" data-bind="text: ProviderType"></td>
    <td class="col-lg-1" data-bind="text: FirstName"></td>
    <td class="col-lg-1" data-bind="text: LastName"></td>
    <td class="col-lg-1" data-bind="text: Certification"></>
    <td class="col-lg-1" data-bind="text: Specialization"></td>
    <td class="col-lg-1" data-bind="text: SSN"></td>
    <td class="col-lg-4" data-bind="text: FacilityName"></td>
    <td class="col-lg-4" data-bind="text: ContactNumber"></td>
    <td class="col-lg-1" data-bind="text: ContactEmail"></td>
    <td><a class="btn btn-danger" id="del" onclick = "return confirm('Are you sure, you want to delete');" data-bind="attr: { href: '/Provider/Delete/' + ProviderID }"> Delete </a>
    </td>
      </tr> 
    </tbody>           
</table>

并且在脚本部分,确保将模型从控制器绑定到淘汰赛 viewModel: 编辑:就像 Max 建议的那样,您不需要 AJAX 调用,您可以这样做

<script type="text/javascript">
    var data = @Html.Raw(Json.Encode(Model));
    var viewModel = ko.mapping.fromJS(data);
    ko.applyBindings(viewModel);
</script>

希望这对您有所帮助。