뷰가로드 될 때 AngularJS 초기화 코드 실행


93

뷰를로드 할 때 연결된 컨트롤러에서 일부 초기화 코드를 실행하고 싶습니다.

이를 위해 뷰의 주요 요소에 ng-init 지시문을 사용했습니다.

<div ng-init="init()">
  blah
</div>

컨트롤러에서 :

$scope.init = function () {
    if ($routeParams.Id) {
        //get an existing object
        });
    } else {
       //create a new object
    }

    $scope.isSaving = false;
}

첫 번째 질문 : 이것이 올바른 방법입니까?

다음으로, 발생하는 사건의 순서에 문제가 있습니다. 보기에는 다음 ng-disabled과 같은 지시문 을 사용하는 '저장'버튼이 있습니다 .

<button ng-click="save()" ng-disabled="isClean()">Save</button>

isClean()기능은 제어기에 정의 :

$scope.isClean = function () {
    return $scope.hasChanges() && !$scope.isSaving;
}

보시다시피 함수 $scope.isSaving에서 초기화 된 플래그를 사용합니다 init().

문제 : 뷰가로드 될 때 isClean 함수 호출 전에init() 따라서 플래그, 함수 isSaving이다 undefined. 이를 방지하려면 어떻게해야합니까?

답변:


137

뷰가로드되면 연관된 컨트롤러도로드됩니다. 을 사용하는 대신 컨트롤러에서 메서드를 ng-init호출하기 만하면 init()됩니다.

$scope.init = function () {
    if ($routeParams.Id) {
        //get an existing object
    } else {
        //create a new object
    }
    $scope.isSaving = false;
}
...
$scope.init();

컨트롤러가 이전 ng-init에 실행되기 때문에 두 번째 문제도 해결됩니다.

깡깡이


으로 John David Five언급, 당신은이를 첨부하지 않을 수 있습니다 $scope이 방법은 비공개로하기 위해.

var init = function () {
    // do something
}
...
init();

jsFiddle 참조


특정 데이터가 미리 설정 될 때까지 기다리려면 해당 데이터 요청을 해결로 이동하거나 해당 컬렉션 또는 개체에 감시자를 추가하고 데이터가 초기화 기준을 충족 할 때 init 메서드를 호출합니다. 일반적으로 데이터 요구 사항이 충족되면 감시자를 제거하므로보고있는 데이터가 변경되고 init 메서드를 실행하기위한 기준을 충족하는 경우 init 함수가 무작위로 다시 실행되지 않습니다.

var init = function () {
    // do something
}
...
var unwatch = scope.$watch('myCollecitonOrObject', function(newVal, oldVal){
                    if( newVal && newVal.length > 0) {
                        unwatch();
                        init();
                    }
                });

8
초기화를 실행하기 위해 일부 모델의 데이터가 필요한 경우 어떻게합니까? 아니면 렌더링 할 때 페이지에서 사용할 수있는 일부 데이터 만 있으면 초기화가 작동 할 수 있습니까?
Eugene

38
init 함수는 $ scope에 첨부 할 필요가 없습니다. init 기능을 비공개로 만드십시오. init 함수가 두 번 이상 실행되는 것을 원하지 않으므로 $ scope에 노출하지 마십시오.
John David Five

2
내 뷰가 표시 될 때마다 init 함수를 실행하고 싶지만 함수가 한 번만 실행되는 방법에 대한 단서가 없습니다. 모든 페이지 / 템플릿로드에서 어떻게 실행할 수 있습니까?
Jorre 2014

9
저는 각도 전문가는 아니지만,이 접근 방식은 테스트에별로 좋지 않습니다. 왜냐하면 init ()는 단순히 컨트롤러 인스턴스화에서 호출되기 때문입니다. . 시험을 깨다!
Wagner Leonardi 2015 년

1
@WagnerLeonardi가 말한 것. 이 접근 방식은 "개인"init () 메서드를 테스트하는 것을 매우 어렵게 만듭니다.
Steven Rogers

36

AngularJS 1.5부터 우리는$onInit AngularJS 컴포넌트에서 사용할 수있는 것을 사용해야합니다 . v1.5 이후 의 구성 요소 수명주기 문서 에서 가져온 것입니다.

$ onInit ()-요소의 모든 컨트롤러가 구성되고 바인딩이 초기화 된 후 (이 요소의 지시문에 대한 사전 및 사후 연결 함수 이전에) 각 컨트롤러에서 호출됩니다. 컨트롤러에 대한 초기화 코드를 넣을 수있는 좋은 장소입니다.

var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function ($scope) {

    //default state
    $scope.name = '';

    //all your init controller goodness in here
    this.$onInit = function () {
      $scope.name = 'Superhero';
    }
});

>> 바이올린 데모


구성 요소 수명주기 사용의 고급 예 :

컴포넌트 라이프 사이클은 컴포넌트를 좋은 방식으로 처리 할 수있는 능력을 제공합니다. 이를 통해 컴포넌트의 "초기화", "변경"또는 "파괴"와 같은 이벤트를 생성 할 수 있습니다. 이런 식으로 우리는 컴포넌트의 라이프 사이클에 의존하는 것들을 관리 할 수 ​​있습니다. 이 작은 예제는 $rootScope이벤트 리스너 를 등록 및 등록 해제하는 방법을 보여줍니다 $on. 알면, 이벤트 있음 $on에 바인더 제본이 $rootScope컨트롤러는 뷰의 참조를 잃을 때 undinded되지 않거나 파괴지고 우리는 파괴 할 필요가 $rootScope.$on수동으로 리스너를. 그 물건을 넣을 좋은 곳 $onDestroy은 구성 요소의 수명주기 기능입니다.

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

myApp.controller('MyCtrl', function ($scope, $rootScope) {

  var registerScope = null;

  this.$onInit = function () {
    //register rootScope event
    registerScope = $rootScope.$on('someEvent', function(event) {
        console.log("fired");
    });
  }

  this.$onDestroy = function () {
    //unregister rootScope event by calling the return function
    registerScope();
  }
});

>> Fiddle 데모


17

또는 컨트롤러에서 인라인으로 초기화 할 수 있습니다. 컨트롤러 내부의 init 함수를 사용하는 경우 범위에서 정의 할 필요가 없습니다. 실제로 자체 실행될 수 있습니다.

function MyCtrl($scope) {
    $scope.isSaving = false;

    (function() {  // init
        if (true) { // $routeParams.Id) {
            //get an existing object
        } else {
            //create a new object
        }
    })()

    $scope.isClean = function () {
       return $scope.hasChanges() && !$scope.isSaving;
    }

    $scope.hasChanges = function() { return false }
}

1
초기화 코드가 익명 폐쇄에있는 이유가 있습니까?
Adam Tolley 2015 년

@AdamTolley 특별한 이유가 없습니다. 그는 함수를 정의하고 var에 바인딩하지 않고 즉시 호출합니다.
Tair 2015 년

7
이런 식으로 private init () 함수를 어떻게 단위 테스트 할 수 있습니까?
Steven Rogers

공개 멤버 만 단위 테스트를 거칩니다. 단위 테스트는 예상되는 결과를 얻기 위해 개인적으로 클래스가 수행하는 작업에 의존해서는 안됩니다.
Phil

14

내 프로젝트에서 다음 템플릿을 사용합니다.

angular.module("AppName.moduleName", [])

/**
 * @ngdoc controller
 * @name  AppName.moduleName:ControllerNameController
 * @description Describe what the controller is responsible for.
 **/
    .controller("ControllerNameController", function (dependencies) {

        /* type */ $scope.modelName = null;
        /* type */ $scope.modelName.modelProperty1 = null;
        /* type */ $scope.modelName.modelPropertyX = null;

        /* type */ var privateVariable1 = null;
        /* type */ var privateVariableX = null;

        (function init() {
            // load data, init scope, etc.
        })();

        $scope.modelName.publicFunction1 = function () /* -> type  */ {
            // ...
        };

        $scope.modelName.publicFunctionX = function () /* -> type  */ {
            // ...
        };

        function privateFunction1() /* -> type  */ {
            // ...
        }

        function privateFunctionX() /* -> type  */ {
            // ...
        }

    });

이것은 깨끗해 보이지만 iffe는 스코프에서 정의하고있는 메소드를 실행하지 못하게합니다. 종종 우리가해야하는 일이고, 시작할 때 한 번 실행 한 다음 스코프에서도 실행할 수 있도록합니다. 다시 같이 사용자가 필요로
chrismarx

그것은 컨트롤러 - 상단에 실행 않다면 즉,
chrismarx
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.