AngularJS에 대해서 간단하게 정리
앵귤러JS라고
데이버 바인딩에 연동되는 AngularJS입니다.
생소하죠?
Jquery만 해도 빡센데 새로운 라이브러리라니....
요즘 다시 한번 느끼지만 백앤드 개발자보다는
프론트앤드 개발자가 짱인거 같습니다...
앵귤러 사이트 http://angularjs.org/ 입니다.
홈화면 입니다.
상단 Devlop 메뉴 클릭해서 들어가시면 됩니다.
API Reference 보시면 됩니다.
- 특징
html 태그 안에 ng-app 라는 속성이 포함되어 있다는 점,
AngularJs 를 로드 한다는 점.
{{ }} 로 감싸진 Angular 표현식이 존재한다는 점.
양방향 데이터 바인딩 구현,
자바스크립트 상에서 MVC 모델을 구현,
다이렉티브로 태그를 커스터마이징 가능
- Angular JS Loading 과정
ng-app 지시어를 통해 AngularJS 의 로딩은 대부분 매우 쉽고 간편하게 이루어집니다.
일부의 경우 스크립트 로더를 사용하는 형태로 수동적으로 어플리케이션으로 시작 할 수 있습니다.
세가지 매우 중요한 과정이 어플리케이션의 로딩 중에 일어나게 됩니다.
dependency injection 을 위해 사용되는 인젝터가 생성
인젝터는 어플리케이션의 모델을 위한 컨텍스트가 되는 루트 스코프를 생성
앵귤러는 그 이후에 ng-app 의 루트 요소로부터 시작점을 삼아 하위요소들을 "컴파일"
한번 어플리케이션이 로딩되고 나면 프라우저에서 어떤 이벤트 (마우스클릭, HTTP 응답, 키 입력 등 ) 가 입력될 때까지 기다리게 됩니다.
이런 이벤트가 일어나게 되면 앵귤러는 이벤트를 인지하고 이 이벤트가 어떤 모델이든 변경시키고 또 그 변화된 것을 찾게되면 앵귤러는 영향을 반영한 뷰를 리플렉트 하게 됩니다.
어플리케이션의 구조는 매우 간단합니다.
Angular.js의 데이터 바인딩 예제
이 예제코드에서 설명해야 할 부분이 좀 있기는 하지만
앵귤러JS 코드에 익숙해져야 합니다.
이 예제에서 보듯이 input에 입력한 내용이 바로 출력됩니다.
동작방식을 설명하자면 ng-model 디렉티브로 input이 양방향 바인딩(two-way binding) 된 것 입니다.
(디렉티브에 대해서는 뒤에서 설명)
그러면 user.name는 어디에 저장되는지가 궁금할텐데 user.name은 $scope에 저장되어 있습니다.
input에 입력할 때마다 스코프의 user.name 객체가 갱신되고 Angular.js의 {{ ... }}
인터폴레이션으로 모델을 출력할 수 있다. 그래서 HTML에서 user.name의 값을 볼 수 있는 것입니다.
input에 입력할 때 user.name이 스코프에 저장되고 인터폴레이션으로 HTML에서 그 값을 보게 됩니다.
어려운 내용은 아니지만 여기서 언급한 $scope는 무엇인가가 궁금할 것인데요
$scope는 기본적으로 컨트롤러와 템플릿을 연결하고
모델을 보광해서 양방향 바인딩을 할 수 있게 하는 객체다. 이 개념은 다음과 같이 표현할 수 있습니다.
즉, 템플릿에서 $scope에 user.name을 설정하면 컨트롤러에서도
user.name에 접근할 수 있습니다.
약간 더 복잡한 예제를 보겠습니다.
가장 먼저 해야할 작업은 Angular 어플리케이션을 정의하는 것입니다.
Angular 어플리케이션을 정의하려면 이름과 의존성에 대한
배열을 받는(1번 줄) Angular 모듈을 생성하면 됩니다.
이어서 app에 컨트롤러를 생성해야 하는데 app module에서 controller 메서드를 호출해서
생성할 수 있는데 이 메서드에 이름과 함수를 전달합니다.
controller 메서드에 전달하는 함수는 양방향 데이터 바인딩에 사용할 $scope
(자세한 내용은 뒤에서 설명)를 파라미터로 받고 이 함수내에서 $scope에 message 문자열을 추가합니다.
뷰 파일에서 body태그에 무언가 추가된 것을 볼 수 있는데
이를 directive라고 합니다.
디렉티브는 HTML에 새로운 기능을 알려 주는 역할을 하는데
이 예제에서는 다음의 두 가지 디렉티브를 사용했습니다.
ng-app은 Angular에게 body 요소가 Anuglar 어플리케이션에 포함되어 있다고 알려줍니다.
즉, body 요소내의 모든 것을 Angular 어플리케이션이 관리하도록 합니다.
일반적으로는 html태그에 사용하고 파라미터는 어플리케이션의 이름으로 모듈에서
사용한 이름과 일치해야 합니다.
ng-controller: 이 디렉티브를 사용하면 해당 요소의 스코프를 컨트롤러에 할당
이 예제에서는 MainCtrl입니다.
그리고 템플릿에서 message를 사용했습니다. 이를 그림으로 표현하면 다음과 같습니다.
아마 이때쯤 $scope에 함수를 바인딩할 수 있는지 궁금할 수 있는데 당연히 가능합니다.
컨트롤러를 보면 $scope에 함수를 연결하는 방법을 알 수 있습니다.
$scope에 연결한 함수에서 인풋에 입력된 값인 $scope.user.name의 문자열을 이어붙혀서
$scope에 message로 추가합니다.
그리고 HTML에서 버튼을 생성하고 ng-click 디렉티브를 사용했습니다.
간단히 얘기하자면 ng-click 디렉티브는 해당 요소를 클릭할 수 있게 만들어서 클릴할 때마다
할당한 함수를 실행하는데 이 예제에서는 greet()를 실행합니다.
input
에서 엔터를 눌러도 동작하지 않는데 여기서는 정상적인 동작입니다.
이 예제는 ng-click
의 동작방식을 보여주기 위한 예제입니다.
디렉티브(Directives)
디렉티브는 무엇인가? 디렉티브는 HTML에게 새로운 동작을 알려주는 방법입니다.
HTML은 아주 강력하기는 하지만 때로는 좀 더 강력했으면 할 때가 있습니다.
정말 그런지 직접 봅시다.
이 코드는 어떤 동작을 할까?
아무런 힌트도 없고 id가 있기는 하지만 이 id가 어떤 역할을 할 지 누가 알까요?
어떤 동작을 하는지 알려면 HTML 파일에 나오는 30개의 자바스크립트 파일중에 하나를 봐야 합니다
이 부분을 찾아내면 위의 HTML이 파이차트를 담는 곳이라는 것을 알 수 있습니다.
여기서 문제점은 페이지에 사용한 모든 자바스크립트 파일을 보지 않으면
페이지가 무엇을 하는지 정확히 알 수 없다는 것입니다.
이제 Angular 어플리케이션의 코드를 보도록 하겠습니다.
훨씬 더 명확하지 않은가요?
파이차트를 추가한다는 간다한 사실뿐만 아니라 크기가 어느정도이고
어떤 데이터가 할당되었는지를 알 수 있습니다.
이 예제에 대해서 궁금하다면 재미삼아 만들어 본 pie-chart 예제에서 확인해 볼 수 있습니다.
내장 디렉티브
이미 ng-app, ng-controller, ng-click, ng-model를 봤지만(Angular는 ng 접두사를 사용)
Angular에는 다수의 내장 디렉티브가 존재
이 내장 디렉티브를 살펴봅시다.
페이지에 어떤 프로퍼티가 true일 때만 보여줄 부분이 있다고 하겠습니다
ng-show는 표현식이 true일때만(예제에서는 바인딩한 값) 해당 요소를 보여줍니다.
이 예제에서 ng-click을 사용한 방법을 주의깊게 보길 바랍니다.
이 예제에서는 컨트롤러에 함수를 생성할 필요가 없으므로(컨트롤러 자체도 필요없다!)
디렉티브의 인자를 표현식으로 작성해서 show의 값을 토글했습니다.
show는 undefined로 시작되고 첫 클릭시 true가 됩니다.
ng-show의 반대인 ng-hide도 있습니다.
좀 더 재밌는 예제를 보죠
객체에 배열이 있고 이 배열의 목록을 출력하고자 하면 어떻게 하겠는가?
컨트롤러에 객체의 리스트를 정의한 것외에는 별로 특별한 내용은 없습니다.
이어서 HTML에서 ng-repeat 디렉티브를 사용했습니다.
ng-repeat는 컬렉션의 아이템마다 새로운 템플릿을 생성할 것입니다.
예제에서는 4개의 아이템이 있으므로 ng-repeat가 이 코드 부분을 4번 생성할 것입니다.
ng-repeat에서 각 복사본은 자신만의 스코프를 가집니다.
그래서 템플릿에서는 컨트롤러가 스코프의 역할을 하지 않고 이 예제에서는 person이 스코프가 됩니다.
다시 말하자면 여기서는 부모 컨트롤러에 대한 접근을 하지 않습니다.
(실제로는 부모 컨트롤러에 접근하는 방법이 있기는 합니다.)
이를 그림으로 표현하면 다음과 같습니다.
자신만의 디렉티브를 만들 수 있는가?
당연히 가능합니다!
거의 모든 것을 만들 수 있는데 모달 다이얼로그, 어코디언, 페이지네이터, 차트, 검색폼 등에 대한
디렉티브를 만들 수 있습니다.
예시로 든 것처럼 항상 보여지는 것이어야 하는 것은 아니고 보이지 않는 부분에 대한
디렉티브를 만들 수도 있습니다.
앞에서 사용했던 greet 예제로 돌아가 봅시다
이 코드는 잘 동작하기는 하지만 페이지를 로딩했을 때 인풋에 포커싱을 주고 싶다면 어떻게 해야 하는가?
jQuery를 사용해서 인풋에 focus()메서드를 호출해야 하는가?
당연히 아닙니다.
우리는 디렉티브에서 HTML이 최대한 자기서술적이 되기를 원하기 때문에 focus 디렉티브를 생성할 것입니다.
그래서 app 객체의 directive 함수를 호출합니다.
directive는 컨트롤러처럼 디렉티브의 이름과 함수를 받습니다.
디렉티브는 Angular.js에서 가장 복잡하지만 (이 글을 쇼케이스같은 글이므로) 간단히만 설명할 것
(추후에 이 주제로 글을 따로 올리겠습니다.)
디렉티브는 객체를 반환해야 하고 이 반환 객체에 몇가지 속성을 정의할 수 있지만
이 예제에서는 속성을 사용하지 않았다. 디렉티브는 link 함수를 반환할 수 있는데
이 link함수 안에 템플릿 로직의 대부분을 작성하고 여기서 DOM 리스너를 등록하거나
DOM을 갱신하는 등의 작업을 할 수 있습니다.
이 link함수는 3개의 파라미터를 받습니다.
(실제로는 4개지만 이는 약간 고급에 해당)
3개의 파라미터는 scope와 디렉티브를 사용한 element와 element의 속성인 attr입니다.
여기서 HTML 요소에 click 이벤트나 mouseenter 이벤트를 바인드할 수 있습니다.
이 예제에서는 첫번째 요소(인풋)을 가져와서 focus함수를 호출했습니다.
element가 어떻게 동작하는지 궁금하면 공식문서 Element API를 참고
이제 남은 작업을 이 디렉티브를 사용하는 것 뿐
포커스를 주고자 하는 요소에 이 디렉티브 이름을 추가하면 된니다.
의도한 기능이 잘 동작하지만 이 디렉티브는 정말 간단합니다.
(이 예제는 블로그 포스트내에서는 제대로 포커스가 동작하지 않으니 JSFiddle에서 직접 확인하기 바람 - 글쓰고 확인할때는 포커싱이 잘 안되어 이렇게 써놨었는데 브라우저에 따라서는 아예 포커스가 옮겨가기도 하는것 같네요. 일단 실행결과가 바로 뜨지 않도록 수정했습니다.)
그러면 HTML을 렌더링하는 디렉티브는 어떻게 작성해야 할까?
다음 예제를 봅시다.
이 예제는 (앞에서 얘기했듯이) 몇 가지 속성이 설정된 객체를 반환합니다.
restrict: 디렉티브는 여러 위치에 사용할 수 있다.
replace: 이 값을 true로 설정하면 해당 요소는 새로운 템플릿으로 대체될 것이다.
template: HTML 요소에 추가할(또는 대체할) 템플릿을 여기에 둔다.
요소에 사용할 디렉티브를 제한하고(기본값은 속성으로 제한된다.)
HTML 요소를 대체할 템플릿을 지정했습니다.
디렉티브에서 사용할 수 있는 많은 옵션이 더 있기는 하지만 추가적인 작업이 좀 더 필요합니다.
이 디렉티브에서는 로직이 필요없으므로 link 함수는 사용하지 않았습니다.
사용방법은 다음 예제를 보실게요
코드를 보면 기대한 대로 hello,/hello가
필터
쇼핑 장바구니를 보여주는 화면이 있다고 하죠
이 예제로 인터폴레이션에서 기본적인 표현식을 사용하는 방법을 알 수 있습니다.
예제에서는 숫자를 출력했는데 당연히 읽을 수 있고 이 숫자가 $1,232.12를 의미한다는 것을 알 수 있지만
숫자를 금액으로 변환해서 보여준다면 훨씬 좋을 것입니다.
이는 필터를 사용하면 쉬운데
다음 예제는 currency 필터를 사용하는 예제입니다.
훨씬 나아졌습니다.
이 예제에서 볼 수 있듯이 |로 필터를 사용할 수 있는데
이는 유닉스 환경에서 파이프를 사용하는 것과 비슷합니다.
표현식에서는 다수의 필터를 파이프로 연결할 수 있는데
예를 들어 ng-repeat에서 정렬을 할 수도 있습니다.
앞에서 보았던 개발자 목록을 출력하는 예제를 다시 봅시다.
이 예제에는 흥미로운 부분이 있는데 필터에 파라미터를 전달했습니다.
orderBy 필터는 정렬에 사용할 값(predicate)를 받습니다.
예제에서는 name을 전달했으므로 name으로 목록을 정렬할 것이고
이 파라미터에 -name를 전달하면 역순으로 정렬할 것입니다.
이정도로도 유용하다고 생각할 것이지만 좀 더 괜찮은 예제를 보겠습니다.
4명의 개발자가 아니라 300명의 개발자가 있고 이를 (name, country등으로) 필터링하기를 원한다고 해보고
이를 위해서 컬렉터를 필터링하는 방법을 정하고 필터링되지 않은 컬렉션을 필터링한 컬렉션으로
교체하려고 할텐데 더 간단한 방법이 있습니다.
(개발자 목록 예제에서 사용한 것과 같은 컨트롤러를 다시 사용합니다.)
놀랍지 않은가요?
이 예제에서는 필터를 사용한 것이 전부인데 filter필터에 담길 파라미터를 전달했습니다.
예제에서 스코프에 바인딩되어 있으면서 인풋에 할당된 search를 전달했습니다.
필요하다면 다음과 같이 좀 더 정밀한 필터를 만들 수도 있습니다.
이 예제에서는(인풋에서 search.name를 바인딩하는 방법을 보세요)
단순히 이름으로 필터링하고 있고 필터 파라미터는 바꾸지 않았다.
필터 파라미터는 search객체에 바인딩되어 있고 입력의 이름을 찾아서 이름으로 필터링합니다.
이번에는 자신만의 필터를 직접 생성해 봅시다
첫글자를 대문자를 필터를 어떻게 작성하는지 봅시다.
필터는 인풋(인터폴레이션의 결과값이다.)과 필터 파라미터를 받는 함수를 반환하고
반환된 함수는 새로운 인풋을 반환합니다.
이 예제에서는 인풋의 첫글자를 대문자로 바꿨습니다.
이제 이 필터를 사용해 봅시다.
문자열을 문자열 리터럴로 만들기 위해 대문자로 감싼 뒤 capitalize 필터를 "파이프"로 연결하면 동작합니다.
서비스
이 글의 마지막 부분인 서비스 입니다.
서비스는 무엇일까? 서비스는 어플리케이션의 어떤 기능을 제공하는 싱글톤 클래스입니다.
어플리케이션 로직을 컨트롤러에 분산시키는 대신 다른 서비스에 로직을 둘 수 있습니다.
Angular에는 HTTP 요청을 관리하는 $http나 프로미스(Promise)에 대한 $q와 같은 많은 내장 서비스가 있습니다.
하지만 내장 서비스는 설명하기가 더 어렵기 때문에 다른 글에서 설명하기로 하고
여기서는 내장 서비스는 따로 설명하지 않을 것입니다.
대신 간단한 서비스를 생성해 봅시다.
서비스를 사용하는 가장 일반적인 경우는 컨트롤러간에 정보를 공유해야하는 경우입니다.
모든 컨트롤러는 자신만의 스코프를 가지므로 다른 컨트롤러의 스코프를 바인딩할 수 없습니다.
이 문제를 해결하기 위해 서비스를 사용하면 한 곳에서 데이터를 가지고 있고
필요한 어디서나 이 데이터를 사용하도록 할 수 있습니다.
우선 문제의 상황을 보기 위해 서비스가 없는 다음 예제를 살펴봅시다
인풋을 같은 모델에 바인딩했으므로 인풋에 글을 쓰면
다른 쪽에도 업데이트 되기를 기대할 것입니다.
즉, 다음과 같은 형태를 기대한 것입니다.
하지만 이런 형태가 되는 것이 아니라 이런 형태가 됩니다.
이 문제를 해결하기 위해 두 컨트롤러에서 사용할 수 있도록 사용자 이름을 가진 서비스를 생성할 것입니다
서비스를 생성하기 위해 app 모듈의 factory 함수를 사용했습니다.
서비스를 생성하는 좀더 고급적인 방법도 있습니다.
(service와 provider 함수를 사용하지만 이는 다른 글에서 설명)
서비스를 생성하는 여러가지 방법이 있지만
이 예제에서는 미리 정의해 놓은 이름으로 private 사용자 객체를 생성해서 반환했습니다.
이 서비스는 컨트롤러에서 다음과 같이 사용
이 예제는 다음과 같이 됩니다.
이 예제는 의도대로 잘 동작합니다.
MainCtrl와 SecondCtrl 양쪽의 $scope.user는 UserInformation를 사용하고
서비스가 싱글톤이기 때문에 한 컨트롤러에서 UserInformation의 값을 바꾸면 다른 쪽에서도 바뀝니다.
여기서 UserInformation 파라미터가 어디서 왔는지 궁금할 것인데
Angular는 서비스를 필요로 하는 곳에 서비스를 주입하는 의존성 주입을 사용합니다.
의존성 주입이 동작하는 방식을 설명하는 것은 이 글의 주제를 벗어나지만
간단히 말하자면 서비스를 생성하면 어느 컨트롤러나 디렉티브, 다른 서비스에도 이 서비스를 주입할 수 있습니다.
주입하는 방법은 그냥 파라미터에 서비스의 이름을 전달하면 됩니다.
아마 이 의존성 주입이 $scope 파라미터를 사용한 것과 같은 것인지 궁금할텐데
$scope는 다른 컨트롤러에 주입되기는 하지만 실제로 서비스는 아닌 예외사항 중 하나입니다.
결론
Angular.js는 뛰어난 프레임워크이고 현재 많이 쓰이고 있습니다.
강추
Congratulations @shinbyron! You received a personal award!
Click here to view your Board
Congratulations @shinbyron! You received a personal award!
You can view your badges on your Steem Board and compare to others on the Steem Ranking
Vote for @Steemitboard as a witness to get one more award and increased upvotes!