Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Usage of ng-change and ng-model in a custom directive - digest loop

Tags:

angularjs

I'm working on date picker to implement range selector on AngularUI.

An html code to call custom time picker:

<time-range 
         name-time="Hours" 
         max-length="2" min="00" max="23" step="01" 
         ng-model="hours" 
         ng-change="updateHours()">
  </time-range>
  <time-range 
         name-time="Minutes" 
         max-length="2" min="00" max="59" step="01" 
         ng-model="minutes" 
         ng-change="updateMinutes()">
   </time-range>

Here is my directive:

module app.common.directives {

    export interface ITimeRangeScope extends ng.IScope {
        ngModel: string;
        ngChange;
        nameTime: string;
        maxLength: number;
        min: number;
        max: number;
        step: number;
        vm: TimeRangeController;
    }

    export class TimeRange implements ng.IDirective {
        scope: any = {
            ngModel: "=",
            ngChange: "=",
            nameTime: "@",
            maxLength: "@",
            min: "@",
            max: "@",
            step: "@"
        };
        controller = TimeRangeController;

        template = `
            <div class="custom-range-slider">
                <span> {{nameTime}}: </span>
                <div style="padding-bottom: 5px;"></div>
                <input type="range" max-length="{{maxLength}}" min="{{min}}" max="{{max}}" step="{{step}}" ng-model="ngModel"ng-change="ngChange">
            </div>
        `;

        restrict: string = "E";

        //Use this to register this directive
        static factory(): ng.IDirectiveFactory {
            var directive: ng.IDirectiveFactory = () => new TimeRange();
            return directive;
        }
    }

    class TimeRangeController {
        init;
        val;

        // @ngInject
        constructor(
            private $scope: ITimeRangeScope,
            private $element: ng.IAugmentedJQuery,
            private $attrs,
            private $transclude
        ) {
            $scope.vm = this;

            this.$scope.$watch("ngModel", () => {
                this.showPercentage();
                this.drawRangeTrace();
            });
        }

        showPercentage() {
            this.init = parseInt(this.$scope.ngModel);
            var min = parseInt(this.$element.attr('min'));
            var max = parseInt(this.$element.attr('max'));
            this.val = (this.init - min) / max - min;
        }

        drawRangeTrace() {
            this.$element.children().find('input').css('background-image',
                '-webkit-gradient(linear, left top, right top, '
                + 'color-stop(' + this.val + ', #2196F3), '
                + 'color-stop(' + this.val + ', #C5C5C5)'
                + ')'
            );
            this.$element.children().find('input').val(this.init);
        }
    }
}

This is how it is working:

Date Picker with sliders

But I recived an error of: 10 $digest()

> vendor.min.js:84275 Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [[{"msg":"fn: ngModelWatch","newVal":"2017-05-28T22:00:00.000Z","oldVal":"2017-05-28T22:00:00.000Z"},{"msg":"fn: ngModelWatch","newVal":"2017-05-28T22:00:00.000Z","oldVal":"2017-05-28T22:00:00.000Z"},{"msg":"fn: ngModelWatch","newVal":"2017-05-28T22:00:00.000Z","oldVal":"2017-05-28T22:00:00.000Z"}],[{"msg":"fn: ngModelWatch","newVal":"2017-05-28T22:00:00.000Z","oldVal":"2017-05-28T22:00:00.000Z"},{"msg":"fn: ngModelWatch","newVal":"2017-05-28T22:00:00.000Z","oldVal":"2017-05-28T22:00:00.000Z"},{"msg":"fn: ngModelWatch","newVal":"2017-05-28T22:00:00.000Z","oldVal":"2017-05-28T22:00:00.000Z"}],[{"msg":"fn: ngModelWatch","newVal":"2017-05-28T22:00:00.000Z","oldVal":"2017-05-28T22:00:00.000Z"},{"msg":"fn: ngModelWatch","newVal":"2017-05-28T22:00:00.000Z","oldVal":"2017-05-28T22:00:00.000Z"},{"msg":"fn: ngModelWatch","newVal":"2017-05-28T22:00:00.000Z","oldVal":"2017-05-28T22:00:00.000Z"}],[{"msg":"fn: ngModelWatch","newVal":"2017-05-28T22:00:00.000Z","oldVal":"2017-05-28T22:00:00.000Z"},{"msg":"fn: ngModelWatch","newVal":"2017-05-28T22:00:00.000Z","oldVal":"2017-05-28T22:00:00.000Z"},{"msg":"fn: ngModelWatch","newVal":"2017-05-28T22:00:00.000Z","oldVal":"2017-05-28T22:00:00.000Z"}],[{"msg":"fn: ngModelWatch","newVal":"2017-05-28T22:00:00.000Z","oldVal":"2017-05-28T22:00:00.000Z"},{"msg":"fn: ngModelWatch","newVal":"2017-05-28T22:00:00.000Z","oldVal":"2017-05-28T22:00:00.000Z"},{"msg":"fn: ngModelWatch","newVal":"2017-05-28T22:00:00.000Z","oldVal":"2017-05-28T22:00:00.000Z"}]]
http://errors.angularjs.org/1.6.1/$rootScope/infdig?p0=10&p1=%5B%5B%7B%22ms…%3A00.000Z%22%2C%22oldVal%22%3A%222017-05-28T22%3A00%3A00.000Z%22%7D%5D%5D
    at vendor.min.js:84275
    at Scope.$digest (vendor.min.js:102059)
    at Scope.$apply (vendor.min.js:102287)
    at vendor.min.js:104131
    at completeOutstandingRequest (vendor.min.js:90318)
    at vendor.min.js:90597
like image 213
Andrej Avatar asked May 29 '17 07:05

Andrej


1 Answers

I changed ngChange into onUpdate.

In html:

on-update="updateHours()"

I added in changed from ngCgange; in directive to

onUpdate: () => any;

Bind the scope:

onUpdate: "&",

aldo called a method add

class TimeRangeController {
        init;
        val;
        onUpdate; // Override callback for adding an entity to the list

        // @ngInject
        constructor(
            private $scope: ITimeRangeScope,
            private $element: ng.IAugmentedJQuery,
            private $attrs,
            private $transclude
        ) {
            $scope.vm = this;

            this.$scope.$watch("ngModel", () => {
                this.showPercentage();
                this.drawRangeTrace();
                this.add();
            });
        }

        add() {
             if (this.$attrs.onUpdate != undefined) {
                  this.$scope.onUpdate();
              }
        }

        showPercentage() {
            this.init = parseInt(this.$scope.ngModel);
            var min = parseInt(this.$element.attr('min'));
            var max = parseInt(this.$element.attr('max'));
            this.val = (this.init - min) / max - min;
        }

        drawRangeTrace() {
            this.$element.children().find('input').css('background-image',
                '-webkit-gradient(linear, left top, right top, '
                + 'color-stop(' + this.val + ', #2196F3), '
                + 'color-stop(' + this.val + ', #C5C5C5)'
                + ')'
            );
            this.$element.children().find('input').val(this.init);
        }
    }
like image 66
Andrej Avatar answered Nov 15 '22 06:11

Andrej