尝试刷新数据时的knockout.js绑定问题

时间:2014-01-08 05:52:26

标签: asp.net-mvc-4 knockout.js

我正在使用knockout.js数据绑定。在页面加载时,绑定工作正常,数据正确显示在页面上。然后我尝试将数据推送回数据库并推送成功。数据库接收数据OK。

当我尝试在推送成功时重新加载数据时出现问题。此时绑定已经发生一次(在页面加载时)。如果我不再绑定它,页面上的数据不会刷新。如果我再次进行绑定,knockout.js会发出错误“无法多次绑定”。如果我在重新绑定之前进行清理,则会收到错误“nodeType undefined”。 谁能告诉我在这里错过了什么?我正在使用带有knockout.js 3.0.0的ASP.NET MVC 4.0。

控制器:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcApplJSON.Controllers
{
    public class KnockoutController : Controller
    {
        //
        // GET: /Knockout/

        public ActionResult Index()
        {
            return View();
        }

        [HttpGet]
        public JsonResult GetProductList()
        {
            var model = new List<Product>();
            try
            {
                using (var db = new KOEntities())
                {
                    var product = from p in db.Products orderby p.Name select p;
                    model = product.ToList();
                }
            }
            catch (Exception ex)
            { throw ex; }
            return Json(model, JsonRequestBehavior.AllowGet);
        }
        // your controller action should return a JsonResult. There's no such thing as a controller action that returns void. You have specified dataType: 'json' so return JSON. That's it. As far as what parameter this controller action should take, well, from the JSON you are sending ({"Name":"AA"}) it should be a class that has a Name property of type string. 
        //  modify your action signature to look like this: [HttpPost] public ActionResult SaveProduct (Product product) { ... return Json(new { success = true }); }. Or get rid of this dataType: 'json' attribute from your AJAX request if you don't want to return JSON. In this case you could return simply status code 201 (Created with empty response body): return new HttpStatusCodeResult(201);.
        [HttpPost]
        public ActionResult SaveProduct(Product product)
        {
            using (var db = new KOEntities())
            {
                db.Products.Add(new Product { Name = product.Name, DateCreated = DateTime.Now });
                db.SaveChanges();
            }
            return Json(new { success = true });
        }
    }
}

查看:

@{
    ViewBag.Title = "Knockout";
}

<h2>Knockout</h2>
<h3>Load JSON Data</h3>
<div id="loadJson-custom" class="left message-info">
    <h4>Products</h4>
    <div id="accordion" data-bind='template: { name: "product-template", foreach: product }'>
    </div>
</div>

<h3>Post JSON Data</h3>
<div id="postJjson-custom" class="left message-info">
    <h4>Add Product</h4>
    <input id="productName" /><br />
    <button id="addProduct">Add</button>
</div>
@section Scripts {
    @Scripts.Render("~/bundles/knockout")
    @Scripts.Render("~/bundles/livequery")
    <script src="/Scripts/jquery.livequery.min.js"></script>
    <style>
        #accordion { width: 400px; }
    </style>
    <script id="product-template" type="text/html">
        <h3><a data-bind="attr: {href:'#', title: Name, class: 'product'}"><span data-bind="text: Name"></span></a></h3>
        <div>
            <p>Here's some into about <span data-bind="text: Name" style="font-weight: bold;"></span> </p>
        </div>
    </script>

    <script>
      var isBound;
        function loadJsonData() {
            $.ajax({
                url: "/knockout/GetProductList",
                type: "GET",
                contentType: "application/json",
                dataType: "json",
                data: {},
                async: true,
                success: function (data) {
                    var loadJsonViewModel = {
                        product: ko.observableArray(),
                        init: function () {
                            loadAccordion();
                        }
                    };
                    var a = $('loadJson-custom');
                    loadJsonViewModel.product = ko.mapping.fromJS(data);
                    if (isBound) { }
                    else
                    {
                      ko.applyBindings(loadJsonViewModel, $('loadJson-custom')[0]);
                      isBound = true;
                    }
                    loadJsonViewModel.init();
                }
            });
        }
        // push data back to the database
        function pushJsonData(productName) {
            var jData = '{"Name": "' + productName + '"}';
            $.ajax({
                url: "/knockout/SaveProduct",
                type: "POST",
                contentType: "application/json",
                dataType: "json",
                data: jData,
                async: true,
                success: function (data, textStatus, jqXHR) {
                  console.log(textStatus + " in pushJsonData: " + data + " " + jqXHR);
                  //ko.cleanNode($('loadJson-custom')[0]);
                    loadJsonData(); 

                },
                error: function (jqXHR, textStatus, errorThrown) {
                  alert(textStatus + " in pushJsonData: " + errorThrown + " " + jqXHR);
                }
            });
        }

        function loadAccordion() {
          $("#accordion > div").livequery(function () {
            if (typeof $("#accordion").data("ui-accordion") == "undefined")
            {
              $("#accordion").accordion({ event: "mouseover" });
            }
            else
            {
              $("#accordion").accordion("destroy").accordion({ event: "mouseover" });
            }
          });
        }

        $(function () {
          isBound = false;
            loadJsonData();
            $("#addProduct").click(function () {
                pushJsonData($("#productName").val());
            });
        });
    </script>
}

2 个答案:

答案 0 :(得分:1)

您在loadJsonData函数成功回调中声明了您的模型,&amp;在每个成功回调上创建新对象,在该函数外部移动模型,创建一个对象&amp;在loadJsonData函数中使用它,它将解决问题。

答案 1 :(得分:1)

以下是您问题的完整解决方案。 我刚刚实施并检查过。 请看看。

我创建了一个用于获取一些记录的类,即:Records.cs。

public static class Records
{
    public static IList<Student> Stud(int size)
    {
        IList<Student> stud = new List<Student>();

        for (int i = 0; i < size; i++)
        {
            Student stu = new Student()
                              {
                                  Name = "Name " + i,
                                  Age = 20 + i
                              };
            stud.Add(stu);
        }
        return stud;
    }
}

public class Student
{
    public string Name { get; set; }
    public int Age { get; set; }
}

这是相应视图的控制器。

//
    // GET: /HelpStack/
    private static IList<Student> stud = Records.Stud(10);
    public ActionResult HelpStactIndex()
    {
        return View();
    }

    [HttpGet]
    public JsonResult GetRecord()
    {
        return Json(stud, JsonRequestBehavior.AllowGet);
    }

    [HttpPost]
    public void PostData(Student model)
    {
        //do the required code here as All data is in "model"
    }

这是一个HTML视图,我有两个第一部分用于列表,另一部分用于添加记录

<div id="loadJson-custom">
<h4>Student</h4>
<table width="100%">
    <tr>
        <td style="width: 50%">
            <div id="accordion" data-bind='template: { name: "product-template", foreach: Student }'>
            </div>
        </td>
        <td valign="top">
            <div id="NewStudent">
                <input type="text" data-bind="value: Name" /><br />
                <input type="number" data-bind="value: Age" /><br />
                <input type="submit" data-bind="click: Save" value="AddNew" />
            </div>
        </td>
    </tr>
</table>

以下是Knockoutjs的脚本。

<script id="product-template" type="text/html">

    <h3><a data-bind="attr: { href: '#', title: Name, class: 'product' }"><span data-bind="    text: Name"></span></a>
        <br />
        Age: <span data-bind="text: Age"></span>
    </h3>
    <div>
        <p>Here's some into about <span data-bind="text: Name" style="font-weight: bold;"></span></p>
    </div>
</script>

<script type="text/javascript">
    //Model for insert new record
    var Model = {
        Name: ko.observable(''),
        Age: ko.observable(''),
    };

    var Student = ko.observableArray([]); // List of Students

    function loadData() { //Get records
        $.getJSON("/HelpStack/GetRecord", function (data) {
            $.each(data, function (index, item) {
                Student.push(item);
            });
        }, null);
    }

    function Save() { //Save records
        $.post("/HelpStack/PostData", Model, function () { //Oncomplete i have just pushed the new record.

            // Here you can also recall the LoadData() to reload all the records
            //Student.push(Model);
            Student.unshift(Model); // unshift , add new item at top

        });
    }
    $(function () {
        loadData();
        ko.applyBindings(Model, $('#NewStudent')[0]);
    });
</script>