2015-11-15 22 views
7

Starałem się pracować z roztworu do tegoJak utrzymać pozycję przewijania NG-repeat w angularjs podczas usuwania elementu z górnym

How to retain scroll position of ng-repeat in AngularJS?

osiągnąć zachowując pozycję przewijania podczas zdejmowania pokrywy element w powtórzeniu ng, ale nie mógł znaleźć kodu, aby to zrobić.

Również na marginesie, lista powinna być wydrukowana w tej samej kolejności co tablica elementów, a nie na odwrocie, jak to robi przykład.

kod użytkownika rozwiązania:

angular.module("Demo", []) 

.controller("DemoCtrl", function($scope) { 
    $scope.items = []; 

    for (var i = 0; i < 10; i++) { 
    $scope.items[i] = { 
     id: i, 
     name: 'item ' + i 
    }; 
    } 

    $scope.addNewItem = function() { 
    $scope.items = $scope.items.concat({ 
     id: $scope.items.length, 
     name: "item " + $scope.items.length 
    }); 
    }; 
}) 

.directive("keepScroll", function(){ 

    return { 

    controller : function($scope){ 
     var element = 0; 

     this.setElement = function(el){ 
     element = el; 
     } 

     this.addItem = function(item){ 
     console.log("Adding item", item, item.clientHeight); 
     element.scrollTop = (element.scrollTop+item.clientHeight+1); //1px for margin 
     }; 

    }, 

    link : function(scope,el,attr, ctrl) { 

    ctrl.setElement(el[0]); 

    } 

    }; 

}) 

.directive("scrollItem", function(){ 


    return{ 
    require : "^keepScroll", 
    link : function(scope, el, att, scrCtrl){ 
     scrCtrl.addItem(el[0]); 
    } 
    } 
}) 

Co próbowałem robi się zmienia

element.scrollTop = (element.scrollTop + item.clientHeight+1) 

do

element.scrollTop = (element.scrollTop - item.clientHeight+1) 

i drukowania w kolejności 'id' nie '-id'

Odpowiedz

5

myślę początkowe rozwiązanie jest rodzaj hacky ... ale tutaj jest robocza edycja wykorzystująca ją jako podstawę.

Problem polega na tym, że rozwiązanie zależy od pozycji dodawanych do powtórzenia ng. Jeśli spojrzysz na dyrektywę scrollItem, spowoduje to tylko, że dyrektywa keepScroll ponownie dopasuje scrollTop, jeśli linker zostanie wykonany. Dzieje się tak tylko wtedy, gdy elementy zostaną dodane, a nie usunięte.

Edycja zamiast tego słucha zdarzenia scope.$on('$destroy'). Problem w tym momencie polega jednak na tym, że element nie ma już pozycji ClientHeight, ponieważ został usunięty z DOM. Rozwiązaniem jest zapisanie jego wysokości, gdy zostanie utworzone, a następnie powiedzenie keepScroll, jaka była wysokość usuniętego elementu.

Uwaga: Wydaje się, że spowodował to przewinięcie przewijania, jeśli przewijacz znajdował się na samym dole, więc musisz zajrzeć do tej sprawy jako wyjątek.

robocza JSBin: http://jsbin.com/geyapugezu/1/edit?html,css,js,output

Dla porównania:

HTML

<!DOCTYPE html> 
<html> 
<head> 
<script src="//code.angularjs.org/1.3.0-beta.7/angular.js"></script> 
    <meta charset="utf-8"> 
    <title>JS Bin</title> 
</head> 
<body ng-app="Demo" ng-controller="DemoCtrl"> 
    <div class="wrapper" keep-scroll> 
    <div class="item" scroll-item ng-repeat="item in items | orderBy: 'id'"> 
     {{ item.name }} 
    </div> 
    </div> 
    <button ng-click="removeItem()"> 
    Remove item 
    </button> 
</body> 
</html> 

CSS

.wrapper { 
    width: 200px; 
    height: 300px; 
    border: 1px solid black; 
    overflow: auto; 
} 
.item { 
    background-color: #ccc; 
    height: 100px; 
    margin-bottom: 1px; 
} 

JS

angular.module("Demo", []) 
    .controller("DemoCtrl", function($scope) { 
    $scope.items = []; 

    for (var i = 0; i < 10; i++) { 
     $scope.items[i] = { 
     id: i, 
     name: 'item ' + i 
     }; 
    } 

    $scope.removeItem = function() { 
     $scope.items = $scope.items.slice(1); 
    }; 
}) 
.directive("keepScroll", function(){ 

    return { 
    controller : function($scope){ 
     var element = 0; 

     this.setElement = function(el){ 
     element = el; 
     }; 

     this.itemRemoved = function(height){ 
     element.scrollTop = (element.scrollTop - height - 1); //1px for margin 
     console.log("Item removed", element.scrollTop); 
     }; 

    }, 

    link : function(scope,el,attr, ctrl) { 
    ctrl.setElement(el[0]); 

    } 

    }; 

}) 
.directive("scrollItem", function(){ 


    return { 
    require : "^keepScroll", 
    link : function(scope, el, att, scrCtrl){ 
     var height = el[0].clientHeight; 

     scope.$on('$destroy', function() { 
     scrCtrl.itemRemoved(height); 
     }); 
    } 
    }; 
}); 

EDIT

Albo to zrobić. Nie ma potrzeby używania scrollItem, zamiast tego oglądamy zmiany w elementach powtarzających ng i odpowiednio dostosowujemy scrollTop.

JSBin: http://jsbin.com/dibeqivubi/edit?html,css,js,output

JS

angular.module("Demo", []) 
    .controller("DemoCtrl", ['$scope', function($scope) { 
    $scope.items = []; 

    for (var i = 0; i < 10; i++) { 
     $scope.items[i] = { 
     id: i, 
     name: 'item ' + i 
     }; 
    } 

    $scope.removeItem = function() { 
     $scope.items = $scope.items.slice(1); 
    }; 
}]) 
.directive("keepScroll", function() { 
    return { 
    link : function(scope,el,attr, ctrl) { 
     var scrollHeight; 

     scope.$watchCollection('items', function(n,o) { 
     // Instantiate scrollHeight when the list is 
     // done loading. 
     scrollHeight = scrollHeight || el[0].scrollHeight; 
     // Adjust scrollTop if scrollHeight has changed (items 
     // have been removed) 
     el[0].scrollTop = el[0].scrollTop - (scrollHeight - el[0].scrollHeight); 
     // Remember current scrollHeight for next change. 
     scrollHeight = el[0].scrollHeight; 
     }); 
    } 

    }; 
}); 

HTML

<!DOCTYPE html> 
<html> 
<head> 
<script src="//code.angularjs.org/1.3.0-beta.7/angular.js"></script> 
    <meta charset="utf-8"> 
    <title>JS Bin</title> 
</head> 
<body ng-app="Demo" ng-controller="DemoCtrl"> 
    <div class="wrapper" keep-scroll> 
    <div class="item" ng-repeat="item in items | orderBy: 'id'"> 
     {{ item.name }} 
    </div> 
    </div> 
    <button ng-click="removeItem()"> 
    Remove item 
    </button> 
</body> 
</html> 
+0

To najlepsze rozwiązanie. Bardzo kompletny i zgodny z dobrą praktyką kątową. Jak już wspomniano, w przypadku obu rozwiązań przewijanie do dołu i kliknięcie przycisku usuwania powoduje przewijanie do wybranej pozycji. Jaka byłaby tego przyczyna? –

0

Mam nadzieję, że $anchorScroll może ci pomóc. Postępuj zgodnie z link.

+0

To naprawdę nie robić tego, co chcemy. Nie wszystkie elementy miałyby taką samą wysokość i niekoniecznie chciałbym przewinąć do góry. –

+1

Ale dziękuję, @ ​​lokeshjain2008 –

0

Nie jestem pewien, czy rozumiem poprawnie, ale możesz osiągnąć to, czego chcesz, słuchając tablicy przedmiotów i przedmiotu do usunięcia.

nadzieję, że pomoże

http://plnkr.co/edit/buGcRlVGClj6toCVXFKu?p=info

Oto co zrobiłem:

Dodany właściwość height przedmiotów

for (var i = 0; i < 20; i++) { 
    $scope.items[i] = { 
     id: i, 
     name: 'item ' + i, 
     height: (Math.random()*100)+30 
    }; 
} 

style: height nieruchomość wewnątrz pliku html

<div class="wrapper" keep-scroll> 
    <div class="item" scroll-item ng-repeat="item in items" style="height:{{item.height}}px"> 
     {{ item.name }} 
    </div> 
</div> 

deleteItem metoda wewnątrz DemoCtrl

$scope.deleteItem = function() { 
    var itemToDelete = $scope.items[0]; 
    $scope.items.splice(0,1); 
    $scope.$broadcast("scrollFix",itemToDelete); 
}; 

niż słuchać scrollFix zdarzenia wewnątrz keepScroll dyrektywy

$scope.$on('scrollFix',function(event,data){ 
    element.scrollTop = element.scrollTop - data.height; 
}); 
+0

Dlaczego właściwość wysokości jest niezbędna do dodania elementu, chociaż nie było to konieczne do usunięcia go, jak w połączonym poprzednim rozwiązaniu? –

+0

Nadawanie wydarzenia w zakresie głównym nie jest dobrą praktyką. Chciałbym użyć dyrektywy tak, jak w oryginalnym rozwiązaniu i zgodnie z najlepszymi praktykami dotyczącymi manipulowania elementami DOM. –

+0

Tak, masz rację, muhamed. Nie jest konieczne definiowanie wysokości elementów. Rozwiązanie Foglerek jest wygodniejsze. – huseyinozcan