2013-05-05 14 views
7

Używam szybkiego wyszukiwania jquery do przeszukiwania tabeli, która jest zapełniana przez pętlę foreach knockout. element quicksearch musi zostać zainicjowany po zakończeniu foreach. Próbowałem już kilku podejść, ale jak dotąd nie udało się.nokaut - wykonanie kodu po wyrenderowaniu ostatniego elementu

Próbuję użyć "afterRender", ale nie byłem w stanie określić, czy bieżący element jest ostatnim elementem w kolekcji, czy też próbowałem użyć bindingHandlers, ale w zamian otrzymałem kolekcję o długości 0. o długości 2005

tak:

  1. co jest najlepszym sposobem na znalezienie ostatniego elementu w pętli foreach?
  2. jaki jest najlepszy sposób wdrożenia go w tym konkretnym scenariuszu?

tu jest mój widok:

<tbody data-bind="foreach: containers"> 
     <tr> 
      <td><span data-bind="text: code"></span></td> 
      <td><span data-bind="text: typeName"></span></td> 
      <td><span data-bind="text: parentClient"></span></td> 
      <td><span data-bind="text: client"></span></td> 
      <td> 
       <a data-bind="attr: { onclick: deleteUrl }"> 
        <i class="icon-trash"></i>@delete </a> 
       | 
       <a data-bind="attr: { href: editUrl }"> 
        <i class="icon-edit"></i>@edit</a> 
       | 
       <a data-bind="attr: { href: qrUrl }" target="blank"> 
        <i class="icon-qrcode"></i> 
        @printQr 
       </a> 
      </td> 

     </tr> 
    </tbody> 

i tu jest mój kod nokaut:

function Container(data) { 
     var self = this; 
     self.id = ko.observable(data.Id); 
     self.code = ko.observable(data.Code); 
     self.typeName = ko.observable(data.TypeName); 
     self.parentClient = ko.observable(data.ParentClient); 
     self.client = ko.observable(data.Client); 
     self.deleteUrl = ko.computed(function() { 
      return "GetModal('/Containers/Delete/" + data.Id + "','containerModal');"; 
     }); 
     self.editUrl = ko.computed(function() { 
      return '/Containers/Edit/' + data.Id; 
     }); 

     self.qrUrl = ko.computed(function() { 
      return '/Qr/Index/10?entity=' + data.Id; 
     }); 
    } 
function ContainersViewModel() { 
     var self = this; 
     self.containers = ko.observableArray([]); 
     self.counter = ko.computed(function() { 
      return self.containers().length; 
     }); 

     $.getJSON("/Containers/Json", function (data) { 
      var containers = $.map(data, function (item) { 
       return new Container(item); 
      }); 

      self.containers(containers); 
     }); 

    }; 
    ko.applyBindings(new ContainersViewModel()); 

Dzięki wielkie!

Nir

Odpowiedz

4

Wiązanie opcję afterRender może zrobić to, czego szukasz foreach, część Sztuką jest, aby móc wiem, że ten element jest ostatni. Można to rozwiązać za pomocą podanych argumentów, jak pokazano w http://jsfiddle.net/n54Xd/.

Funkcja:

this.myPostProcessingLogic = function(elements, data) { 
    if(this.foreach[this.foreach.length-1] === data) 
     console.log("list is rendered"); 
}; 

zostanie wywołana dla każdego elementu, ale „jeśli” będzie upewnić się, że kod działa tylko dla ostatniego elementu.

+0

dzięki Ricardo !, próbowałem go, ale to wyrażenie: "this.foreach [this.foreach.length - 1] 'w th' if statement" zawsze jest niezdefiniowane. jakieś pomysły ? –

+0

mój zły - i przypadkowo napisałem funkcję tuż poza viewmodel (rano coś ..) dzięki! –

2

Spróbuj zasubskrybować ręcznie zmiany w tablicy. Używając subscribe otrzymasz powiadomienie o modyfikacji macierzy.

Jeśli subskrybujesz po wywołaniu applyBindings, otrzymasz powiadomienie po odświeżeniu widoku.

See fiddle

var ViewModel = function() { 
    var self = this; 

    self.list = ko.observableArray(); 

    self.add = function() { 
     self.list.push('Item'); 
    } 
    self.list.subscribe(function() { 
     alert('before'); 
    }); 
}; 
var vm = new ViewModel(); 
ko.applyBindings(vm); 

vm.list.subscribe(function() { 
    alert('after'); 
}); 

Mam nadzieję, że to pomaga.

+0

Dzięki Damien !, ale to nie jest dokładnie to, co miałem na myśli.Twój przykład będzie działał tylko po dodaniu lub usunięciu elementów, ale to nie jest coś, co będę robić z tą kolekcją. tak jak jest teraz, pochodzi z db do widoku i po prostu się wyświetla. nic więcej. Chcę, aby zdarzenie zostało uruchomione zaraz po renderowaniu ostatniego elementu w pętli –

+0

Cześć Nir, dodałem zegar, aby zasymulować wywołanie usługi sieciowej, jak widzisz, powiadamia po wyrenderowaniu elementów. http://jsfiddle.net/bUJmu/2/ – Damien

1

użycie przepustnicy extender, w ten sposób obliczona zostanie wywołany raz po zakończeniu wypełniania tablicy:

self.counter = ko.computed(function() { 
     return self.containers().length; 
    }).extend({ throttle: 100 }); 
+0

Uwielbiam tę odpowiedź. Tak proste i właśnie to, czego potrzebowałem, aby rozwiązać podobny problem z wyrównywaniem kolumn w tabeli po wykonaniu każdego wiersza. Dzięki! –

2

Udało mi się użyć odpowiedzi Ricardo Medeirosa Penny za pomocą tylko jednej drobnej korekty.

this.myPostProcessingLogic = function(elements, data) { 
     if(this.foreach._latestValue[this.foreach._latestValue.length-1] === data) 
     console.log("list is rendered"); 
    }; 

Musiałem dodać _latestValue, aby uzyskać wartość długości i teraz działa zgodnie z oczekiwaniami.

+0

_latestValue jest zmienną prywatną. Nie jestem pewien, czy dostęp do niego byłby bezpieczny. Więc zamiast tego użyj 'this.foreach()'. Niezbyt duża różnica polega na tym, że 'this.myPostProcessingLogic = funkcja (elementy, dane) { var underLyingArray = this.foreach(); if (underLyingArray [underLyingArray.length - 1] === dane) console.log ("lista jest renderowana"); }; ' – pravin

+0

Dzięki za aktualizację pravin – JaxCoder

Powiązane problemy