在ng-repeat中滚动到数组中最后添加的记录

时间:2015-08-28 08:42:36

标签: javascript jquery css angularjs

我尝试使用ngRepeat指令实现滚动到最后添加的条目。

我找到并调查了一些相关的SO问题:#1#2。但仍然无法解决问题。

代码非常简单。 当用户向阵列添加新记录时,控制器广播“滚动事件”。使用新添加的项目名称,指令接收此事件并滚动到列表中新添加的条目。

<div ng-controller="MainCtrl">
    <input ng-model="newItem" ng-keydown="$event.which === 13 && addNewItem(newItem)"/>
        <button ng-click="addNewItem(newItem)">Add</button>

        <div id="items-list" scroll-to-new-item> 
            <div ng-repeat="item in items | orderBy: 'name'">
                <input ng-model="item.name" ng-readonly="true"/>
            </div>
        </div>
 </div>

app.controller("MainCtrl", function($scope){
    $scope.items = [
        {id: 1, name: "aaa"}, {id: 2, name: "bbb"},         
        {id: 3, name: "ccc"}, {id: 4, name: "ddd"},
        .......
    ];

    $scope.addNewItem = function(newItem){
        $scope.items.push({name: newItem});
        $scope.$broadcast('scroll-event', newItem);
        $scope.newItem = "";
    };
});

这是我的指令,它应滚动到列表中最后添加的记录。

app.directive("scrollToNewItem", function(){
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            scope.$on('scroll-event', function (event, newValue) {
                if(newValue){
                    var newItemHeightPosition = // !!! MY ISSUE HERE !!!
                    $('#items-list').animate({
                        scrollTop: newItemHeightPosition
                    }, 'slow');
                }
            });
        }
    };
});

但我无法弄明白,如何获得新增项目的顶级位置。我尝试了几种变体,但它们没有得到任何结果。例如,以下jquery选择器不起作用:

$('#items-list').find('input[value=' + newValue +']');
$('#items-list').find('input').eq(newValue);

请注意,数组按字母顺序排序,因此会使此任务变得复杂。

This is my JSFiddle

谁知道,如何解决这个问题?

提前致谢!

2 个答案:

答案 0 :(得分:1)

该代码存在两个问题。

1)第一个问题是,ngRepeat指令在scrollToNewItem指令开始之前没有在重复中呈现新添加的项目。

我已经通过$timeout中的DOM选择器包装来修复它。它提供了一种安全的方法来调用$ scope。$ apply并确保$ digest循环已经过去。您可以在此处阅读更多详细信息:Angular $scope.$apply vs $timeout as a safe $apply

2)第二个问题与我的渲染输入项没有任何包含值的属性有关。因此,由于这个原因,我找不到任何带有以下JQuery选择器的DOM项。

$('#items-list').find('input[value=' + newValue +']')

我通过添加额外的属性value来修复它,以输入whithin ngRepeat指令。

value="{{vehicle.Name}}"

最后,我编辑的 JSFiddle 与您可以找到here的工作示例。

答案 1 :(得分:0)

我不能提高效率,但除非你的名单在1000中,否则我个人不介意使用.each()这样的话。

app.directive("scrollToNewItem", function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            scope.$on('scroll-event', function (event, newValue) {

                var newItemHeightPosition

                if (newValue) {
                    $('#items-list input').each(function () {
                        if ($(this).html().indexOf(newValue)) {
                            newItemHeightPosition = $(this).position().top;
                        }
                    })

                    $('#items-list').animate({
                        scrollTop: newItemHeightPosition
                    }, 'slow');
                }
            });
        }
    };
});

进一步解释,在你自己的例子中,你写

$('#items-list').find('input[value=' + newValue +']');

你正在做的是尝试选择一个dom元素,例如看起来像这样

<input type="submit" value="name">

但是您的输入项目实际上甚至没有值属性。相反,我迭代输入并找到其html包含刚刚添加的名称的输入。它并不完美,但它应该说明如何解决您的问题。