How do I update an angularjs page after a scope update?

为君一笑 提交于 2019-12-12 16:23:24

问题


I have written a directive that captures keyboard events, and on certain keys I update some objects in the scope. The idea is to move up and down an array and display the selected row details. The problem is the page is not updated until I do another action that updates the page. How can I force this?

Here's the directive:

LogApp.directive("keyCapture", [function(){
    var scopeInit;
    return{
        link: function(scope, element, attrs, controller){
            scopeInit = scope
            element.on('keydown', function(e){
                scopeInit[attrs.keyCapture].apply(null, [e]);                
            });
        }
    }
}]);

Bound the template like this:

<body ng-controller="logCtrl" key-capture="movePreview">

The controller method:

$scope.movePreview = function(e){
    if ($scope.events.length === 0)
        return;
    // Find the element 
    if (e.keyCode === 38 || e.keyCode === 40){
        console.log("Pressed %s", e.keyCode);
        var offset = 0;
        if (e.keyCode === 38 && $scope.previewIndex > 0)
            offset = -1;
        else if (e.keyCode === 40 && $scope.previewIndex < $scope.events.length -1 )
            offset = 1;

        $scope.previewIndex += offset;
        var eventId = $scope.events[$scope.previewIndex].uuid;
        $scope.showEvent(eventId);
        e.preventDefault();
    }
};

$scope.showEvent(eventId) will take the item with given ID and display it in another part of the page. Part that is not update until another action is performed, like clicking a button. Is it possible to force the page update?

Here's a fiddle that reproduces: http://jsfiddle.net/gM2KF/1/ If you click on the button, the counter is updated. If you press any key, nothing shows. But you click again on the button, you see the counter has been updated by the keyboard event, but didn't show.


回答1:


If you are listening to non-angular events:

element.on('keydown', function(e){
    scopeInit[attrs.keyCapture].apply(null, [e]);                
});

Then, to update the scope, you need to call scope.$apply:

element.on('keydown', function(e){
    scopeInit[attrs.keyCapture].apply(null, [e]); 
    scope.$apply();               
});

This will kick off an angular $digest cycle and allow changes to bind.




回答2:


Just wrap the $scope changes in $scope.$apply();

While your code could be altogether cleaner, this ought to make it work:

$scope.movePreview = function(e){
  $scope.$apply(function() {
    if ($scope.events.length === 0)
        return;
    // Find the element 
    if (e.keyCode === 38 || e.keyCode === 40){
        console.log("Pressed %s", e.keyCode);
        var offset = 0;
        if (e.keyCode === 38 && $scope.previewIndex > 0)
            offset = -1;
        else if (e.keyCode === 40 && $scope.previewIndex < $scope.events.length -1 )
            offset = 1;

        $scope.previewIndex += offset;
        var eventId = $scope.events[$scope.previewIndex].uuid;
        $scope.showEvent(eventId);
        e.preventDefault();
    }
  });
};



回答3:


This is a single example that prints out events based on your example:

HTML

<body ng-controller="MyCtrl" key-capture  move="movePreview()">    
    <pre>Pressed: {{previewIndex}}</pre>    
</body>

JS

var app = angular.module('App', []);

function MyCtrl($scope) {   
    $scope.movePreview = function(e){        
        $scope.previewIndex = e.keyCode; 
};

}
app.$inject = ['$scope'];
app.directive("keyCapture", [function(){
    var scopeInit;
    return{
        link: function(scope, element, attrs, controller){

             element.bind('keydown', function (e) {
                scope.$apply(function(){scope.movePreview(e);});                    
            });            
        }
    }
}]);

Demo Fiddle

We call movePreview method on each key event.



来源:https://stackoverflow.com/questions/20571109/how-do-i-update-an-angularjs-page-after-a-scope-update

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!