2012-04-18 2 views
0

제목이 다음과 같이 작성되었습니다. ko.observableArray 유형의 속성에 객체를 추가하면 knockoutjs가보기를 업데이트합니다.knockoutjs가 뷰 모델을 다시 바인드 한 후 UI가 깨졌습니다.

보기 업데이트 후 왼쪽에서 약 100 픽셀의 여백이 발생합니다. 그리고 놀랍게도 마우스 왼쪽 버튼으로 전체보기를 선택하면보기 수정 및 왼쪽 여백 영향이 사라집니다. 그런데 IE 8에서 이런 일이 발생합니다.

크롬에서도 같은 일이 발생했습니다. 어떻게 든 왼쪽 여백이보기에 적용됩니다. 반대로 이번에는 이전의 pharagraph에서 설명한대로보기를 선택해도 문제가 해결되지 않습니다.

jquery에 관한 내용 일 수도 있지만 확실하지 않습니다.

아래보기와 뷰 모델을 볼 수 있습니다 (다소 복잡합니다). 또한 문제와 관련된 스크린 샷 (IE8)을 넣었습니다.

내가 Enter 키를 누르 전에 "http://img560.imageshack.us/img560/6598/minqbeforeenter.png"

를 Enter 키를 히트 후 "http://img221.imageshack.us "나는 마우스 leftclick로 선택하면

을"/img221/1905/minqafterenter.png http://img689.imageshack.us/img689/882/minqafterselect.png "

내가 사용하고 스크립트를 (텍스트 상자에서 Enter 키를 누르면 AdvancedSearchControlViewModel의 searchValue_keydown 메소드가 작동 중임)

function SearchControlViewModel(context) { 
    var normalizeSelectItems = function (selectItems) { 
     var normalizedItems = []; 

     if (!(selectItems && $.isArray(selectItems) && selectItems.length > 0)) 
      return normalizedItems; 

     for (var index = 0; index < selectItems.length; index++) { 
      var item = selectItems[index]; 
      if (item.Items && $.isArray(item.Items)) { 
       if (item.Items.length <= 0) 
        continue; 
       var group = { Value: item.Value, Description: item.Description }; 
       for (var index2 = 0; index2 < item.Items.length; index2++) { 
        var subItem = item.Items[index2]; 
        normalizedItems.push(new SelectItem({ Value: subItem.Value, Description: subItem.Description, Group: group })); 
       } 
      } else { 
       normalizedItems.push(new SelectItem({ Value: item.Value, Description: item.Description, Group: { Description: ''} })); 
      } 
     } 

     return normalizedItems; 
    }; 
    var normalizedSelectItems = normalizeSelectItems(context.SelectItems); 
    context.SelectedValues = normalizeSelectItems(context.SelectedValues); 
    $.each(context.SelectedValues, function (selectedIndex, selectedItem) { 
     var selItem; 
     $.each(normalizedSelectItems, function (selectIndex, selectItem) { 
      if (selectItem.Value === selectedItem.Value) { 
       selItem = selectItem; 
       return false; 
      } 
     }); 
     if (selItem) { 
      context.SelectedValues[selectedIndex] = selItem; 
     } 
    }); 

    var self = this; 

    self.allOptions = 'All'; 

    self.selectItems = ko.observableArray(normalizedSelectItems); 

    self.searchContext = new SearchContext(context); 

    self.DropDownCheckList = function (elements) { 

     $('select', elements).dropdownchecklist({ 
      firstItemChecksAll: true, 
      forceMultiple: true, 
      onItemClick: function (checkBox, originalSelect) { 
       var selectedItem; 
       for (var selectedItemIndex = 0; selectedItemIndex < originalSelect.options.length; selectedItemIndex++) { 
        if (originalSelect.options[selectedItemIndex].value === checkBox.val()) { 
         selectedItem = originalSelect.options[selectedItemIndex]; 
         break; 
        } 
       } 
       selectedItem.selected = checkBox.attr('checked') === 'checked'; 
      }, 
      maxDropHeight: 300, 
      width: 250, 
      emptyText: 'Please Select...' 
      /*, 
      textFormatFunction: function (options) { 
      return 'Filtre'; 
      }*/ 
     }); 
    }; 

    self.Validate = function() { 
     var check; 

     check = self.searchContext.searchValue(); 
     if (check === null || check === undefined || 
      check === '') 
      return false; 

     check = self.searchContext.selectedItems(); 
     if (check === null || check === undefined || 
      !$.isArray(check) || check.length === 0) 
      return false; 

     var hasAtLeastOneItem = false; 
     $.each(check, function (index) { 
      if (check[index]) { 
       hasAtLeastOneItem = true; 
       return false; 
      } 
     }); 

     return hasAtLeastOneItem; 
    }; 

    self.GetConvertedJSONObj = function() { 
     var obj = { 
      SelectedValues: [], 
      SearchValue: self.searchContext.searchValue() 
     }; 

     var selectedItems = self.searchContext.selectedItems(); 
     if (selectedItems) { 
      for (var i = 0; i < selectedItems.length; i++) { 
       var selItem = selectedItems[i]; 
       if (selItem === null || selItem === undefined) 
        continue; 

       var pushArray; 
       if (selItem.Group.Description !== '') { 
        var group = undefined; 
        $.each(obj.SelectedValues, function (index, item) { 
         if (item.Items && $.isArray(item.Items)) { 
          if (item.Value === selItem.Group.Value) { 
           group = item; 
           return false; 
          } 
         } 
        }); 
        if (group === undefined) { 
         pushArray = []; 
         obj.SelectedValues.push({ 
          Value: selItem.Group.Value, 
          Items: pushArray 
         }); 
        } else { 
         pushArray = group.Items; 
        } 

       } else { 
        pushArray = obj.SelectedValues; 
       } 

       pushArray.push({ 
        Value: selItem.Value 
       }); 
      } 
     } 

     return obj; 
    }; 
    self.ConvertToJSON = function() { 
     var obj = self.GetConvertedJSONObj(); 

     return JSON.stringify(obj); 
    }; 
} 
function SearchContext(context) { 
    var self = this; 

    self.selectedItems = ko.observableArray(context.SelectedValues); 

    self.searchValue = ko.observable(context.SearchValue); 
} 
function SelectItem(context) { 
    var self = this; 

    self.Value = context.Value; 
    self.Text = context.Description; 
    self.Group = context.Group; 
} 

function SearchFilter(context) { 
    var self = this; 

    var getSelectedItemsDescription = function (selectedItems) { 
     var text = ''; 
     var selectedValues = context.template.searchContext.selectedItems(); 
     for (var i = 0; i < selectedValues.length; i++) { 
      var selectedValue = selectedValues[i]; 

      text += selectedValue.Text; 
      if (i + 1 < selectedValues.length) 
       text += ', '; 
     } 

     return text; 
    }; 
    self.selectedValuesDescription = getSelectedItemsDescription(
     context.template.searchContext.selectedItems() 
    ); 

    self.searchValueText = context.template.searchContext.searchValue(); 

    self.filterCombineType = context.defaultCombineType.key; 

    self.GetConvertedJSONObj = function() { 
     var obj = context.template.GetConvertedJSONObj(); 
     obj.CombineType = self.filterCombineType; 

     return obj; 
    }; 
    self.ConvertToJSON = function() { 
     var obj = self.GetConvertedJSONObj(); 

     return JSON.stringify(obj); 
    }; 
} 
function AdvancedSearchControlViewModel(context) { 
    var self = this; 

    self.SearchControlViewModelTemplate = ko.observable(new SearchControlViewModel(context.data.TemplateSearch)); 

    // key , value 
    self.SearchFilterCombineTypes = []; 
    for (var ct in context.data.SearchCombineTypes) { 
     self.SearchFilterCombineTypes.push({ key: ct, value: context.data.SearchCombineTypes[ct] }); 
    } 

    self.searchFilters = []; 
    if ($.isArray(context.data.Searchs) && context.data.Searchs.length > 0) { 
     for (var i = 0; i < context.data.Searchs.length; i++) { 
      var search = context.data.Searchs[i]; 
      var searchFilter; 
      $.each(self.SearchFilterCombineTypes, function (index, element) { 
       if (element.key === search.CombineType.toString()) { 
        searchFilter = element; 
        return false; 
       } 
      }); 

      search.SelectItems = context.data.TemplateSearch.SelectItems; 

      self.searchFilters.push(
       new SearchFilter({ template: new SearchControlViewModel(search), defaultCombineType: searchFilter }) 
      ); 
     } 
    } 
    self.searchFilters = ko.observableArray(self.searchFilters); 

    self.addSearchFilter = function() { 
     if (self.SearchControlViewModelTemplate().Validate()) { 
      self.searchFilters.push(new SearchFilter({ template: self.SearchControlViewModelTemplate(), defaultCombineType: self.SearchFilterCombineTypes[0] })); 
      self.SearchControlViewModelTemplate(new SearchControlViewModel(context.data.TemplateSearch)); 
     } 
    }; 

    self.searchValue_keydown = function (sender, event) { 
     if (event.keyCode === $.ui.keyCode.ENTER) { 
      // Code block to prevent submit 
      /*var fnDontSubmit = function() { 
      $(this).unbind('submit', fnDontSubmit); 
      return false; 
      }; 
      $(event.currentTarget.form).bind('submit', fnDontSubmit);*/ 

      self.SearchControlViewModelTemplate().searchContext.searchValue(event.srcElement.value); 
      self.addSearchFilter(); 
     } 
     return true; 
    }; 

    self.iButton = function (elements, bindings) { 
     var boundSearchFilter = bindings; 

     var elem = $(elements).filter('[type="checkbox"]'); 

     if (boundSearchFilter.filterCombineType === self.SearchFilterCombineTypes[1].key) 
      elem.attr('checked', 'checked'); 
     else 
      elem.removeAttr('checked'); 

     elem.iButton({ 
      labelOn: self.SearchFilterCombineTypes[1].value, 
      labelOff: self.SearchFilterCombineTypes[0].value, 
      change: function (sender, event) { 
       var selectedVal = self.SearchFilterCombineTypes[sender.is(':checked') ? 1 : 0]; 
       boundSearchFilter.filterCombineType = selectedVal.key; 
       // if you remove this line and 
       // make filterCombineType an observable 
       // the iButton animation wont work. So We're binding the checkbox manually. 
       ko.applyBindings(self, $('#' + context.valueId)[0]); 
      } 
     }); 

     var isLastElem = $(self.searchFilters()).last()[0] === boundSearchFilter; 
     if (isLastElem) 
      elem.iButton('disable'); 
    }; 

    self.ConvertToJSON = function() { 
     var jsonFilterArr = []; 
     for (var i = 0; i < self.searchFilters().length; i++) { 
      var searchFilter = self.searchFilters()[i]; 
      jsonFilterArr.push(searchFilter.GetConvertedJSONObj()); 
     } 

     return JSON.stringify({ 
      Searchs: jsonFilterArr 
     }); 
    }; 
} 

if (!$.data(document, "BindKnockoutjsControl")) { 
    $.data(document, "BindKnockoutjsControl", function (context) { 
     switch (context.controlType) { 
      case 'SearchControl': 

       var viewModel = new SearchControlViewModel(context.dataForViewModel); 

       ko.applyBindings(viewModel, $('#' + context.controlDisplayIdToBind)[0]); 
       ko.applyBindings(viewModel, $('#' + context.controlValueIdToBind)[0]); 

       break; 
      case "AdvancedSearchControl": 

       var viewModel = new AdvancedSearchControlViewModel({ data: context.dataForViewModel, valueId: context.controlValueIdToBind }); 

       ko.applyBindings(viewModel, $('#' + context.controlDisplayIdToBind)[0]); 
       ko.applyBindings(viewModel, $('#' + context.controlValueIdToBind)[0]); 

       break; 
      default: 
       throw 'Unknown controlType: ' + context.controlType; 
       break; 
     } 
    }); 
} 

나는 아래와 같이 searchValue_keydown 기능을 변경 한

<script id="AdvancedSearchControl_View" type="text/html"> 
    <table style="display:inline-block; width: 25%;"> 
     <thead data-bind="template: { name: 'SearchControl_View' }"> 
     </thead> 
     <tbody data-bind="template: { name: 'AdvancedSearchControlItem_View', foreach: $data.searchFilters }"> 
     </tbody> 
    </table> 
</script> 
<script id="SearchControl_View" type="text/html"> 
    <tr> 
     <td> 
      @Html.LabelFor(model => model.AdvancedSearchViewModel, new { @class = "SearchControlCaption" }) 
     </td> 
     <td></td> 
     <td></td> 
    </tr> 
    <tr> 
     <td style="padding-top:9px;"> 
      <select multiple="multiple" data-bind="options: SearchControlViewModelTemplate().selectItems, selectedOptions: SearchControlViewModelTemplate().searchContext.selectedItems, optionsText: 'Text', optionsGroup: function(item){return item.Group !== '' ? item.Group.Description : ''}, optionsCaption: SearchControlViewModelTemplate().allOptions"></select> 
     </td> 
     <td> 
      <input type="text" class="SearchValue" data-bind=" 
        value: SearchControlViewModelTemplate().searchContext.searchValue, 
        event: { 
         keydown: searchValue_keydown 
        } 
       " 
      /> 
     </td> 
     <td> 
      <input type="image" src="@Url.Content("~/Content/Images/" + Models.ResourceFiles.Resources._SearchButtonFileName)" 
       data-bind="enable: $data.searchFilters().length > 0" /> 
     </td> 
    </tr> 
</script> 
<script id="AdvancedSearchControlItem_View" type="text/html"> 
    <tr> 
     <td data-bind="text: $data.selectedValuesDescription"></td> 
     <td data-bind="text: $data.searchValueText"></td> 
     <td /> 
    </tr> 
    <tr> 
     <td data-bind="template: { name: 'AdvancedSearchControlItemRadios_View', afterRender: $root.iButton }"> 
     </td> 
     <td /> 
     <td /> 
    </tr> 
</script> 
<script id="AdvancedSearchControlItemRadios_View" type="text/html"> 
    <input type="checkbox" name="AndOr" /> 
</script> 
+0

많은 코드가 있습니다. jsfiddle에서 더 압축 된 데모를 만들 수 있습니까? 시작하려면이 예제를 포크하십시오. http://jsfiddle.net/madcapnmckay/bNSSq/ – madcapnmckay

+0

[가셔서] (http://jsfiddle.net/rebulanyum/VKdxZ/). 그러나 나는 거기에서 오류를 보지 못했다. – rebulanyum

답변

0

뷰;

self.searchValue_keydown = function (sender, event) { 
     if (event.keyCode === $.ui.keyCode.ENTER) { 
      self.SearchControlViewModelTemplate().searchContext.searchValue(event.currentTarget.value); 
      self.addSearchFilter(); 
      /* ADDED the code below to fix the issue; While knockoutjs updates */ 
      /* the ui but not forcing to apply css styles; thought I can update */ 
      /* the ui again by inserting into DOM again with dummy empty text. */ 
      /* And I succeded. */ 
      $('#' + context.displayId).append(' '); 
     } 
     return true; 
    }; 
관련 문제