2014-01-08 53 views
0

我正在使用knockout.js數據綁定。在頁面加載時,綁定工作正常,數據正確顯示在頁面上。然後,我嘗試將數據推回到數據庫,並且推送成功。數據庫接收數據OK。嘗試刷新數據時knockout.js綁定問題

問題出在我試圖在推送成功時重新加載數據。這時綁定已經發生過一次(在頁面加載時)。如果我不再綁定,頁面上的數據不會刷新。如果我再次執行綁定,則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> 
} 
+0

不要綁定多次 - 只需刷新您的淘汰賽模型。你可以自動做到這一點:通過使用ko.mapping.fromJS(newViewModel)和手動vm.myProperty(newValue); – VikciaR

回答

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> 
+0

謝謝developersatish以及所有回答我問題的人。我非常感謝你的幫助。我終於消化了這些建議和代碼。你太棒了。 – Shawn

1

您聲明loadJsonData功能成功回調內部模型,&每個成功回調創建新的對象,將這一職能外的模型,創建一個對象&在loadJsonData函數中使用它,它會解決這個問題。