Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scope variable not updating in DOM after event listener changes it

Tags:

angularjs

I have a variable defined in my $scope object and bound in the DOM. When the page loads, the value is displayed correctly. I have a listener defined on the $window resize event which does fire appropriately when the window is resized. I put a breakpoint in the function that gets called and it does have the correct value of picCols when run and it does change to the new value based on the current window width. However after the function is finished the DOM does not update with the new value.

Here is my controller. The watched variable is $scope.picCols

.controller('AlbumEditCtrl', function($scope, $stateParams, $window) {
$scope.album = {id: 1, date: '8/23/2014', title: 'My Album 1', photos:
    [
        {url: 'img/default-placeholder.png'},
        {url: 'img/default-placeholder.png'},
        {url: 'img/default-placeholder.png'},
        {url: 'img/default-placeholder.png'},
        {url: 'img/default-placeholder.png'},
        {url: 'img/default-placeholder.png'},
        {url: 'img/default-placeholder.png'},
        {url: 'img/default-placeholder.png'},
        {url: 'img/default-placeholder.png'},
        {url: 'img/default-placeholder.png'},
        {url: 'img/default-placeholder.png'},
        {url: 'img/default-placeholder.png'}
    ]};
    $scope.photoRows = [];
    $scope.picCols = 0;

    $window.addEventListener("resize", function () {
        if(parseInt($window.innerWidth / 80, 10) != $scope.picCols)
        {
            $scope.recalculateImageColumns();
        }
    });

    $scope.recalculateImageColumns = function (){
        var photoRows = [];
        $scope.picCols = parseInt($window.innerWidth / 80, 10);
        console.log($scope.$id);
        var count = 0;
        var currentArray = -1;
        for(var i = 0; i < $scope.album.photos.length; i++){
            if(count < $scope.picCols){
                if(count == 0){
                    count++;
                    currentArray++;
                    photoRows.push({photos:[$scope.album.photos[i]]});
                }
                else{
                    photoRows[currentArray].photos.push($scope.album.photos[i]);
                    if(count == $scope.picCols-1)
                        count = 0;
                    else
                        count++;
                }
            }
        }
        angular.copy(photoRows, $scope.photoRows);
    };
    $scope.recalculateImageColumns();
});

Here is the DOM

<ion-view title="My BGCA">
<ion-content class="has-header padding">
    <h2>{{album.title}}</h2>
    <h5>{{album.date}}</h5>
    <h5>{{picCols}}</h5>
    <h5>{{$id}}</h5>
    <div class="row" ng-repeat="photoRow in photoRows">
        <div class="col" ng-repeat="photo in photoRow.photos"><img ng-src="{{photo.url}}" width="75" height="75" /></div>
    </div>
 </ion-content>
</ion-view>

UPDATE Here is the directive that ended up working nicely.

.directive(
"ngResize",
function($window) {
    function link( $scope, element, attributes ) {
        var domElement = element[0];
        function updateImageCapacity() {

                var viewportWidth = domElement.clientWidth;
                var capacity = parseInt(viewportWidth / 80, 10);
                $scope.setImageCapacity( capacity );
        }
        updateImageCapacity();       

        window.angular.element($window).on('resize', function(){
            $scope.$apply( updateImageCapacity );
        });

        $scope.$on(
            "$destroy",
            function() {
                window.angular.element($window).off('resize');
            }
        );
    }

    return({
        link: link,
        restrict: "A"
    });

}
)

http://www.bennadel.com/blog/2476-my-approach-to-building-angularjs-directives-that-bind-to-javascript-events.htm?&_=0.9274228068534285#comments_45548

like image 279
Brett Mathe Avatar asked Sep 01 '14 18:09

Brett Mathe


1 Answers

$window.addEventListener("resize", function () {
    if(parseInt($window.innerWidth / 80, 10) != $scope.picCols)
    {
        $scope.recalculateImageColumns();
        $scope.$apply(); // you need to call $apply if you do anything outside of angular context;
    }
});

Angular Way

app.directive("ngResize", function ($window) {
    return {
        scope: {
            ngResize: "="
        },
        link: function ($scope, element, attrs) {
            angular.element($window).on("resize", function () {
                $scope.ngResize = "Smith";
                $scope.$apply();
            });
        }
    }
});

Add directive

<div ng-controller="ctrl" ng-resize="name">{{ name }}</div>

DEMO

like image 103
Darshan P Avatar answered Nov 05 '22 16:11

Darshan P