2013-08-19 97 views
1

我用MVC4,jQuery和Twitter Boostrap開發了一個站點。現在我決定在一些頁面添加淘汰賽,以使工作流程更流暢。在這個特定的頁面上,我們的目的是在左邊有一個可以用jQuery UI可排序項目重新排序的項目列表。點擊後,每個項目的詳細信息將在右側的區域中顯示以進行編輯。根據類型的不同,編輯將會有很大的不同,所以我決定讓單獨的DIV標籤根據類型變得可見。敲除綁定不起作用

上一個工作版本通過模型加載頁面項目。我的想法是添加一個可觀察的數組到knockout viewmodel,然後在頁面加載時加載它。該模型在服務器上定義,所以我的意圖是不再在客戶端視圖模型上定義所有屬性。進一步的操作和編輯只需使用相同的集合,並通過AJAX調用將新/更改/刪除的值上傳到服務器。

我已經閱讀了淘汰賽演示和搜索類似useCases的stackoverflow。我認爲我遵循了這些建議,但顯然缺少某些東西。模型加載完好。項目打開並根據類型顯示不同的顏色。他們是可排序的,並且在度假方面,這些變化被髮回到服務器並且堅持不懈。

缺少的部分是顯示和編輯當前選定的項目。我添加了另一個名爲currentItem的屬性給viewmodel。在函數$(「body」)。on(「click」,「.sortableItem」)中,我可以驗證當前項是否已加載,並且標題屬性是否正確。

但DIV divEditType1的可見性和內容不受影響。?我有沒有誤解的結合概念有我誤解了從服務器JSON數組裝載任何幫助表示最欣賞

這是服務器頁面模型:

public class PresentationItemsModel 
{ 
    public Guid PresentationId { get; set; } 
    public string DisplayName { get; set; } 
    public List<PresentationItemModel> PresentationItems { get; set; } 
} 

這是重複的項目模型:

public class PresentationItemModel 
{ 
    public Guid PresentationItemId { get; set; } 
    public string PresentationItemType { get; set; } 
    public int OrderNumber { get; set; } 
    public string Heading { get; set; } 
    public string Content { get; set; } 
    .... 
} 

這是客戶端頁面(不相關的部分去掉):

@model MyCustomWeb.Models.PresentationItemsModel 

<header> 
    <h2>@Model.DisplayName</h2> 
</header> 

<div style="float: left;"> 
    <fieldset> 
     <legend>Current list</legend> 
     <ul id="sortable" data-bind="foreach: presentationItems"> 
      <li class="sortableItem btn btn-block" data-bind="css: 'sortable' + PresentationItemType + 'Item'"> 
       <div style="font-weight: 500;"> 
        <span data-bind="text: Heading"></span> 
        <span class="ui-icon ui-icon-arrowthick-2-n-s" style="display: inline-block; color: gray; float: right; opacity: 0.5; height: 14px; margin: 2px 4px 0 0"></span> 
       </div> 
      </li> 
     </ul> 
    </fieldset> 
</div> 

<div id="divEditType1" data-bind="visible: currentItem.PresentationItemType == 'Type1'" style="float: left; margin-left: 50px;"> 
    <fieldset> 
     <legend>Edit Type 1</legend> 
     <div class="control-group"> 
      <input type="text" data-bind="value: currentItem.Heading" placeholder = "Enter Heading" /> 
     </div> 
     <div class="control-group"> 
      <button id="btnSave" type="submit" class="btn btn-primary">Save</button> 
      <button id="btnDelete" type="submit" class="btn btn-danger">Delete</button> 
     </div> 
    </fieldset> 
</div> 

<div id="divEditType2" data-bind="visible: currentItem.PresentationItemType = 'Type2'" style="float: left; margin-left: 50px;"> 
</div> 

<div id="divEditType3" data-bind="visible: currentItem.PresentationItemType = 'Type3'" style="float: left; margin-left: 50px;"> 
</div> 


@section Scripts { 
    <script> 
     $(document).ready(function() { 

      // Enable item sorting 
      $("#sortable").sortable(
       { 
        cursor: "move", 
        placeholder: "sortableSeparator", 
        update: function() { 
         // Create array of all changed items 
         var changeItems = []; 
         var currentOrderNumber = 1; 
         $(".sortableItem").each(function() { 
          var id = $(this).attr('data-id'); 
          var previousOrderNumber = $(this).attr('data-orderNumber'); 
          if (currentOrderNumber != previousOrderNumber) 
           changeItems.push({ "id": id, "orderNumber": currentOrderNumber }); 
          currentOrderNumber += 1; 
         }); 
         // Send ajax action 
         $.ajax({ 
          type: "PUT", 
          url: "/api/PresentationApi/ChangeOrder/" + "@Model.PresentationId", 
          contentType: 'application/json; charset=utf-8', 
          data: JSON.stringify(changeItems) 
         }); 
        }, 
       } 
      ); 

      // Enable change depending on item click 
      // Note: Must be done this way beacuse of the dynamic binding! 
      $("body").on("click", ".sortableItem", function() { 
       viewModel.currentItem = ko.dataFor(this); 
       alert(viewModel.currentItem.Heading); // Works fine! 
       //alert(JSON.stringify(viewModel.currentItem)); // Also looks good! 
      }); 



      // Knockout view model 
      function ViewModel() { 
       var self = this; 
       self.presentationItems = ko.observableArray([]); 
       self.currentItem = ko.observable(); 
      } 

      var viewModel = new ViewModel(); 
      viewModel.presentationItems(@Html.Raw(Json.Encode(Model.PresentationItems))); 
      ko.applyBindings(viewModel); 
     }); 
    </script> 
} 

編輯: 創建一個小提琴演示的嘗試可以在這裏找到: http://jsfiddle.net/XXNz9/

+0

你可以發佈@ Html.Raw(Json.Encode(Model.PresentationItems))的結果json嗎?你能製作一個能夠再現探針的小提琴嗎? – Damien

+0

我不習慣小提琴,但我試圖在一個例子中重現這種情況。同樣的例子創建一個列表時,我的VS2012上下文執行,但在小提琴我甚至沒有得到... http://jsfiddle.net/XXNz9/ 也許你可以找到一些明顯的錯誤? –

+0

jsFiddle似乎是一個有用的工具,這是有意義的學習。但我很困惑。有一個下拉框,我可以選擇在示例中添加Knockout或jQuery。這是否意味着我不能兼得? –

回答

1

我建議你來包裝你「divEditType1」與另一個div。內div的背景將變爲「CURRENTITEM」所以你你不需要每次

<div data-bind="with: currentItem"> 
    <div id="divEditType1" data-bind="visible: PresentationItemType = 'Type1'" style="float: left; margin-left: 50px;"> 
     <fieldset> 
      <legend>Edit Type 1</legend> 
      <div class="control-group"> 
       <input type="text" data-bind="value: Heading" placeholder = "Enter Heading" /> 
      </div> 
      <div class="control-group"> 
       <button id="btnSave" type="submit" class="btn btn-primary">Save</button> 
       <button id="btnDelete" type="submit" class="btn btn-danger">Delete</button> 
      </div> 
     </fieldset> 

    </div> 
</div> 

這也可以解決你的問題,因爲你的綁定,如果當應用

CURRENTITEM == NULL可以不寫
+0

謝謝。良好的做法,但在我的例子中沒有什麼不同。 –

+1

@JakobLithner您正在以錯誤的方式設置** selectedItem **。你需要設置一個可觀察的值'viewModel.currentItem(ko.dataFor(this));'而不是通常的賦值 – demkalkov

+0

謝謝!就是這麼簡單...我愚蠢的是我對設定值的警覺檢查,這實際上是正確的。我想我摧毀了可觀察的變體,並通過設置錯誤的方式使它變爲靜態的?你有關於如何調試挖空代碼的建議嗎? –