Предельный выход нокаута

У меня есть этот нокаут, отображающий мой массив, полученный после вызова ajax ниже.

function InvoiceViewModel(data) {
var self = this;

self.survey = data;

}

Ajax Call

$.ajax({
    url: 'http://localhost:43043/api/damage',
    type: 'GET',
    headers: { 'Accept': 'application/json' },
    data: {
        orderNumber: num,
        category: cat
    },
    success:
           function (data) {
               var usingRoutData = document.URL;
               ko.applyBindings(new InvoiceViewModel(data));
           },

    error: function () {
        alert('failure');
    }

});

Мой массив

 var test = {
  Name: Blah,
  Attributes: [
               {Name: Test, Type: Photo, Year:1988},
               {Name: Test, Type: Photo, Year:1988},
               {Name: Test, Type: Photo, Year:1988}
              ]
            };

Как я привязываю свои данные

 <div id="invoiceBodyWrapper">
<div data-bind="template: { name: 'invoice-template', foreach: surveys }">
</div>

<div class="invoiceWrapper">
    </div>
    <div id="completePictureWrapper" data-bind="template: { name: 'photo-template',     foreach: new Array(Attributes) }"></div>

</div>
</script>

<script type="text/html" id="photo-template">
<!-- ko if: classification === 'photo' -->
<div id="pictureWrappers">
    <img class="img" data-bind="attr: { src: 'http://myimagepath/download/full/' +    $index()+1 }" />
</div>
<!-- /ko -->
 </script>
  <script src="~/Scripts/DamageInvoiceCreation.js"></script>

Мне нужен способ ограничить мои атрибуты foreach loop, чтобы показать только 2 из 3 атрибутов. Я только что нашел несколько вещей о том, как это сделать, и они кажутся очень сложными. Я не могу себе представить, что в нокауте нет простого способа сделать это.

Ответ 1

Если у вас всегда есть 3 атрибута, и вы всегда хотите показать только 2 из них, вам не нужно их точно отбирать.

Однако существует специальная переменная контекста привязки $index(), которая позволит вам сделать некоторое основное скрытие, хотя это не помешает рендерингу. Поскольку $index основан на 0, условие $index() < 2. Как замечает Андрей в комментариях, $index является наблюдаемым, поэтому вы должны называть его круглыми скобками как метод или сравнения, t делайте то, что вы ожидаете (вы будете сравнивать int с функцией).

<ul data-bind="foreach: survey.Attributes">
    <li data-bind="visible: $index() < 2">
        Name: <span data-bind="text: Name"> </span><br/>
        Type: <span data-bind="text: Type"> </span><br/>
        Year: <span data-bind="text: Year"> </span><br/>
    </li>
</ul>

Если вам нужен общий ограничитель в цикле foreach, вы правы, это не просто. Вам нужно будет сделать пользовательскую привязку.

Другим подходом, который вы можете рассмотреть, является предварительная обработка ваших данных в модели viewmodel. Когда вы устанавливаете this.survey = data;, вы можете удалить любой из атрибутов, которые вы не хотите отображать в этой точке.

Изменить: я вижу из вашего редактирования, что вы знаете о ko: if psuedo-elements. Я полностью забыл об этом, но вы можете легко использовать его, чтобы предотвратить отображение элементов шаблона шаблона за определенный индекс. foreach все равно будет оценивать наблюдаемое, которое не должно иметь никаких огромных накладных расходов.

Ответ 2

JavaScript-массивы включают отличный slice метод, который должен хорошо наполнить ваши потребности:

template: { name: 'photo-template', foreach: Attributes.slice(0,2) }

Но, как сказал Патрик-М, вам не нужен цикл:

template: { name: 'photo-template', data: Attributes[0] }
template: { name: 'photo-template', data: Attributes[1] }

My Repeat binding включает опцию для ограничения количества повторений:

<div data-bind="repeat: { foreach: Attributes, count: 2 }"
      data-repeat-bind="template: { name: 'photo-template', data: $item() }">
</div>

Ответ 3

Вы можете создать вычисление с ограниченным пределом массива:

var limited = ko.computed( function() {
   return Attributes.slice(0, limit);
});

Затем все, что вам нужно сделать, чтобы ограничить доступ к foreach. Вы даже можете добавить элемент some more:

<!-- ko if: Attributes().length > limit -->
    <div class="more">...</div>          
<!--/ko-->

Я надеюсь, что это будет полезно для последующих поколений;)

Ответ 4

вы можете ограничить цикл таким образом:

for(var i=0;i<data.length;i++){
   if(i>1){
      return false;
   }
}

Ответ 5

Я решил аналогичную проблему, нажав подмножество исходных элементов массива на другой массив в моей модели viewmodel, а затем привязку к массиву подмножеств.