source

ng-change에 대한 지연을 캡슐화하는 각도 지시

factcode 2023. 9. 21. 21:32
반응형

ng-change에 대한 지연을 캡슐화하는 각도 지시

ng-change에 바인딩된 쿼리 기능이 있는 검색 입력 필드가 있습니다.

 <input ng-model="search" ng-change="updateSearch()">

하지만 이것은 모든 캐릭터에게 너무 빨리 발생합니다.그래서 저는 이런 일을 자주 하게 됩니다.

  $scope.updateSearch = function(){
    $timeout.cancel(searchDelay);
    searchDelay = $timeout(function(){
      $scope.requery($scope.search);
    },300);
  }

사용자가 타이핑을 중지한 후 300ms만 요청하도록 합니다.이것을 지시로 포장할 수 있는 해결책이 있습니까?

각도 1.3 기준으로 ngModelOptions를 사용하면 훨씬 쉽게 실행할 수 있습니다.

<input ng-model="search" ng-change="updateSearch()" ng-model-options="{debounce:3000}">

Syntax:  {debounce: Miliseconds}

이 문제를 해결하기 위해 ngDelay라는 명령어를 만들었습니다.

ngDelay는 ngChange의 동작을 모든 키 입력이 아닌 사용자가 비활성 상태일 때마다 업데이트를 제공하는 원하는 지연 동작을 지원하도록 강화합니다.트릭은 자식 스코프를 사용하고 ngChange 값을 타임아웃 로직을 포함하고 상위 스코프에서 원래 식을 실행하는 함수 호출로 대체하는 것이었습니다.두 번째 방법은 ngModel 바인딩이 있는 경우 상위 범위로 이동하는 것입니다.이러한 변경 사항은 모두 ngDelay 지시문의 컴파일 단계에서 수행됩니다.

ngDelay: http://jsfiddle.net/ZfrTX/7/ (Mainguy와 Ryan Q의 도움을 받아 내가 쓰고 편집한)을 사용한 예시를 포함한 fiddle입니다.

이 코드는 brentvatne 덕분에 GitHub에서 찾을 수 있습니다.고마워요 브렌트!

ngDelay 명령어에 대한 자바스크립트를 간단히 참고할 수 있습니다.

app.directive('ngDelay', ['$timeout', function ($timeout) {
    return {
        restrict: 'A',
        scope: true,
        compile: function (element, attributes) {
            var expression = attributes['ngChange'];
            if (!expression)
                return;

            var ngModel = attributes['ngModel'];
            if (ngModel) attributes['ngModel'] = '$parent.' + ngModel;
            attributes['ngChange'] = '$$delay.execute()';

            return {
                post: function (scope, element, attributes) {
                    scope.$$delay = {
                        expression: expression,
                        delay: scope.$eval(attributes['ngDelay']),
                        execute: function () {
                            var state = scope.$$delay;
                            state.then = Date.now();
                            $timeout(function () {
                                if (Date.now() - state.then >= state.delay)
                                    scope.$parent.$eval(expression);
                            }, state.delay);
                        }
                    };
                }
            }
        }
    };
}]);

그리고 TypeScript wunk가 있다면 Definitely 의 각도 정의를 사용하는 TypeScript 입니다.입력:

components.directive('ngDelay', ['$timeout', ($timeout: ng.ITimeoutService) => {
    var directive: ng.IDirective = {
        restrict: 'A',
        scope: true,
        compile: (element: ng.IAugmentedJQuery, attributes: ng.IAttributes) => {
            var expression = attributes['ngChange'];
            if (!expression)
                return;

            var ngModel = attributes['ngModel'];
            if (ngModel) attributes['ngModel'] = '$parent.' + ngModel;
            attributes['ngChange'] = '$$delay.execute()';
            return {
                post: (scope: IDelayScope, element: ng.IAugmentedJQuery, attributes: ng.IAttributes) => {
                    scope.$$delay = {
                        expression: <string>expression,
                        delay: <number>scope.$eval(attributes['ngDelay']),
                        execute: function () {
                            var state = scope.$$delay;
                            state.then = Date.now();
                            $timeout(function () {
                                if (Date.now() - state.then >= state.delay)
                                    scope.$parent.$eval(expression);
                            }, state.delay);
                        }
                    };
                }
            }
        }
    };

    return directive;
}]);

interface IDelayScope extends ng.IScope {
    $$delay: IDelayState;
}

interface IDelayState {
    delay: number;
    expression: string;
    execute(): void;
    then?: number;
    action?: ng.IPromise<any>;
}

JSFiddle 이 제게 딱 맞습니다.

  var app = angular.module('app', []);
    app.directive('delaySearch', function ($timeout) {
        return {
            restrict: 'EA',
            template: ' <input ng-model="search" ng-change="modelChanged()">',
            link: function ($scope, element, attrs) {
                $scope.modelChanged = function () {
                    $timeout(function () {
                        if ($scope.lastSearch != $scope.search) {
                            if ($scope.delayedMethod) {
                                $scope.lastSearch = $scope.search;
                                $scope.delayedMethod({ search: $scope.search });
                            }
                        }
                    }, 300);
                }
            },
            scope: {
                delayedMethod:'&'
            }
        }
    });

지시사항 사용하기

컨트롤러에서:

app.controller('ctrl', function ($scope,$timeout) {
    $scope.requery = function (search) {
        console.log(search);
    }
});

보기에는 다음과 같습니다.

<div ng-app="app">
    <div ng-controller="ctrl">
        <delay-search delayed-method="requery(search)"></delay-search>
    </div>
</div>

내가 게임에 늦었다는 것을 알지만, 이것이 여전히 1.2를 사용하는 사람에게 도움이 되기를 바랍니다.pren-model-options 이것이 나에게 효과가 있다는 것을 발견했습니다. 값이 유효하지 않을 때 song change가 발생하지 않습니다.

이는 모델이 어떤 상태인지 상관없는 ngKeypress를 사용하기 때문에 @doug의 답변에 약간 변형이 있습니다.

function delayChangeDirective($timeout) {
    var directive = {
        restrict: 'A',
        priority: 10,
        controller: delayChangeController,
        controllerAs: "$ctrl",
        scope: true,
        compile: function compileHandler(element, attributes) {
            var expression = attributes['ngKeypress'];
            if (!expression)
                return;

            var ngModel = attributes['ngModel'];
            if (ngModel) {
                attributes['ngModel'] = '$parent.' + ngModel;
            }
            attributes['ngKeypress'] = '$$delay.execute()';

            return {
                post: postHandler,
            };

            function postHandler(scope, element, attributes) {
                scope.$$delay = {
                    expression: expression,
                    delay: scope.$eval(attributes['ngKeypressDelay']),
                    execute: function () {
                        var state = scope.$$delay;
                        state.then = Date.now();
                        if (scope.promise) {
                            $timeout.cancel(scope.promise);
                        }

                        scope.promise = $timeout(function() {
                            delayedActionHandler(scope, state, expression);
                            scope.promise = null;
                        }, state.delay);
                    }
                };
            }
        }
    };

    function delayedActionHandler(scope, state, expression) {
        var now = Date.now();
        if (now - state.then >= state.delay) {
            scope.$parent.$eval(expression);
        }
    };

    return directive;
};

언급URL : https://stackoverflow.com/questions/21121460/angular-directive-encapsulating-a-delay-for-ng-change

반응형