Search code examples
angularjsangularjs-ng-repeatangular-ng-if

ng-if inside ng-repeat not updating from controller


So I am new to Angular, like just started right now so bear with me please... I want to loop thru an array and then inside the loop evaluate a condition to display some HTML it looks like this:

<div ng-controller="BuilderController">
<div ng-repeat="row in formRows" class="fe-form-row">
    <div class="fe-form-draggable-item">
        <div class="fe-form-l-side-menu bg-primary col-md-1 pull-left">
            <i class="fa fa-cog"></i>
            <i class="fa fa-close"></i>
        </div>
        <div class="gray-lighter col-md-11 pull-left">
            <div ng-if="row.columns.length == 0">
                <div ng-click="open('lg','layout')" id="fe-form-container-base" class="fe-form-r-side-menu gray-lighter col-md-12">
                    <div class="fe-form-insert-menu">
                        <i class="fa fa-plus-square-o"></i>
                        <span>Add Column(s)</span>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
</div>

The first time arround column is an empty array so it evaluates to true and the HTML piece is displayed, all good. And I tried setting it up as not an empty array and evaluates to false and the HTML is not showed. So far so good. The problem is when I change the value of column inside the controller:

admin_app.controller('BuilderController', function ($scope, $modal, $log) {
    //default value, empty row
    //TODO: assign value to these and the form should be automatically created
    $scope.formRows = [
        {
            'layout': 'empty',
            columns: []
        }
    ];
    $scope.animationsEnabled = true;
    //TODO: these should be loaded from server-side somehow...
    $scope.columnsOptions = ['1', '2', '3', '4', '5', '6'];

    $scope.open = function (size, content) {
        var modalInstance = $modal.open({
            animation: $scope.animationsEnabled,
            templateUrl: 'fe-form-' + content + '-container.html',
            controller: 'ModalInstanceCtrl',
            windowClass: 'fe-form-builder',
            size: size,
            resolve: {
                columnsOptions: function () {
                    return $scope.columnsOptions;
                }
            }
        });

        modalInstance.result.then(function (selectedItem) {
            $scope.selected = selectedItem;
        }, function () {
            $log.info('Modal dismissed at: ' + new Date());
        });

        $scope.toggleAnimation = function () {
            $scope.animationsEnabled = !$scope.animationsEnabled;
        };
    };
});

admin_app.controller('ModalInstanceCtrl', function ($scope, $modalInstance, columnsOptions) {

    $scope.columnsOptions = columnsOptions;
    $scope.selected = {
        columnsOption: $scope.columnsOptions[0]
    };

    $scope.ok = function () {
        var columns = [];
        for (var i = 0; i < $scope.selected.columnsOption; i++) {
            columns.push({
                type: $scope.selected.columnsOption,
                elements: []
            });
        }
        //update formRows var with new columns
        $scope.formRows = [
            {
                'layout': $scope.selected.columnsOption,
                columns: columns
            }
        ];
        console.log(' $scope.formRows ', $scope.formRows[0].columns.length);
        $modalInstance.close($scope.selected.item);
    };

    $scope.cancel = function () {
        $modalInstance.dismiss('cancel');
    };
});

The console.log shows that the columns have been correctly updated based on the user input, but the HTML is not re-rendered to hide the HTML piece since columns is no longer an empty array. Am I missing something here, is there something wrong with my approach? As I mentioned I am very new to Angular.


Solution

  • If I understand correct, your data structure is something like this:
    formRows -> Array
    row -> Object which contains another object columns
    columns -> Array

    I think the problem is that Angular is tracking any changes to formRows, which are not happening when your columns object change because there is no direct change in formRows. Angular is not trying to check changes at the sub-sub object level, so to speak. You could either create a new object everytime you're changing rows and add it back to formRows. Or you can add a deepwatch to check changes to your columns array. Check this:

    How to deep watch an array in angularjs?