ng-include로 불러온 페이지의 Controller가 두 번 호출되는 문제

2019. 3. 11. 15:15Programming/AngularJS

반응형

임베디드 장비에 서버를 올려서, 장비의 설정을 변경할 수 있는 웹 어플리케이션을 서비스하고 있다. 그건 그렇다치고 몇 년 전부터 골치아픈 문제가 있었는데, ng-include를 사용해서 페이지를 로드했을 때 연결된 Controller가 두 번 호출되고 있었다.

Controller가 두 번씩 호출되는 문제는 생각보다 골치아픈 문제였다. 장비에서 받아오는 데이터가 많으면 많을수록 Controller에서 데이터를 가공하는 코드도 복잡해지기 마련이었는데, Controller가 두 번 로드되면서 초기화하는 코드가 두 번 동작하는 것도 환장할 노릇이었다. 단순히 사용자에게 현재 장비의 설정값을 보여주고, 변경할 수 있게끔 하는 페이지라면 문제는 없었다. 하지만 특정 UI가 다른 UI의 값들과 의존관계가 있다거나, 각각 설정값의 범위나 의존관계가 다른 장비들을 여러대 연동한다면 상당히 골치아픈 문제가 됐다. 안그래도 초기화에 n^2의 시간이 걸리는데, 이 코드가 두 번씩 동작해서 버벅거리기까지 한다.

ng-include page twiceng-include controller twice등으로 검색해보면 상당히 다양한 검색결과를 발견할 수 있다. ng-include same partial page twice in a page, stackOverflow와 같은 내용들이다. 문제는 내가 직면한 문제와는 전혀 다른 문제였다. 1년 전에는 동일한 문제를 좇다가 일정에 가로막혀서 결국 포기했었는데, 이번에는 원인을 파악할 수 있었다.

힌트는 처음 페이지를 로드할때 발생하지 않고, 다른 메뉴를 클릭했을 때 발생한다는 점이었다. AngularJS: when $location changes path and actual path has Query String, it causes that new path is loaded twice times, Radek Anuszewski 페이지와 Common Angular Routing Challenges, Rapid7 Blog를 보다가, $location.path$location.search로 변경해봤다. 주소표시창의 주소는 변경되지 않았지만, Controller는 한번만 호출되고 있었다. 잠깐, 근데 $location.search가 페이지를 이동해주는 녀석이었나?

$location.search는 현재 url의 search part에 대한 getter/setter이다. 즉, 페이지를 로드하는데는 전혀 상관이 없는 녀석이다. 그런데 어째서 $location.search를 호출했는데 페이지가 전환될 수 있었을까?

답은 생각보다 간단했다.

//ng-include로 페이지를 로드하는 html파일 내부
<div ng-include src="'views/' + currentPageId + '.html'"></div>

//메뉴를 클릭했을 때 페이지를 전환해주는 Javascript 내부
$scope.currentPageId = id; 

...

$location.path(id);

html 파일에 바인딩 된 ng-includesrc값을 보면, $scope.currentPageId라는 값을 참조하고 있었다. 그리고 controller내부에 메뉴 클릭시 동작하는 핸들러의, $location.path호출위치 앞에, $scope.currentPageId값을 변경하는 코드가 있었다. $scope.currentPageId가 변경되면서 페이지가 한 번 로드되고, $location.path가 호출될 때 페이지가 다시 한 번 로드되고 있었다. 코드를 작성할 때 발생한 문제였지만, 코드 분석보다 검색 결과에 의지했기 때문에 원인을 발견하기 힘든 문제였다 = ㅅ=

앞으로 검색도 검색이지만, 코드를 먼저 꼼꼼히 분석부터 해야 할 듯 싶었다. 에휴.

반응형