Вы находитесь на странице: 1из 106

Angular.

, Angular -,
.

Angular?
AngularJS -.
HTML HTML,
. ,
, .
JavaScript,
.
Angular , HTML, . HTML
, . ,
, - ,
.
, :
- , -.
, . , Jquery.
- -, .
, - . ,
knockout, SproutCore ..
Angular . HTML
HTML . Angular ,
, . :
, {{}}.
DOM / DOM .
.
DOM .
HTML .


Angular -. ,
-, . Angular
, CRUD . ,
. Angular :
, CRUD : ,
, , , , ,
.
: -, end-to-end , ,
.

.

Angular
Angular , .
, . ,
Angular. Angular CRUD. CRUD
, , 90% -. , Angular ,
, Angular.
, DOM.
CRUD , , , Angular. ,
- JavaScript, JQuery .

Angular
CRUD , .
, ,
. ,
:
.
, .
.
.
I ndex .htm l

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="InvoiceCntl">
9. <b>Invoice:</b>
10. <br>
11. <br>
12. <table>
13. <tr><td>Quantity</td><td>Cost</td></tr>
14. <tr>
15. <td><input type="number" ng-pattern="/\d+/" step="1" min="0" ng-model="qt
y" required ></td>
16. <td><input type="number" ng-model="cost" required ></td>
17. </tr>
18. </table>
19. <hr>
20. <b>Total:</b> {{qty * cost | currency}}
21. </div>
22. </body>
23. </html>

Script.js

1. function InvoiceCntl($scope) {
2. $scope.qty = 1;
3. $scope.cost = 19.95;
4. }

End to end test

1. it('should show of angular binding', function() {


2. expect(binding('qty * cost')).toEqual('$19.95');
3. input('qty').enter('2');
4. input('cost').enter('5.00');
5. expect(binding('qty * cost')).toEqual('$10.00');
6. });

, , .

<html>, , Angular ng-app. Ng-app


Angular .
<html ng-app>
<script>, Angular.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/?.?.?/angular.mi
n.js"></script>
ng-model <input> ,
.
Quantity: <input type="number" ng-pattern="/\d+/" step="1" min="0" ng-model="
qty" required >

Cost: <input type="number" ng-model="cost" required >


, :
, Angular (qty cost)
. , "" Model-
View-Controller.
, HTML .
, .
CRUD.
, , {{ }}:
Total: {{qty * cost | currency}}

{{_expression_}} Angular .
: {{ expression | filter }}.
Angular .

, Angular ,
, .

, , ,
. ,
, , , .
Angular .

Angular
Angular , , ,
,
-.
, DOM .
.
, ,
. .
, .
, .
, :
, -, .
, , , .
Angular :
: ,
. ,
. JavaScript ,
, , .
HTML DOM : DOM HTML
AJAX, . ,
,
DOM . ,
Angular, DOM, , .
: CRUD
AJAX. HTML-,
, , ,
, ,
. Angular , ,
, .

, Angular, .

Angular <script>
Angular .

<!doctype html>
<html xmlns:ng="http://angularjs.org" ng-app>
<body>
...
<script src="angular.js">
</body>
</html>

<script> .
, .. HTML
. agular
http://code.angularjs.org.
. :
,
- angular-[version].js.
- angular-[version].min.js

ng-app ,
<html>, angular .
<html ng-app>

IE7 id, ng-app.


<html ng-app id="ng-app">

, .
XML. :
<html xmlns:ng="http://angularjs.org">


DOMContentLoaded Angular .
ng-app, .
, :

, .
.
DOM.
DOM angular.

<!doctype html>
<html ng-app="optionalModuleName">
<body>
I can add: {{ 1+2 }}.
<script src="angular.js"></script>
</body>
</html>


,
. , ,
- .
. ng-app.

1. <!doctype html>
2. <html xmlns:ng="http://angularjs.org">
3. <body>
4. Hello {{'World'}}!
5. <script src="http://code.angularjs.org/angular.js"></script>
6. <script>
7. angular.element(document).ready(function() {
8. angular.bootstrap(document);
9. });
10. </script>
11. </body>
12. </html>

, angular (
html).
API angular.bootstrap
.

HTML

HTML angular HTML


. HTML,
. angular
.

HTML
. ,
,
. align=center, .
.

, ..
. 1/3
.
.

Angular ,
. ,
,
.

, .

angular . DOM
. :

1. DOM .
.
2. , (scope)
(view).
,
.
.

, ng-repeat DOM
.
, ,
.
.

.
: , ,
class, . ng-
bind.

1. <span ng-bind="exp"></span>
2. <span class="ng-bind: exp;"></span>
3. <ng-bind></ng-bind>
4. <!-- directive: ng-bind exp -->

, ,
DOM. , .

index.html:

1. <!doctype html>
2. <html ng-app="drag">
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <span draggable>Drag ME</span>
9. </body>
10. </html>

script.js

1. angular.module('drag', []).
2. directive('draggable', function($document) {
3. return function(scope, element, attr) {
4. var startX = 0, startY = 0, x = 0, y = 0;
5. element.css({
6. position: 'relative',
7. border: '1px solid red',
8. backgroundColor: 'lightgrey',
9. cursor: 'pointer'
10. });
11. element.bind('mousedown', function(event) {
12. // Prevent default dragging of selected content
13. event.preventDefault();
14. startX = event.screenX - x;
15. startY = event.screenY - y;
16. $document.bind('mousemove', mousemove);
17. $document.bind('mouseup', mouseup);
18. });
19.
20. function mousemove(event) {
21. y = event.screenY - startY;
22. x = event.screenX - startX;
23. element.css({
24. top: y + 'px',
25. left: x + 'px'
26. });
27. }
28.
29. function mouseup() {
30. $document.unbind('mousemove', mousemove);
31. $document.unbind('mouseup', mouseup);
32. }
33. }
34. });

draggable. ,
. ,
, , HTML.
view.
.
, .
HTML innerHTML.


innerHTML DOM. ,
:

.
.
.
.

Angular . DOM, ,
. ,
(scope) .
.
. .. innerHTML ,
. , angular
, .
DOM,
DOM
. ,
, .

angular,
. :

(startup) .
(runtime) angular .
(scope) .
.
.
, .
HTML.
.
.
.
$ - angular .

, .
,
.

1. HTML
DOM.
2. angular.js angular.
3. Angular DOMContentLoaded.
4. Angular ng-app, .
5. , ng-app ( ) .
6. $compile, $rootScope.
7. $compile DOM
$rootScope.
8. ng-init $scope .
9. {{name}} name
$scope $rootScope.

Index.html

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. </head>
6. <body>
7. <p ng-init=" name='World' ">Hello {{name}}!</p>
8. </body>
9. </html>


, angular .

1.

,

.
2.
,
DOM.
3.

javascript
DOM .

Angular
javascript, . javascript
angular . ,
angular, , ,
.. $apply()
angular javascript. , (, )
$apply() , , .
$apply()

.

1. angular, $scope.$apply(stimulusFn). stimulusFn


,
angular.
2. Angular stimulusFn, .
3. Angular $digest. $digest ,
$evalAsync $watch. $digest ,
, $evalAsync , $watch
.
4. $evalAsync ,
, .
setTimeout(0), ,
, ..
.
5. $watch ,
. , $watch ,
.
6. $digest Angular javascript.
DOM,
.

hello world,
.

1. :
1.1. Ng-model input keydown
input.
1.2. {{name}} name, $watch
name.
2. :
2.1. x input
keydown.
2.2. input input $apply(name=x)
Angular.
2.3. Angular name x.
2.4. $digest.
2.5. $watch name ,
DOM.
2.6. Angular,
keydown, javascript.
2.7. .

Index.html
1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. </head>
6. <body>
7. <input ng-model="name">
8. <p>Hello {{name}}!</p>
9. </body>
10. </html>

(scope)
Scope
. Scope
DOM. ( ,
scope).

, name ,
, .

Index.html

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="GreetCtrl">
9. Hello {{name}}!
10. </div>
11. <div ng-controller="ListCtrl">
12. <ol>
13. <li ng-repeat="name in names">{{name}}</li>
14. </ol>
15. </div>
16. </body>
17. </html>

Style.css

1. .show-scope .doc-example-live.ng-scope,
2. .show-scope .doc-example-live .ng-scope {
3. border: 1px solid red;
4. margin: 3px;
5. }
Script.js

1. function GreetCtrl($scope) {
2. $scope.name = 'World';
3. }
4.
5. function ListCtrl($scope) {
6. $scope.names = ['Igor', 'Misko', 'Vojta'];
7. }

.
.

scope . Scope
,



.


:


javascript,
.


.
(DOM HTML ).
HTML, .
.
.
,
.
(re-skinning), (
), .

Index.html

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="MyCtrl">
9. Hello {{name}}!
10. <button ng-click="action()">
11. OK
12. </button>
13. </div>
14. </body>
15. </html>

script.js

1. function MyCtrl($scope) {
2. $scope.action = function() {
3. $scope.name = 'OK';
4. }
5.
6. $scope.name = 'World';
7. }

,

.

,
scope.
Angular


.

,

. ,
. javascript.

, , .
, , .
Angular
,
:


,
.

HTML,

innerHTML.
.
,
DOM .
Angular
,
DOM, . ,
HTML, ,
DOM, Angular
($compile). DOM ,
$watch. ,
.

Index.html

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. </head>
6. <body>
7. <div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
8. <input ng-model="list" ng-list> <br>
9. <input ng-model="list" ng-list> <br>
10. <pre>list={{list}}</pre> <br>
11. <ol>
12. <li ng-repeat="item in list">
13. {{item}}
14. </li>
15. </ol>
16. </div>
17. </body>
18. </html>

DOM, HTML
, .
HTML,
.
contentEditable.

Index.html

1. <!doctype html>
2. <html ng-app="directive">
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div contentEditable="true" ng-model="content">Edit Me</div>
9. <pre>model = {{content}}</pre>
10. </body>
11. </html>

Style.css

1. div[contentEditable] {
2. cursor: pointer;
3. background-color: #D0D0D0;
4. margin-bottom: 1em;
5. padding: 1em;
6. }

Script.js

1. angular.module('directive', []).directive('contenteditable', function() {


2. return {
3. require: 'ngModel',
4. link: function(scope, elm, attrs, ctrl) {
5. // view -> model
6. elm.bind('blur', function() {
7. scope.$apply(function() {
8. ctrl.$setViewValue(elm.html());
9. });
10. });
11.
12. // model -> view
13. ctrl.$render = function(value) {
14. elm.html(value);
15. };
16.
17. // load init value from DOM
18. ctrl.$setViewValue(elm.html());
19. }
20. };
21. });

.
(
). UNIX .

Index.html

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. </head>
6. <body>
7. <div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
8. Number formatting: {{ 1234567890 | number }} <br>
9. array filtering <input ng-model="predicate">
10. {{ list | filter:predicate | json }}
11. </div>
12. </body>
13. </html>


,

Angular.

.
,


. ,

, .


, .

1. //
2. var myModule = angular.module('myModule', [])
3.
4. //
5. myModule.factory('serviceA', function() {
6. return {
7. // {},
8. };
9. });
10.
11. // 'myModule'
12. var $injector = angular.injector(['myModule']);
13.
14. //
15. var serviceA = $injector.get('serviceA');
16.
17. // , .. .
18. $injector.get('serviceA') === $injector.get('serviceA');

, .
, .

1. // , .
2. function doSomething(serviceA, serviceB) {
3. // do something here.
4. }
5.
6. // Angular
7. var $injector = ...;
8.
9. ///////////////////////////////////////////////
10. // .
11. var serviceA = $injector.get('serviceA');
12. var serviceB = $injector.get('serviceB');
13.
14. //
15. doSomething(serviceA, serviceB);
16.
17. ///////////////////////////////////////////////
18. // .
19. // $injector
20. $injector.invoke(doSomething); //

, ,
. Angular
.

ClockCtrl , ,
. ng-controller ,
, , .
, .

Index.html
1. <!doctype html>
2. <html ng-app="timeExampleModule">
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="ClockCtrl">
9. Current time is: {{ time.now }}
10. </div>
11. </body>
12. </html>

Script.js

1. angular.module('timeExampleModule', []).
2. // , ,
3. //
4. factory('time', function($timeout) {
5. var time = {};
6.
7. (function tick() {
8. time.now = new Date().toString();
9. $timeout(tick, 1000);
10. })();
11. return time;
12. });
13.
14. // ,
15. // .
16. function ClockCtrl($scope, time) {
17. $scope.time = time;
18. }

Angular
Angular $. ,
, .

HTML.
DOM, HTML .
DOM.

Angular ,
, , HTML
(DSL).
HTML.
, ngBind.
, ,
, :, _. x-
data-, , ,
HTML. : ng:bind,
ng_bind, ng-bind, x-ng-bind data-ng-bind.

, , .
myDir (,
).

1. <span my-dir="exp"></span>
2. <span class="my-dir: exp;"></span>
3. <my-dir></my-dir>
4. <!-- directive: my-dir exp -->

,
, .

Index.html

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="Ctrl1">
9. Hello <input ng-model='name'> <hr/>
10. &lt;span ng:bind="name"&gt; <span ng:bind="name"></span> <br/>
11. &lt;span ng_bind="name"&gt; <span ng_bind="name"></span> <br/>
12. &lt;span ng-bind="name"&gt; <span ng-bind="name"></span> <br/>
13. &lt;span data-ng-bind="name"&gt; <span data-ng-bind="name"></span> <br/>
14. &lt;span x-ng-bind="name"&gt; <span x-ng-bind="name"></span> <br/>
15. </div>
16. </body>
17. </html>

Script.js

1. function Ctrl1($scope) {
2. $scope.name = 'angular';
3. }

End to end test


1. it('should show off bindings', function() {
2. expect(element('div[ng-controller="Ctrl1"] span[ng-bind]').text()).toBe('angular
');
3. });


$interpolate
, .
$watch $digest.
.

<a href="img/{{username}}.jpg">Hello {{username}}!</a>

.
HTML :

1. DOM HTML.
, .
, , DOM
.
2. DOM $compile().
DOM, . ,
, DOM.
DOM,
. DOM,
link , . $compile
, ,
.
3. scope, ,
.
, ,
scope.
DOM scope. scope DOM.

4. var $compile = ...; //


5. var scope = ...;
6.
7. var html = '<div ng-bind="exp"></div>';
8.
9. // 1. HTML DOM
10. var template = angular.element(html);
11.
12. // 2.
13. var linkFn = $compile(template);
14.
15. // 3. scope.
16. linkFn(scope);

, 2 ,
. ,
( ).

1. Hello {{user}}, you have these actions:


2. <ul>
3. <li ng-repeat="action in user.actions">
4. {{action.description}}
5. </li>
6. </ul>

, ,
DOM .

,
. {{user}} - , ngRepeat .
ngRepeat . li
user.actions. li
, ul.
li . ,
, {{action.description}}. ,
li, .
, DOM,
. ,
100 ,
.

,
,
li scope.

ngRepeat li . ngRepeat li
. li ,
li, scope.
ngRepeat ,
, scope, li
.

,
DOM,
DOM. ,
,
.
.
DOM
, scope DOM.

( )
, .

Index.html

1. <!doctype html>
2. <html ng-app="time">
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="Ctrl2">
9. Date format: <input ng-model="format"> <hr/>
10. Current time is: <span my-current-time="format"></span>
11. </div>
12. </body>
13. </html>

Script.js

1. function Ctrl2($scope) {
2. $scope.format = 'M/d/yy h:mm:ss a';
3. }
4.
5. angular.module('time', [])
6. // 'myCurrentTime'.
7. // $timeout dateFilter .
8. .directive('myCurrentTime', function($timeout, dateFilter) {
9. // . ( )
10. return function(scope, element, attrs) {
11. var format, //
12. timeoutId; //
13.
14. //
15. function updateTime() {
16. element.text(dateFilter(new Date(), format));
17. }
18.
19. // UI.
20. scope.$watch(attrs.myCurrentTime, function(value) {
21. format = value;
22. updateTime();
23. });
24.
25. //
26. function updateLater() {
27. //
28. timeoutId = $timeout(function() {
29. updateTime(); // DOM
30. updateLater(); //
31. }, 1000);
32. }
33.
34. // destroy UI
35. // .
36. element.bind('$destroy', function() {
37. $timeout.cancel(timeoutId);
38. });
39.
40. updateLater(); // UI.
41. }
42. });

( )
.
. ,
(. ), postLink ,
.

, .

1. var myModule = angular.module(...);


2.
3. myModule.directive('directiveName', function factory(injectables) {
4. var directiveDefinitionObject = {
5. priority: 0,
6. template: '<div></div>',
7. templateUrl: 'directive.html',
8. replace: false,
9. transclude: false,
10. restrict: 'A',
11. scope: false,
12. compile: function compile(tElement, tAttrs, transclude) {
13. return {
14. pre: function preLink(scope, iElement, iAttrs, controller) { ... },
15. post: function postLink(scope, iElement, iAttrs, controller) { ... }
16. }
17. },
18. link: function postLink(scope, iElement, iAttrs) { ... }
19. };
20. return directiveDefinitionObject;
21. });
,
. ,
compile,
.
:

1. var myModule = angular.module(...);


2.
3. myModule.directive('directiveName', function factory(injectables) {
4. var directiveDefinitionObject = {
5. compile: function compile(tElement, tAttrs) {
6. return function postLink(scope, iElement, iAttrs) { ... }
7. }
8. };
9. return directiveDefinitionObject;
10. });

, ,
. postLink.

1. var myModule = angular.module(...);


2.
3. myModule.directive('directiveName', function factory(injectables) {
4. return function postLink(scope, iElement, iAttrs) { ... }
5. });


. ,
.
. $injector.invoke,
.


. :

name (scope).
.
priority , DOM,
.
. ,
.
.
terminal true,
, (
).
scope :
true .
, ,
.
, .
{}( ) .
,
.
,
.
,
.
.
.
@ @attr DOM.
, .. DOM .
, .
<widget my-attr="hello {{name}}">
scope: { localName:'@myAttr' }
widget hello
{{name}}. name,
localName. name (
).
= =attr attr

. attr ,
. <widget my-attr="parentModel">
scope: {
localModel:'=myAttr' },
localModel
parenModel .
parentModel
localModel , .
& &attr .
attr ,
. <widget my-attr="count = count + value">,
scope: { localFn:'&myAttr' },
localFn
count = count + value.
,
,
localFn .
, increment(amount),
localFn,
localFn(amount:22).
controller .
, . (. require).
.
:
$scope , .
$element .
$attrs .
$transclude ,
: function(cloneLinkingFn).
require
. Require .
, . :
? . .
^ - .
restrict ,
EACM,
.
E : <my-directive></my-directive>
A : <div my-directive="exp"> </div>
C : <div class="my-directive: exp;"></div>
M : <!-- directive: my-directive exp -->
template HTML ,
.
.
.
templateUrl , , url.
,
.
replace true,
, .
transclude .
ngTransclude. ,
.
, transclude
, - .

.
true
element , ,
.
compile , .
link , .
, compile .

(compile)
function compile(tElement, tAttrs, transclude) { ... }

DOM.
DOM, . ,
, DOM,
ngRepeat, , ngView.
:
tElement .
.
tAttrs ,
, . . .
transclude : function(scope, cloneLinkingFn).

:
, . ,
, DOM,
. DOM,
, .

, .

link,
,
compile .
pre post,
,
(pre) (post). - -
.

(link)
function link(scope, iElement, iAttrs, controller) { ... }

DOM,
, . .
.

scope ,
$watch.
iElement - , .
postLink
, .
iAttrs ,
, . . .
controller ,
.
, .

- (pre-linking)

, .
DOM, ..
.

- (post-linking)

.
.

link compile,
:

1.
,
.
2. ,
.
3. ,
. .
4.
, $observe.
,

.

1. function linkingFn(scope, elm, attrs, ctrl) {


2. //
3. console.log(attrs.ngModel);
4.
5. //
6. attrs.$set('ngModel', 'new value');
7.
8. //
9. attrs.$observe('ngModel', function(value) {
10. console.log('ngModel has changed value to ' + value);
11. });
12. }

.
. ,
, .

1. <div>
2. <button ng-click="show=true">show</button>
3. <dialog title="Hello {{username}}."
4. visible="show"
5. on-cancel="show = false"
6. on-ok="show = false; doSomething()">
7. Body goes here: {{username}} is {{title}}.
8. </dialog>
9. </div>

show . ,
username, , . ,
.
1. <div ng-show="visible">
2. <h3>{{title}}</h3>
3. <div class="body" ng-transclude></div>
4. <div class="footer">
5. <button ng-click="onOk()">Save changes</button>
6. <button ng-click="onCancel()">Close</button>
7. </div>
8. </div>

, , title,
username. ,
onOk onCancel, .
. , ,
, .

1. scope: {
2. title: '@', //
3. onOk: '&', //
4. onCancel: '&', //
5. visible: '=' //
6. }

1. title ,
.
2. DOM ,
, . title
title .

.

, , .

, DOM
, ,
.
, ( ) .
, - (
).

, .

1. transclude: true,
2. scope: {
3. title: '@', //
4. onOk: '&', //
5. onCancel: '&', //
6. visible: '=' // -
7. },
8. restrict: 'E',
9. replace: true


DOM.
, .

Index.html

1. <!doctype html>
2. <html ng-app="zippyModule">
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="Ctrl3">
9. Title: <input ng-model="title"> <br>
10. Text: <textarea ng-model="text"></textarea>
11. <hr>
12. <div class="zippy" zippy-title="Details: {{title}}...">{{text}}</div>
13. </div>
14. </body>
15. </html>

Style.css

1. .zippy {
2. border: 1px solid black;
3. display: inline-block;
4. width: 250px;
5. }
6. .zippy.opened > .title:before { content: ' '; }
7. .zippy.opened > .body { display: block; }
8. .zippy.closed > .title:before { content: ' '; }
9. .zippy.closed > .body { display: none; }
10. .zippy > .title {
11. background-color: black;
12. color: white;
13. padding: .1em .3em;
14. cursor: pointer;
15. }
16. .zippy > .body {
17. padding: .1em .3em;
18. }

Script.js

1. function Ctrl3($scope) {
2. $scope.title = 'Lorem Ipsum';
3. $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
4. }
5.
6. angular.module('zippyModule', [])
7. .directive('zippy', function(){
8. return {
9. restrict: 'C',
10. // zippy.
11. replace: true,
12. transclude: true,
13. scope: { title:'@zippyTitle' },
14. template: '<div>' +
15. '<div class="title">{{title}}</div>' +
16. '<div class="body" ng-transclude></div>' +
17. '</div>',
18. //
19. link: function(scope, element, attrs) {
20. // Title
21. var title = angular.element(element.children()[0]),
22. // Opened / closed
23. opened = true;
24.
25. // /
26. title.bind('click', toggle);
27.
28. //
29. function toggle() {
30. opened = !opened;
31. element.removeClass(opened ? 'closed' : 'opened');
32. element.addClass(opened ? 'opened' : 'closed');
33. }
34.
35. // zippy
36. toggle();
37. }
38. }
39. });

End to end test

1. it('should bind and open / close', function() {


2. input('title').enter('TITLE');
3. input('text').enter('TEXT');
4. expect(element('.title').text()).toEqual('Details: TITLE...');
5. expect(binding('text')).toEqual('TEXT');
6.
7. expect(element('.zippy').prop('className')).toMatch(/closed/);
8. element('.zippy > .title').click();
9. expect(element('.zippy').prop('className')).toMatch(/opened/);
10. });

JavaScript ,
. ( {{expression}}).
$parse.

Angular:

1+2
3*10 | currency
user.name

Angular JavaScript
, Angular JavaScript. Angular
eval(), . Angular JavaScript :

angular ,
JavaScript .
angular null,
JavaScript NullPointerExceptions.
angular
, .
angular
. .

JavaScript,
. eval()
JavaScript angular, $eval().

Index.html

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. </head>
6. <body>
7. 1+2={{1+2}}
8. </body>
9. </html>

Ent to end test

1. it('should calculate expression in binding', function() {


2. expect(binding('1+2')).toEqual('3');
3. });

, :

Index.html

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="Cntl2" class="expressions">
9. Expression:
10. <input type='text' ng-model="expr" size="80"/>
11. <button ng-click="addExp(expr)">Evaluate</button>
12. <ul>
13. <li ng-repeat="expr in exprs">
14. [ <a href="" ng-click="removeExp($index)">X</a> ]
15. <tt>{{expr}}</tt> => <span ng-bind="$parent.$eval(expr)"></span>
16. </li>
17. </ul>
18. </div>
19. </body>
20. </html>

Script.js

1. function Cntl2($scope) {
2. var exprs = $scope.exprs = [];
3. $scope.expr = '3*10|currency';
4. $scope.addExp = function(expr) {
5. exprs.push(expr);
6. };
7.
8. $scope.removeExp = function(index) {
9. exprs.splice(index, 1);
10. };
11. }

End to end test


1. it('should allow user expression testing', function() {
2. element('.expressions :button').click();
3. var li = using('.expressions ul').repeater('li');
4. expect(li.count()).toBe(1);
5. expect(li.row(0)).toEqual(["3*10|currency", "$30.00"]);
6. });


. JavaScript,
, $window. ,
alert() ,
$window.alert(). ,
( ).

Index.html

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div class="example2" ng-controller="Cntl1">
9. Name: <input ng-model="name" type="text"/>
10. <button ng-click="greet()">Greet</button>
11. </div>
12. </body>
13. </html>

Script.js

1. function Cntl1($window, $scope){


2. $scope.name = 'World';
3.
4. $scope.greet = function() {
5. ($window.mockWindow || $window).alert('Hello ' + $scope.name);
6. }
7. }

End to end test

1. it('should calculate expression in binding', function() {


2. var alertText;
3. this.addFutureAction('set mock', function($window, $document, done) {
4. $window.mockWindow = {
5. alert: function(text){ alertText = text; }
6. };
7. done();
8. });
9. element(':button:contains(Greet)').click();
10. expect(this.addFuture('alert text', function(done) {
11. done(null, alertText);
12. })).toBe('Hello World');
13. });



null. JavaScript a.b.c , a
b. , angular
, :

{{a.b.c}}

,
, .
,
, , : {{((a||{}).b||{}).c}}.

null,
undefined.


.
angular, ,
. ,
, .


, . , ,
,
. , :

name | uppercase
name uppercase,
. :

value | filter1 | filter2

,
:

123 | number:2
$
, . angular api
. angular , a.length(),
undefined, a, angular .

, angular ,
. ,
, .
, .

(input, select, textarea) .



. ,
, , .
.


ngModel.
,
. , api, ,
.

Index.html

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="Controller">
9. <form novalidate class="simple-form">
10. Name: <input type="text" ng-model="user.name" /><br />
11. E-mail: <input type="email" ng-model="user.email" /><br />
12. Gender: <input type="radio" ng-model="user.gender" value="male" />male
13. <input type="radio" ng-model="user.gender" value="female" />female<br />
14. <button ng-click="reset()">RESET</button>
15. <button ng-click="update(user)">SAVE</button>
16. </form>
17. <pre>form = {{user | json}}</pre>
18. <pre>master = {{master | json}}</pre>
19. </div>
20. </body>
21. </html>
Script.js

1. function Controller($scope) {
2. $scope.master= {};
3.
4. $scope.update = function(user) {
5. $scope.master= angular.copy(user);
6. };
7.
8. $scope.reset = function() {
9. $scope.user = angular.copy($scope.master);
10. };
11.
12. $scope.reset();
13. }

: novalidate
.

CSS
, ngModel
:

ng-valid
ng-invalid
ng-pristine
ng-dirty

CSS,
. user.name user.email ,
, . ,
, ,
.

Index.html

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="Controller">
9. <form novalidate class="css-form">
10. Name:
11. <input type="text" ng-model="user.name" required /><br />
12. E-mail: <input type="email" ng-model="user.email" required /><br />
13. Gender: <input type="radio" ng-model="user.gender" value="male" />male
14. <input type="radio" ng-model="user.gender" value="female" />female<br />
15. <button ng-click="reset()">RESET</button>
16. <button ng-click="update(user)">SAVE</button>
17. </form>
18. </div>
19.
20. <style type="text/css">
21. .css-form input.ng-invalid.ng-dirty {
22. background-color: #FA787E;
23. }
24.
25. .css-form input.ng-valid.ng-dirty {
26. background-color: #78FA89;
27. }
28. </style>
29. </body>
30. </html>

Script.js

1. function Controller($scope) {
2. $scope.master = {};
3.
4. $scope.update = function(user) {
5. $scope.master = angular.copy(user);
6. };
7.
8. $scope.reset = function() {
9. $scope.user = angular.copy($scope.master);
10. };
11.
12. $scope.reset();
13. }


FormController. , ,
, name. ,
NgModelController. ,
name. ,
, .

, .
, .
, user.email user.agree.

Index.html

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="Controller">
9. <form name="form" class="css-form" novalidate>
10. Name:
11. <input type="text" ng-model="user.name" name="uName" required /><br />
12. E-mail:
13. <input type="email" ng-model="user.email" name="uEmail" required/><br />
14. <div ng-show="form.uEmail.$dirty && form.uEmail.$invalid">Invalid:
15. <span ng-show="form.uEmail.$error.required">Tell us your email.</span>
16. <span ng-show="form.uEmail.$error.email">This is not a valid email.</spa
n>
17. </div>
18.
19. Gender: <input type="radio" ng-model="user.gender" value="male" />male
20. <input type="radio" ng-model="user.gender" value="female" />female<br />
21.
22. <input type="checkbox" ng-model="user.agree" name="userAgree" required />
23. I agree: <input ng-show="user.agree" type="text" ng-model="user.agreeSign"
24. required /><br />
25. <div ng-show="!user.agree || !user.agreeSign">Please agree and sign.</div>
26.
27. <button ng-click="reset()" ng-disabled="isUnchanged(user)">RESET</button>
28. <button ng-click="update(user)"
29. ng-disabled="form.$invalid || isUnchanged(user)">SAVE</button>
30. </form>
31. </div>
32. </body>
33. </html>

Script.js

1. function Controller($scope) {
2. $scope.master= {};
3.
4. $scope.update = function(user) {
5. $scope.master= angular.copy(user);
6. };
7.
8. $scope.reset = function() {
9. $scope.user = angular.copy($scope.master);
10. };
11.
12. $scope.isUnchanged = function(user) {
13. return angular.equals(user, $scope.master);
14. };
15.
16. $scope.reset();
17. }


Angular
HTML5 (text, number, url, email, radio, checkbox),
(required, pattern, minlength, maxlength, min, max).
, ,
ngModel. ,
, . :

1. ,
, NgModelController#$formatters,

NgModelController#$setValidity.
2. ,
, NgModelController#$setViewValue.
NgModelController#$parsers,

NgModelController#$setValidity.

1. integer , .
1,23 , .. .
, unshift parsers,
. , ,
, .
2. smart-float. 1,2 1.2
1.2.
number, ..
.

Index.html

1. <!doctype html>
2. <html ng-app="form-example1">
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="Controller">
9. <form name="form" class="css-form" novalidate>
10. <div>
11. Size (integer 0 - 10):
12. <input type="number" ng-model="size" name="size"
13. min="0" max="10" integer />{{size}}<br />
14. <span ng-show="form.size.$error.integer">This is not valid integer!</spa
n>
15. <span ng-show="form.size.$error.min || form.size.$error.max">
16. The value must be in range 0 to 10!</span>
17. </div>
18.
19. <div>
20. Length (float):
21. <input type="text" ng-model="length" name="length" smart-float />
22. {{length}}<br />
23. <span ng-show="form.length.$error.float">
24. This is not a valid float number!</span>
25. </div>
26. </form>
27. </div>
28. </body>
29. </html>

Script.js

1. var app = angular.module('form-example1', []);


2.
3. var INTEGER_REGEXP = /^\-?\d*$/;
4. app.directive('integer', function() {
5. return {
6. require: 'ngModel',
7. link: function(scope, elm, attrs, ctrl) {
8. ctrl.$parsers.unshift(function(viewValue) {
9. if (INTEGER_REGEXP.test(viewValue)) {
10. // it is valid
11. ctrl.$setValidity('integer', true);
12. return viewValue;
13. } else {
14. // it is invalid, return undefined (no model update)
15. ctrl.$setValidity('integer', false);
16. return undefined;
17. }
18. });
19. }
20. };
21. });
22.
23. var FLOAT_REGEXP = /^\-?\d+((\.|\,)\d+)?$/;
24. app.directive('smartFloat', function() {
25. return {
26. require: 'ngModel',
27. link: function(scope, elm, attrs, ctrl) {
28. ctrl.$parsers.unshift(function(viewValue) {
29. if (FLOAT_REGEXP.test(viewValue)) {
30. ctrl.$setValidity('float', true);
31. return parseFloat(viewValue.replace(',', '.'));
32. } else {
33. ctrl.$setValidity('float', false);
34. return undefined;
35. }
36. });
37. }
38. };
39. });

(
ngModel)
Angular (input, select, textarea),
. , ,
.

, ngModel
, :

$render, ,
NgModelController#$formatters.
NgModelController#$setViewValue ,
.

$compileProvider.directive .

,
.

Index.html

1. <!doctype html>
2. <html ng-app="form-example2">
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div contentEditable="true" ng-model="content" title="Click to edit">Some</div
>
9. <pre>model = {{content}}</pre>
10.
11. <style type="text/css">
12. div[contentEditable] {
13. cursor: pointer;
14. background-color: #D0D0D0;
15. }
16. </style>
17. </body>
18. </html>

Script.js
1. angular.module('form-example2', []).directive('contenteditable', function() {
2. return {
3. require: 'ngModel',
4. link: function(scope, elm, attrs, ctrl) {
5. // view -> model
6. elm.bind('blur', function() {
7. scope.$apply(function() {
8. ctrl.$setViewValue(elm.html());
9. });
10. });
11.
12. // model -> view
13. ctrl.$render = function() {
14. elm.html(ctrl.$viewValue);
15. };
16.
17. // load init value from DOM
18. ctrl.$setViewValue(elm.html());
19. }
20. };
21. });

i18n l10n
i18n l10n Angular.
, i18n, ,
. , l10n,
.

( , ) .
, .

angular i18n l10n?

angular i18n l10n ,


.

angular
ngPluralize.

angular
$locale.

, , ,
, Angular
. Github, i18n/l10n
Angular.

?
, .
, :
. en-US, en-AU, zh-CH, ,
. ,
, en, zh. ICU
.

angular?

Angular
. .

Angular.
Angular :

Angular.

,
angular.

*nix ,
, :

cat angular.js i18n/angular-locale_de-ge.js > angular_de-ge.js

angular_de-ge.js,
angular.js, Angular .

js index.html

index.html.
index.html :

1. <html ng-app>
2. <head>
3. .
4. <script src="angular.js"></script>
5. <script src="i18n/angular-locale_de-ge.js"></script>
6. .
7. </head>
8. </html>

, (
index.html, angular-locale.js) ,
. ,
.

, , ..
.

gotcha

Angular ,
$locale,
, .
, . ,
,
, .

, 1000$,
, {{1000 | currency}},
, 1000 .
.

.
, .

gotcha

, ,
. ,
,
.

, angular datetime .
angular, JavaScript
.

IE

IE.
angular IE8.0 .


, Angular IE, , :

1. IE JSON.stringify (IE7.0 ), ,
JSON2 JSON3 .

1. <!doctype html>
2. <html xmlns:ng="http://angularjs.org">
3. <head>
4. <!--[if lte IE 8]>
5. <script src="/path/to/json2.js"></script>
6. <![endif]-->
7. </head>
8. <body>
9. ...
10. </body>
11. </html>

2. id=ng-app , ng-app.

1. <!doctype html>
2. <html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="optionalModuleName">
3. ...
4. </html>

3. , <ng:view>,
- <div ng-view>,

4. ,
, IE:

1. <!doctype html>
2. <html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="optionalModuleName">
3. <head>
4. <!--[if lte IE 8]>
5. <script>
6. document.createElement('ng-include');
7. document.createElement('ng-pluralize');
8. document.createElement('ng-view');
9.
10. // Optionally these for CSS
11. document.createElement('ng:include');
12. document.createElement('ng:pluralize');
13. document.createElement('ng:view');
14. </script>
15. <![endif]-->
16. </head>
17. <body>
18. ...
19. </body>
20. </html>

xmlns:ng - namespace,
, .

document.createElement(yourTagName), IE.


IE ,
HTML. , :
my:,
XML, <html xmlns:my="ignored">
:, HTML,
document.createElement('my-tag')
CSS,
document.createElement('my-tag')
.

, ,
.

, ?

, myTag ( , ).

1. <html>
2. <body>
3. <mytag>some text</mytag>
4. </body>
5. </html>

DOM.

1. #document
2. +- HTML
3. +- BODY
4. +- mytag
5. +- #text: some text

, BODY mytag,
. IE , :

1. #document
2. +- HTML
3. +- BODY
4. +- mytag
5. +- #text: some text
6. +- /mytag

, BODY :

mytag. , <br/>.
, / .
, , mytag,
.
/ mytag. ,
/. ,
DOM, .

CSS
CSS
document.createElement('my-tag') , ,
.

1. <html xmlns:ng="needed for ng: namespace">


2. <head>
3. <!--[if lte IE 8]>
4. <script>
5. // needed to make ng-include parse properly
6. document.createElement('ng-include');
7.
8. // needed to enable CSS reference
9. document.createElement('ng:view');
10. </script>
11. <![endif]-->
12. <style>
13. ng\\:view {
14. display: block;
15. border: 1px solid red;
16. }
17.
18. ng-include {
19. display: block;
20. border: 1px solid blue;
21. }
22. </style>
23. </head>
24. <body>
25. <ng:view></ng:view>
26. <ng-include></ng-include>
27. ...
28. </body>
29. </html>

Angular , JavaScript.
(HTML, CSS, JavaScript),
- .

, angular
, . Angular
, :

DOM

,
, .

, angular ,
, ..:

,

( -,
)
( )
HTML ( JavaScript)

.
Angular -,
. ,
, .

Angular ,
- .
, angular .
.

?
,
. Angular . ,
. :


- ,
-.
,
end-to-end

.
/ (-
).

, . Hello world ?

Module API
myApp ng-app="myApp",
.
:
I ndex .htm l
1. <!doctype html>
2. <html ng-app="myApp">
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div>
9. {{ 'World' | greet }}
10. </div>
11. </body>
12. </html>

Script.js

1. //
2. var myAppModule = angular.module('myApp', []);
3.
4. // .
5. //
6. myAppModule.filter('greet', function() {
7. return function(name) {
8. return 'Hello, ' + name + '!';
9. };
10. });


, .
, , :

Service , .
Directives ,
Filters ,
, ,
.
, ,
, . ,
. ,
.

, , .

:
I ndex .htm l

1. <!doctype html>
2. <html ng-app="xmpl">
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="XmplController">
9. {{ greeting }}!
10. </div>
11. </body>
12. </html>

Script.js

1. angular.module('xmpl.service', []).
2. value('greeter', {
3. salutation: 'Hello',
4. localize: function(localization) {
5. this.salutation = localization.salutation;
6. },
7. greet: function(name) {
8. return this.salutation + ' ' + name + '!';
9. }
10. }).
11. value('user', {
12. load: function(name) {
13. this.name = name;
14. }
15. });
16.
17. angular.module('xmpl.directive', []);
18.
19. angular.module('xmpl.filter', []);
20.
21. angular.module('xmpl', ['xmpl.service', 'xmpl.directive', 'xmpl.filter']).
22. run(function(greeter, user) {
23. // This is effectively part of the main method initialization code
24. greeter.localize({
25. salutation: 'Bonjour'
26. });
27. user.load('World');
28. })
29.
30.
31. // A Controller for your app
32. var XmplController = function($scope, greeter, user) {
33. $scope.greeting = greeter.greet(user.name);
34. }


,
.
:

1. .
.
, .
2. ,
. .
.

1. angular.module('myModule', []).
2. config(function(injectables) { // provider-injector
3. // .
4. // .
5. // ( )
6. // .
7. }).
8. run(function(injectables) { // instance-injector
9. // .
10. // .
11. // ( )
12. //
13. });


, . :

1. angular.module('myModule', []).
2. value('a', 123).
3. factory('a', function() { return 123; }).
4. directive('directiveName', ...).
5. filter('filterName', ...);
6.
7. //
8.
9. angular.module('myModule', []).
10. config(function($provide, $compileProvider, $filterProvider) {
11. $provide.value('a', 123);
12. $provide.factory('a', function() { return 123; });
13. $compileProvider.directive('directiveName', ...);
14. $filterProvider.register('filterName', ...);
15. });

, .
,
.

Angular .
. .
, -,
, -
.

, . ,
.
,
. .
, .


- $injector,
VM. , ,
Angular. , VM
, ,
.



. ,
. . ,
, , VM.
, :

1. angular.module('greetMod', []).
2.
3. factory('alert', function($window) {
4. return function(text) {
5. $window.alert(text);
6. }
7. }).
8.
9. value('salutation', 'Hello').
10.
11. factory('greet', function(alert, salutation) {
12. return function(name) {
13. alert(salutation + ' ' + name + '!');
14. }
15. });

1. describe('myApp', function() {

1. // ,
2. // $window mock ,
3. // $window.alert
4. // .
5. // .
6. beforeEach(module('greetMod', function($provide) {
7. $provide.value('$window', {
8. alert: jasmine.createSpy('alert')
9. });
10. }));
11.
12. // inject() injector greet
13. // $window . ,
14. // .
15. it('should alert on $window', inject(function(greet, $window) {
16. greet('World');
17. expect($window.alert).toHaveBeenCalledWith('Hello World!');
18. }));
19.
20. //
21. // .
22. it('should alert using the alert service', function() {
23. var alertSpy = jasmine.createSpy('alert');
24. module(function($provide) {
25. $provide.value('alert', alertSpy);
26. });
27. inject(function(greet) {
28. greet('World');
29. expect(alertSpy).toHaveBeenCalledWith('Hello World!');
30. });
31. });
32. });

?
, .
. , DOM
. .


($watch)
.
($apply)
, Angular " (,
, Angular ).
, ,
. ()
.
, . {{username}}
, ,
username.

,
.
$watch,
. $watch
, DOM.

, .
, DOM. ,
, .
:

Index.html
1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="MyController">
9. Your name:
10. <input type="text" ng-model="username">
11. <button ng-click='sayHello()'>greet</button>
12. <hr>
13. {{greeting}}
14. </div>
15. </body>
16. </html>

Script.js

1. function MyController($scope) {
2. $scope.username = 'World';
3.
4. $scope.sayHello = function() {
5. $scope.greeting = 'Hello ' + $scope.username + '!';
6. };
7. }

, MyController username world


. ,
. ,
.
,
sayHello, , "". sayHello
username . ,
, HTML .
{{ greeting }} :

, DOM , {{
greeting }}. , ,
MyController. ( .)
greeting ,
.

, ,
.
.
, , ..
, .

1. it('should say hello', function() {


2. var scopeMock = {};
3. var cntl = new MyController(scopeMock);
4.
5. // Assert that username is pre-filled
6. expect(scopeMock.username).toEqual('World');
7.
8. // Assert that we read new username and greet
9. scopeMock.username = 'angular';
10. scopeMock.sayHello();
11. expect(scopeMock.greeting).toEqual('Hello angular!');
12. });


angular ,
.
,
(. , ,
). ,
. , DOM,
.
Angular {{username}}, ,
, . ,
, , .
JavaScript ,
.
, .
I ndex .htm l

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="EmployeeController">
9. Manager: {{employee.name}} [ {{department}} ]<br>
10. Reports:
11. <ul>
12. <li ng-repeat="employee in employee.reports">
13. {{employee.name}} [ {{department}} ]
14. </li>
15. </ul>
16. <hr>
17. {{greeting}}
18. </div>
19. </body>
20. </html>

Style.css

1. /* remove .doc-example-live in jsfiddle */


2. .doc-example-live .ng-scope {
3. border: 1px dashed red;
4. }
Script.js

1. function EmployeeController($scope) {
2. $scope.department = 'Engineering';
3. $scope.employee = {
4. name: 'Joe the Manager',
5. reports: [
6. {name: 'John Smith'},
7. {name: 'Mary Run'}
8. ]
9. };
10. }

, Angular ng-scope ,
. <style>
. , ,
{{ employee.name }}
. {{
department }}, ,
, .

DOM.
DOM $scope, .
(,
.) , DOM,
ng-app. ng-app <html>,
, , , ,
Angular.
:
1.
" . .
2. ,
$0.
3. : angular.element
($0).scope().


DOM.
.
:
I ndex .htm l

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="EventController">
9. Root scope <tt>MyEvent</tt> count: {{count}}
10. <ul>
11. <li ng-repeat="i in [1]" ng-controller="EventController">
12. <button ng-click="$emit('MyEvent')">$emit('MyEvent')</button>
13. <button ng-click="$broadcast('MyEvent')">$broadcast('MyEvent')</button>
14. <br>
15. Middle scope <tt>MyEvent</tt> count: {{count}}
16. <ul>
17. <li ng-repeat="item in [1, 2]" ng-controller="EventController">
18. Leaf scope <tt>MyEvent</tt> count: {{count}}
19. </li>
20. </ul>
21. </li>
22. </ul>
23. </div>
24. </body>
25. </html>

Script.js

1. function EventController($scope) {
2. $scope.count = 0;
3. $scope.$on('MyEvent', function() {
4. $scope.count++;
5. });
6. }



JavaScript. DOM
.
Angular, Angular
. Angular
, $apply. ,
$apply Angular. ,
DOM, ng-click $apply.
, $apply $digest. $digest
$watch . .
, , $ scope.username = "angular"
$watch, , $watch
$digest. ,
$watch , , $watch
$watch . $watch ,
$digest.

1.
$injector.
.

2. Watcher
.
DOM.

3.
$aplly. (Angular API
, $aplly ,
a $http $timeout.

4.
$apply, Angular $digest ,
. $digest, $watch
, $watch
.
5.
, , API
$destroy. $digest
, .


, DOM.
:
, {{expression}},
$watch (). ,
.
, ng-click, DOM.
DOM,
$apply().
(, , XHR) ,
$apply(),
.


, , .
, , ng-controller ng-repeat,
DOM.
DOM angular.element(aDomElement).scope().


:
(.
ng-controller).
(), (
).
.
, .
. ng-controller .

$watch

Angular .
, DOM, .. DOM ,
JavaScript.


(DI) ,
.
DI Dependency Injection, Inversion of Control ,
DI .

DI
, :
1. , new.
2. .
3. , .
,
. , , .
,
.
,
. .

1. function SomeClass(greeter) {
2. this.greeter = greeter;
3. }
4.
5. SomeClass.prototype.doSomething = function(name) {
6. this.greeter.greet(name);
7. }

SomeClass , greeter,
.
, ,
SomeClass.
, Angular
. , .
:

1. //
2. angular.module('myModule', []).
3.
4. // 'greeter'
5. // greeter '$window'
6. factory('greeter', function($window) {
7. //
8. // 'greet'.
9. return {
10. greet: function(text) {
11. $window.alert(text);
12. }
13. };
14. });
15.
16. // .
17. // ( Angular)
18. var injector = angular.injector(['myModule', 'ng']);
19.
20. //
21. var greeter = injector.get('greeter');

, ,
. .
, ,
:

1. <! HTML -->


2. <div ng-controller="MyController">
3. <button ng-click="sayHello()">Hello</button>
4. </div>

1. //
2. function MyController($scope, greeter) {
3. $scope.sayHello = function() {
4. greeter.greet('Hello World');
5. };
6. }
7.
8. // 'ng-controller'
9. injector.instantiate(MyController);

, ng-controller,
MyController , . .
, , .
.


, ?
,
. Angular, API
, API. ,
. .
.


,
.

1. function MyController($scope, greeter) {


2. ...
3. }


. $scope greeter
, .
, JavaScript /
, .
-.

$inject
-
, $inject. $inject
.

1. var MyController = function(renamed$scope, renamedGreeter) {


2. ...
3. }
4. MyController.$inject = ['$scope', 'greeter'];

, $inject ,
.
,
.

$inject, , .
:

1. someModule.factory('greeter', function($window) {
2. ...
3. });

, :

1. var greeterFactory = function(renamed$window) {


2. ...
3. };
4.
5. greeterFactory.$inject = ['$window'];
6.
7. someModule.factory('greeter', greeterFactory);

1. someModule.factory('greeter', ['$window', function(renamed$window) {


2. ...
3. }]);

, ,
Angular .

DI?
DI Angular . .
DI
, .
:

1. var MyController = function($scope, dep1, dep2) {


2. ...
3. $scope.aMethod = function() {
4. ...
5. }
6. }
7. MyController.$inject = ['$scope', 'dep1', 'dep2'];


Angular. ,
. , ,
:

1. angular.module('myModule', []).
2. config(['depProvider', function(depProvider){
3. ...
4. }]).
5. factory('serviceId', ['depService', function(depService) {
6. ...
7. }]).
8. directive('directiveName', ['depService', function(depService) {
9. ...
10. }]).
11. filter('filterName', ['depService', function(depService) {
12. ...
13. }]).
14. run(['depService', function(depService) {
15. ...
16. }]);

MVC Angular
-- (MVC) ,
, , Angular MVC
-.

MVC :
, ,

MVC Angular ,
.

, Angular MVC -
:


Angular
, (,
) ( ).
Angular ,
Angular. , , JavaScript
( ).
, JavaScript Angular,
Angular . .
,
JavaScript :
JavaScript-;
:
function MyCtrl($scope) {

// create property 'foo' on the MyCtrl's scope

// and assign it an initial value 'bar'

$scope.foo = 'bar';

}
Angular :

<button ng-click="{{foos='ball'}}">Click me</button>

ng-init (
).

<body ng-init=" foo = 'bar' ">

Angular ( )
:

input, select, textarea .

<input ng-model="query" value="fluffy cloud">

query fluffy
cloud.
ng-repeat

<p ng-repeat="phone in phones"></p>



phones phone () phone
.
Angular, JavaScript :
Angular , .
Angular , , ,
.
, .

Angular JavaScript (/),
, . Angular
scope.$new() API,
. Angular,
.
:
.
.


, Angular
.
Angular ( JavaScript function#apply)
, . , Angular
( new
). .
. :
function GreetingCtrl($scope) { $scope.greeting = 'Hola!'; }
GreetingCtrl greeting, .
:
. -
Angular controller() , :

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


myApp.controller (GreetingCtrl, [$scope, function($scope) {$scope.greeting = Hola!;}]);

,
$scope, Angular.


Angular ,
.
.
, ( ),
. ,
Angular
, (, ng-click).


, . -
.
,
, ,
.
.
:
DOM -.
DOM .
-.
Angular DOM.
DOM, .
Angular .
Angular .
, Angular.
(,
).
Angular
, API
scope.$new(), ngController $route.


, Angular ,
:

, spice
, spice
spice,
very. , , spice chili
jalapeo, .

Spicy

1. <body ng-controller="SpicyCtrl">
2. <button ng-click="chiliSpicy()">Chili</button>
3. <button ng-click="jalapenoSpicy()">Jalapeo</button>
4. <p>The food is {{spice}} spicy!</p>
5. </body>
6.
7. function SpicyCtrl($scope) {
8. $scope.spice = 'very';
9. $scope.chiliSpicy = function() {
10. $scope.spice = 'chili';
11. }
12. $scope.jalapenoSpicy = function() {
13. $scope.spice = 'jalapeo';
14. }
15. }

:
NgController ()
, () SpicyCtrl .
SpicyCtrl JavaScript. ()
Ctrl Controller.
$scope .
(
chiliSpicy)
( body ).
NB: Angular (pre 1.0 RC) this $scope,
. , this $scope
(Angular this = $scope),
.
NB: Angular(pre 1.0 RC)
, ;
.
,
.

1. <body ng-controller="SpicyCtrl">
2. <input ng-model="customSpice" value="wasabi">
3. <button ng-click="spicy('chili')">Chili</button>
4. <button ng-click="spicy(customSpice)">Custom spice</button>
5. <p>The food is {{spice}} spicy!</p>
6. </body>
7.
8. function SpicyCtrl($scope) {
9. $scope.spice = 'very';
10. $scope.spicy = function(spice) {
11. $scope.spice = spice;
12. }
13. }

, SpicyCtrl spicy,
spice.
'chili'
customSpice ( ) .


Angular .
:

1. <body ng-controller="MainCtrl">
2. <p>Good {{timeOfDay}}, {{name}}!</p>
3. <div ng-controller="ChildCtrl">
4. <p>Good {{timeOfDay}}, {{name}}!</p>
5. <p ng-controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
6. </div>
7. </body>
8.
9. function MainCtrl($scope) {
10. $scope.timeOfDay = 'morning';
11. $scope.name = 'Nikki';
12. }
13.
14. function ChildCtrl($scope) {
15. $scope.name = 'Mattie';
16. }
17.
18. function BabyCtrl($scope) {
19. $scope.timeOfDay = 'evening';
20. $scope.name = 'Gingerbreak Baby';
21. }

ngController .
4 :


MainCtrl, timeOfDay name
ChildCtrl, name
timeOfDay.
BabyCtrl, , timeOfDay
MainCtrl name, ChildCtrl

, .
, , ,
.
: ,
, , , Angular,
.


, , ,
$rootScope $controller.

1. function myController($scope) {
2. $scope.spices = [{"name":"pasilla", "spiciness":"mild"},
3. {"name":"jalapeno", "spiceiness":"hot hot hot!"},
4. {"name":"habanero", "spiceness":"LAVA HOT!!"}];
5.
6. $scope.spice = "habanero";
7. }

1. describe('myController function', function() {


2.
3. describe('myController', function() {
4. var scope;
5.
6. beforeEach(inject(function($rootScope, $controller) {
7. scope = $rootScope.$new();
8. var ctrl = $controller(myController, {$scope: scope});
9. }));
10.
11. it('should create "spices" model with 3 spices', function() {
12. expect(scope.spices.length).toBe(3);
13. });
14.
15. it('should set the default value of spice', function() {
16. expect(scope.spice).toBe('habanero');
17. });
18. });
19. });

,
, , DOM.

1. describe('state', function() {
2. var mainScope, childScope, babyScope;
3.
4. beforeEach(inject(function($rootScope, $controller) {
5. mainScope = $rootScope.$new();
6. var mainCtrl = $controller(MainCtrl, {$scope: mainScope});
7. childScope = mainScope.$new();
8. var childCtrl = $controller(ChildCtrl, {$scope: childScope});
9. babyScope = childCtrl.$new();
10. var babyCtrl = $controller(BabyCtrl, {$scope: babyScope});
11. }));
12.
13. it('should have over and selected', function() {
14. expect(mainScope.timeOfDay).toBe('morning');
15. expect(mainScope.name).toBe('Nikki');
16. expect(childScope.timeOfDay).toBe('morning');
17. expect(childScope.name).toBe('Mattie');
18. expect(babyScope.timeOfDay).toBe('evening');
19. expect(babyScope.name).toBe('Gingerbreak Baby');
20. });
21. });


Angular DOM,
, , .

Angular MVC, .
.
Angular , ngController ngView,
: {{someControllerFunction()}}. ,
.

E2e
,
, .
, Angular ,
, Angular.

JavaScript, , ,
.
( ), ,
. , (,
), ,
(, URL-).
, failed .
beforeEach afterEach , ( ) , ,
.

, it.

1. describe('Buzz Client', function() {


2. it('should filter results', function() {
3. input('user').enter('jacksparrow');
4. element(':button').click();
5. expect(repeater('ul li').count()).toEqual(10);
6. input('filterText').enter('Bees');
7. expect(repeater('ul li').count()).toEqual(1);
8. });
9. });
Buzz Client,
user. 'user'
, 10 li. 'Bees' 'filterText'
, .
API .

API

pause()
resume() ( resume
Runner UI).

sleep(seconds)
seconds .

browser().navigateTo(url)
url .

browser().navigateTo(url, fn)
URL fn .
url . URL
( ).

browser().reload()
.

browser().window().href()
window.location.href , .

browser().window().path()
window.location.pathname , .

browser().window().search()
window.location.search , .

browser().window().hash()
window.location.hash , .

browser().location().url()
$location.url() , .

browser().location().path()
$location.path() , .

browser().location().search()
$location.search() , .

browser().location().hash()
$location.hash() , .
expect(future).{matcher}
, future matcher. API
future, value
. angular.scenario.matcher,
. :
expect(browser().location().href()).toEqual('http://www.google.com')

expect(future).not().{matcher}
, future matcher.

using(selector, label)
DSL .

binding(name)
name.

input(name).enter(value)
value name.

input(name).check()
/ name.

input(name).select(value)
value name.

input(name).val()
name.

repeater(selector, label).count()
, jQuery
selector. label .

repeater(selector, label).row(index)
index
jQuery selector. label .

repeater(selector, label).column(binding)
binding
jQuery selector. label .

select(name).option(value)
, value select name.

select(name).option(value1, value2...)
, values select name.
element(selector, label).count()
, jQuery selector.
label .

element(selector, label).click()
, jQuery selector. label
.

element(selector, label).query(fn)
fn(selectedElements, done), selectedElements
jQuery selector done , ,
fn. label .

element(selector, label).{method}()
method , jQuery
selector, method jQuery
: val, text, html, height, innerHeight, outerHeight, width, innerWidth,outerWidt
h, position, scrollLeft, scrollTop, offset. label .

element(selector, label).{method}(value)
method value ,
jQuery selector, method
jQuery: val, text, html, height, innerHeight, outerHeight, width,innerWidth, outerWidth,
position, scrollLeft, scrollTop, offset. label .

element(selector, label).{method}(key)
method
key , jQuery selector, method
jQuery : attr, prop, css. label .

element(selector, label).{method}(key, value)


method key
value , jQuery selector,
method jQuery : attr, prop, css. label
.
JavaScript , ,
. , ,
JavaScript .
Angular, Angular .
.

Angular
Angular ,
, .
DOM, HTML, CSS, angular. Angular
angular
DOM DOM.

Angular :
Directive DOM
DOM .
Markup ,
Angular.
Filter .
Form controls .

: ,
JavaScript .

Angular HTML
Angular :

1. <html ng-app>
2. <! Body ngController-->
3. <body ng-controller="MyController">
4. <input ng-model="foo" value="bar">
5. <! Button ng-click,
6. 'buttonText'
7. "{{ }}" markup -->
8. <button ng-click="changeFoo()">{{buttonText}}</button>
9. <script src="angular.js">
10. </body>
11. </html>

, HTML, CSS, angular


HTML ( index.html). ,
,
HTML . ""
$route
ngView. angular ,
.

CSS Angular
Angular CSS . .

CSS classes used by angular


ng-invalid, ng-valid

: angular ,
. ( input ).
ng-pristine, ng-dirty

: angular input ng-pristine


.
, ng-dirty.


- Angular
. Angular
, .
. ,
.




:

,
. ,



.

,
,

. ,
.

Angular
Angular , . ,
(
HTML

)
,

.


,
.


,

.

.

,
. , ..
DOM/ .


Angular .

, ,
. ,
, :
name | uppercase
name uppercase .

Angular
:
, .
, .
.

.
.

Index.html

1. <!doctype html>
2. <html ng-app="MyReverseModule">
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="Ctrl">
9. <input ng-model="greeting" type="greeting"><br>
10. No filter: {{greeting}}<br>
11. Reverse: {{greeting|reverse}}<br>
12. Reverse + uppercase: {{greeting|reverse:true}}<br>
13. </div>
14. </body>
15. </html>

Script.js

1. angular.module('MyReverseModule', []).
2. filter('reverse', function() {
3. return function(input, uppercase) {
4. var out = "";
5. for (var i = 0; i < input.length; i++) {
6. out = input.charAt(i) + out;
7. }
8. // conditional based on optional argument
9. if (uppercase) {
10. out = out.toUpperCase();
11. }
12. return out;
13. }
14. });
15.
16. function Ctrl($scope) {
17. $scope.greeting = 'hello';
18. }

End to end test


1. it('should reverse greeting', function() {
2. expect(binding('greeting|reverse')).toEqual('olleh');
3. input('greeting').enter('ABC');
4. expect(binding('greeting|reverse')).toEqual('CBA');
5. });

Angular
api/ng.$rootScope.Scope,
:
{{ expression | filter }}

,
. , .

, :
{{ expression | filter1 | filter2 }}

: , ,
123 :
123 | number:2

:
myArray | orderBy:'timestamp':true

,
:

: {{1234.5678}} => 1234.5678


: {{1234.5678|number}} => 1,234.57. "," -
.
: {{1234.5678|number:5}} => 1,234.56780.
, . , "number"
, .

Angular
, - ,
. apps
, (DI).

, Angular ,
. Angular
,
(DI).
$location

?
$location URL ( window.location)
URL . URL
$location $location .

$location:

URL ,
URL.
URL.
URL

( ).
.
URL (protocol, host, port, path, search, hash).

$location window.location
window.location $location service

API "raw"
, jQuery


,
angular $watch, ...

(
HTML5 API )

- window.location.path - $location.path()
/ "/docroot/actual/path" "/actual/path"

$location?
URL
URL .
?
.
URL, API
$window.location.href.

API
$location , ,
. ,
.
$location,
jQuery, URL
.

$location
$location, $locationProvider
:

html5Mode(mode): {boolean}
true HTML5
false
default: false

hashPrefix(prefix): {string}
URLs ( ,
HTML5)
default: ""

1. $locationProvider.html5Mode(true).hashPrefix('!');


$location URL (absUrl, protocol, host,
port) / url, path, search, hash:

1. //
2. $location.path();
3.
4. //
5. $location.path('/newValue')

$location . ,
, :

1. $location.path('/newValue').search({key: value});

replace $location
,
, .
,
( ).
URL :

1. $location.path('/someNewPath');
2. $location.replace();
3. // or you can chain these as: $location.path('/someNewPath').replace();

window.location. ,
$location
$location window.location
$digest . $location ,
replace(),
. , $location
replace() ,
replace().


. $location
RFC 3986. :

, $location,
path(), search(), hash(), .
( )
path(), search(),hash().
absUrl() url
.
url(), , ,
/path?search=a&b=c#hash. .

HTML5
$location , URL
: ( ) HTML5
History API. API
$location URL APIs
URL .
HTML5

{ html5Mode: true }

URL URLs URLs ,


URLs .

<a href="">

( )
, $location URLs

1. it('should show example', inject(


2. function($locationProvider) {
3. $locationProvider.html5Mode(false);
4. $locationProvider.hashPrefix = '!';
5. },
6. function($location) {
7. // open http://host.com/base/index.html#!/a
8. $location.absUrl() == 'http://host.com/base/index.html#!/a'
9. $location.path() == '/a'
10.
11. $location.path('/foo')
12. $location.absUrl() == 'http://host.com/base/index.html#!/foo'
13.
14. $location.search() == {}
15. $location.search({a: 'b', c: true});
16. $location.absUrl() == 'http://host.com/base/index.html#!/foo?a=b&c'
17.
18. $location.path('/new').search('x=y');
19. $location.absUrl() == 'http://host.com/base/index.html#!/new?x=y'
20. }
21. ));


AJAX ,
- head :

1. <meta name="fragment" content="!" />

, _escaped_fragment_ param
HTML.

AJAX .
HTML5
HTML5, $location, ,
URL HTML5 API, URL
, . HTML5 API
, $location .
, API ;
$location .

URL -> URL


URL -> URL

1. it('should show example', inject(


2. function($locationProvider) {
3. $locationProvider.html5Mode(true);
4. $locationProvider.hashPrefix = '!';
5. },
6. function($location) {
7. // HTML5 :
8. // http://host.com/#!/a -> http://host.com/a
9. // ( http://host.com/#!/a)
10. $location.path() == '/a'
11.
12. $location.path('/foo');
13. $location.absUrl() == 'http://host.com/foo'
14.
15. $location.search() == {}
16. $location.search({a: 'b', c: true});
17. $location.absUrl() == 'http://host.com/foo?a=b&c'
18.
19. $location.path('/new').search('x=y');
20. $location.url() == 'new?x=y'
21. $location.absUrl() == 'http://host.com/new?x=y'
22.
23. // html5 :
24. // http://host.com/new?x=y -> http://host.com/#!/new?x=y
25. // ( http://host.com/new?x=y history)
26. $location.path() == '/new'
27. $location.search() == {x: 'y'}
28.
29. $location.path('/foo/bar');
30. $location.path() == '/foo/bar'
31. $location.url() == '/foo/bar?x=y'
32. $location.absUrl() == 'http://host.com/#!/foo/bar?x=y'
33. }
34. ));


HTML5 history API, $location
. history API , $location
URL. history API;
$location .

Html
HTML5 history API,
, , URL ,
: <a href="/some?foo=bar">link</a>

URL /index.html#!/some?foo=bar
URL /some?foo=bar

;
.

target
: <a href="/ext/link?a=b" target="_self">link</a>
,
: <a href="http://angularjs.org/">link</a>
'/'
: <a href="/not-my-base/link">link</a>


URL ,
( index.html)


, , .. url
head (<base href="/my-base">)
url ( /)
.

Angular History API


, ..
.


HTML5,
:

URL URL.
URL URL .

$location, Html5,
, .
$location . input
.

, url /
/hashbang url, URL =
.
<base href="/base/index.html" />

Index.html

1. <!doctype html>
2. <html ng-app>
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-non-bindable class="html5-hashbang-example">
9. <div id="html5-mode" ng-controller="Html5Cntl">
10. <h4>Browser with History API</h4>
11. <div ng-address-bar browser="html5"></div><br><br>
12. $location.protocol() = {{$location.protocol()}}<br>
13. $location.host() = {{$location.host()}}<br>
14. $location.port() = {{$location.port()}}<br>
15. $location.path() = {{$location.path()}}<br>
16. $location.search() = {{$location.search()}}<br>
17. $location.hash() = {{$location.hash()}}<br>
18. <a href="http://www.host.com/base/first?a=b">/base/first?a=b</a> |
19. <a href="http://www.host.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a>
|
20. <a href="/other-base/another?search">external</a>
21. </div>
22.
23. <div id="hashbang-mode" ng-controller="HashbangCntl">
24. <h4>Browser without History API</h4>
25. <div ng-address-bar browser="hashbang"></div><br><br>
26. $location.protocol() = {{$location.protocol()}}<br>
27. $location.host() = {{$location.host()}}<br>
28. $location.port() = {{$location.port()}}<br>
29. $location.path() = {{$location.path()}}<br>
30. $location.search() = {{$location.search()}}<br>
31. $location.hash() = {{$location.hash()}}<br>
32. <a href="http://www.host.com/base/first?a=b">/base/first?a=b</a> |
33. <a href="http://www.host.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a>
|
34. <a href="/other-base/another?search">external</a>
35. </div>
36. </div>
37. </body>
38. </html>

Script.js

1. function FakeBrowser(initUrl, baseHref) {


2. this.onUrlChange = function(fn) {
3. this.urlChange = fn;
4. };
5.
6. this.url = function() {
7. return initUrl;
8. };
9.
10. this.defer = function(fn, delay) {
11. setTimeout(function() { fn(); }, delay || 0);
12. };
13.
14. this.baseHref = function() {
15. return baseHref;
16. };
17.
18. this.notifyWhenOutstandingRequests = angular.noop;
19. }
20.
21. var browsers = {
22. html5: new FakeBrowser('http://www.host.com/base/path?a=b#h', '/base/index.html'
),
23. hashbang: new FakeBrowser('http://www.host.com/base/index.html#!/path?a=b#h', '/
base/index.html')
24. };
25.
26. function Html5Cntl($scope, $location) {
27. $scope.$location = $location;
28. }
29.
30. function HashbangCntl($scope, $location) {
31. $scope.$location = $location;
32. }
33.
34. function initEnv(name) {
35. var root = angular.element(document.getElementById(name + '-mode'));
36. angular.bootstrap(root, [function($compileProvider, $locationProvider, $provide)
{
37. $locationProvider.html5Mode(true).hashPrefix('!');
38.
39. $provide.value('$browser', browsers[name]);
40. $provide.value('$document', root);
41. $provide.value('$sniffer', {history: name == 'html5'});
42.
43. $compileProvider.directive('ngAddressBar', function() {
44. return function(scope, elm, attrs) {
45. var browser = browsers[attrs.browser],
46. input = angular.element('<input type="text">').val(browser.url()),
47. delay;
48.
49. input.bind('keypress keyup keydown', function() {
50. if (!delay) {
51. delay = setTimeout(fireUrlChange, 250);
52. }
53. });
54.
55. browser.url = function(url) {
56. return input.val(url);
57. };
58.
59. elm.append('Address: ').append(input);
60.
61. function fireUrlChange() {
62. delay = null;
63. browser.urlChange(input.val());
64. }
65. };
66. });
67. }]);
68. root.bind('click', function(e) {
69. e.stopPropagation();
70. });
71. }
72.
73. initEnv('html5');
74. initEnv('hashbang');


$location URL; .
URL ,
API, $window.location.href.
$location
$location Angular. URL
, $location $apply
$watchers / $observers. $location $digest
; $location
$watchers / $observers. $location Angular ( ,
DOM ) $apply
.

$location.path() ! /
(/); $location.path()
.
, ! $location.path();
.

$location
$location ,
. scope.$apply().

1. describe('serviceUnderTest', function() {
2. beforeEach(module(function($provide) {
3. $provide.factory('serviceUnderTest', function($location){
4. // whatever it does...
5. });
6. });
7.
8. it('should...', inject(function($location, $rootScope, serviceUnderTest) {
9. $location.path('/new/path');
10. $rootScope.$apply();
11.
12. // test whatever the service should do...
13.
14. }));
15. });

AngularJS
Angular, $location hashPath hashSearch
. , $location
path search
URL (
http://server.com/#!/path?search=a), .

$location.href = value $location.path(path).search(search)


$location.hash = value

$location.update(value)
$location.updateHash(value)

$location.hashPath = path $location.path(path)

$location.hashSearch = search $location.search(search)

API

$location.href = value $window.location.href = value


$location.update(value)

$location[protocol | host | port | path | search] $window.location[protocol | host | port | path |


search]

$location.hashPath $location.path()

$location.hashSearch $location.search()

$location.href $location.absUrl()
$location.protocol $location.protocol()
$location.host $location.host()
$location.port $location.port()
$location.hash $location.path() + $location.search()

$location.path $window.location.path
$location.search $window.location.search

$location
Angular
(. ). $location (
ngModel ),
( locationPath) , $location
. :

1. <!-- html -->


2. <input type="text" ng-model="locationPath" />

1. // js - controller
2. $scope.$watch('locationPath', function(path) {
3. $location.path(path);
4. });
5.
6. $scope.$watch('$location.path()', function(path) {
7. scope.locationPath = path;
8. });


Angular ,
. ,
Module#factory api
, $provide.

Angular (DI),
, ,
. / /
.


, , .
Module api $provide
. :

angular.Module api:

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


2. myModule.factory('serviceId', function() {
3. var shinyNewServiceInstance;
4. // , shinyNewServiceInstance
5. return shinyNewServiceInstance;
6. });

$provide:

1. angular.module('myModule', [], function($provide) {


2. $provide.factory('serviceId', function() {
3. var shinyNewServiceInstance;
4. // , shinyNewServiceInstance
5. return shinyNewServiceInstance;
6. });
7. });

, , ,
, .

, .
. (DI)
Angular. , $inject ,
.
. $window (
) .
, window alert.

1. angular.module('myModule', [], function($provide) {


2. $provide.factory('notify', ['$window', function(win) {
3. var msgs = [];
4. return function(msg) {
5. msgs.push(msg);
6. if (msgs.length == 3) {
7. win.alert(msgs.join("\n"));
8. msgs = [];
9. }
10. };
11. }]);
12. });

Angular
Angular . ,
. ,
Angular ,
.


, Angular .
. Angular
, ,
, , .

JavaScript , DI
( ).
, $inject , ,
. ID ,
. .
, ,
.

1. function myController($loc, $log) {


2. this.firstMethod = function() {
3. // $location
4. $loc.setHash();
5. };
6. this.secondMethod = function() {
7. // $log
8. $log.info('...');
9. };
10. }
11. // ?
12. myController.$inject = ['$location', '$log'];

index.html

1. <!doctype html>
2. <html ng-app="MyServiceModule">
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="myController">
9. <p>Let's try this simple notify service, injected into the controller...</p>
10. <input ng-init="message='test'" ng-model="message" >
11. <button ng-click="callNotify(message);">NOTIFY</button>
12. </div>
13. </body>
14. </html>

script.js

1. angular.
2. module('MyServiceModule', []).
3. factory('notify', ['$window', function(win) {
4. var msgs = [];
5. return function(msg) {
6. msgs.push(msg);
7. if (msgs.length == 3) {
8. win.alert(msgs.join("\n"));
9. msgs = [];
10. }
11. };
12. }]);
13.
14. function myController(scope, notifyService) {
15. scope.callNotify = function(msg) {
16. notifyService(msg);
17. };
18. }
19.
20. myController.$inject = ['$scope','notify'];

ent to end test


1. it('should test service', function() {
2. expect(element(':input[ng\\:model="message"]').val()).toEqual('test');
3. });


Angular DI .

$window, $scope notify:

Index.html

1. <!doctype html>
2. <html ng-app="MyServiceModuleDI">
3. <head>
4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
5. <script src="script.js"></script>
6. </head>
7. <body>
8. <div ng-controller="myController">
9. <p>Let's try the notify service, that is implicitly injected into the contro
ller...</p>
10. <input ng-init="message='test'" ng-model="message">
11. <button ng-click="callNotify(message);">NOTIFY</button>
12. </div>
13. </body>
14. </html>

Script.js

1. angular.
2. module('MyServiceModuleDI', []).
3. factory('notify', function($window) {
4. var msgs = [];
5. return function(msg) {
6. msgs.push(msg);
7. if (msgs.length == 3) {
8. $window.alert(msgs.join("\n"));
9. msgs = [];
10. }
11. };
12. });
13.
14. function myController($scope, notify) {
15. $scope.callNotify = function(msg) {
16. notify(msg);
17. };
18. }
, , ,
$inject.


Angular ,
.

, .
, $inject .
, $inject .

1. function myModuleCfgFn($provide) {
2. $provide.factory('myService', ['dep1', 'dep2', function(dep1, dep2) {}]);
3. }

$inject:

1. function myModuleCfgFn($provide) {
2. var myServiceFactory = function(dep1, dep2) {};
3. myServiceFactory.$inject = ['dep1', 'dep2'];
4. $provide.factory('myService', myServiceFactory);
5. }

DI ( ):

1. function myModuleCfgFn($provide) {
2. $provide.factory('myService', function(dep1, dep2) {});
3. }

, ,
Angular:

1. /**
2. * batchLog service allows for messages to be queued in memory and flushed
3. * to the console.log every 50 seconds.
4. *
5. * @param {*} message Message to be logged.
6. */
7. function batchLogModule($provide){
8. $provide.factory('batchLog', ['$timeout', '$log', function($timeout, $log) {
9. var messageQueue = [];
10.
11. function log() {
12. if (messageQueue.length) {
13. $log('batchLog messages: ', messageQueue);
14. messageQueue = [];
15. }
16. $timeout(log, 50000);
17. }
18.
19. // start periodic checking
20. log();
21.
22. return function(message) {
23. messageQueue.push(message);
24. }
25. }]);
26.
27. /**
28. * routeTemplateMonitor monitors each $route change and logs the current
29. * template via the batchLog service.
30. */
31. $provide.factory('routeTemplateMonitor',
32. ['$route', 'batchLog', '$rootScope',
33. function($route, batchLog, $rootScope) {
34. $rootScope.$on('$routeChangeSuccess', function() {
35. batchLog($route.current ? $route.current.template : null);
36. });
37. }]);
38. }
39.
40. // get the main service to kick of the application
41. angular.injector([batchLogModule]).get('routeTemplateMonitor');

batchLog $timeout $log,


.
routeTemplateMonitor $route
batchLogservice.

. ,
.
, (
).

Angular
'notify' 'Dependencies' Angular.
Jasmine spy (mock) alert.

1. var mock, notify;


2.
3. beforeEach(function() {
4. mock = {alert: jasmine.createSpy()};
5.
6. module(function($provide) {
7. $provide.value('$window', mock);
8. });
9.
10. inject(function($injector) {
11. notify = $injector.get('notify');
12. });
13. });
14.
15. it('should not alert first two notifications', function() {
16. notify('one');
17. notify('two');
18.
19. expect(mock.alert).not.toHaveBeenCalled();
20. });
21.
22. it('should alert all after third notification', function() {
23. notify('one');
24. notify('two');
25. notify('three');
26.
27. expect(mock.alert).toHaveBeenCalledWith("one\ntwo\nthree");
28. });
29.
30. it('should clear messages after alert', function() {
31. notify('one');
32. notify('two');
33. notify('third');
34. notify('more');
35. notify('two');
36. notify('third');
37.
38. expect(mock.alert.callCount).toEqual(2);
39. expect(mock.alert.mostRecentCall.args).toEqual(["more\ntwo\nthird"]);
40. });

Angular
Angular , -,
$http service
XMLHttpRequest.

Angular,
( ). Angular
. Angular ,
, .

Angular "constructor" (
). JavaScript , Angular
.
$inject. :

myController.$inject = ['$location'];

Angular - .
Angular, ,
$ ( , $http).
.

JavaScript , ,
. ,
JavaScript . Angular ,
Angular.
.


, .
, " ?"
" ?"

, ,
. , ,
, DOM XHR .

,
. , ,
. XHR, , DOM.

Angular ,
XHR ( )
,
DOM. ,
, , ,
.


Angular ,
. , ,
.


: 1.
new. 2. , . 3.
( , .
2). 4. .

, . :

new
, new ,
, . , ,
, XHR.

1. function MyClass() {
2. this.doWork = function() {
3. var xhr = new XHR();
4. xhr.open(method, url, true);
5. xhr.onreadystatechange = function() {...}
6. xhr.send();
7. }
8. }
,
MockXHR .
new XHR() XHR,
. , , ,
.

, :

1. var oldXHR = XHR;


2. XHR = function MockXHR() {};
3. var myClass = new MyClass();
4. myClass.doWork();
5. // assert that MockXHR got called with the right arguments
6. XHR = oldXHR; // if you forget this bad things will happen

:
, .

1. function MyClass() {
2. this.doWork = function() {
3. global.xhr({
4. method:'...',
5. url:'...',
6. complete:function(response){ ... }
7. })
8. }
9. }

, ,
new, global.xhr
, . , ,
.
, , :

, :

1. var oldXHR = global.xhr;


2. global.xhr = function mockXHR() {};
3. var myClass = new MyClass();
4. myClass.doWork();
5. // assert that mockXHR got called with the right arguments
6. global.xhr = oldXHR; // if you forget this bad things will happen

:
, ,
.

1. function MyClass() {
2. var serviceRegistry = ????;
3. this.doWork = function() {
4. var xhr = serviceRegistry.get('xhr');
5. xhr({
6. method:'...',
7. url:'...',
8. complete:function(response){ ... }
9. })
10. }

, serviceRegistry? : * new ,
* ,
( , ).
, :

1. var oldServiceLocator = global.serviceLocator;


2. global.serviceLocator.set('xhr', function mockXHR() {});
3. var myClass = new MyClass();
4. myClass.doWork();
5. // assert that mockXHR got called with the right arguments
6. global.serviceLocator = oldServiceLocator; // if you forget this bad things will h
appen

:
, .

1. function MyClass(xhr) {
2. this.doWork = function() {
3. xhr({
4. method:'...',
5. url:'...',
6. complete:function(response){ ... }
7. })
8. }

, ,
xhr , . ,
, ,
.

, :

1. function xhrMock(args) {...}


2. var myClass = new MyClass(xhrMock);
3. myClass.doWork();
4. // assert that xhrMock got called with the right arguments

, .
Angular
, .

, .. ,
. DOM,
, :

1. function PasswordCtrl() {
2. // get references to DOM elements
3. var msg = $('.ex1 span');
4. var input = $('.ex1 input');
5. var strength;
6.
7. this.grade = function() {
8. msg.removeClass(strength);
9. var pwd = input.val();
10. password.text(pwd);
11. if (pwd.length > 8) {
12. strength = 'strong';
13. } else if (pwd.length > 3) {
14. strength = 'medium';
15. } else {
16. strength = 'weak';
17. }
18. msg
19. .addClass(strength)
20. .text(strength);
21. }
22. }

,
DOM, , .
:

1. var input = $('<input type="text"/>');


2. var span = $('<span>');
3. $('body').html('<div class="ex1">')
4. .find('div')
5. .append(input)
6. .append(span);
7. var pc = new PasswordCtrl();
8. input.val('abc');
9. pc.grade();
10. expect(span.text()).toEqual('weak');
11. $('body').html('');

angular DOM,
, ::

1. function PasswordCtrl($scope) {
2. $scope.password = '';
3. $scope.grade = function() {
4. var size = $scope.password.length;
5. if (size > 8) {
6. $scope.strength = 'strong';
7. } else if (size > 3) {
8. $scope.strength = 'medium';
9. } else {
10. $scope.strength = 'weak';
11. }
12. };
13. }

1. var pc = new PasswordCtrl();


2. pc.password('abc');
3. pc.grade();
4. expect(pc.strength).toEqual('weak');

, , .
, , ,
.

,
. ,
, .

1. myModule.filter('length', function() {
2. return function(text){
3. return (''+(text||'')).length;
4. }
5. });
6.
7. var length = $filter('length');
8. expect(length(null)).toEqual(0);
9. expect(length('abc')).toEqual(3);

angular
HTML, , .
, , ,
.

HTML
angular .

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


.

1. app.directive('aGreatEye', function () {
2. return {
3. restrict: 'E',
4. replace: true,
5. template: '<h1>lidless, wreathed in flame</h1>'
6. };
7. });

<a-great-eye></a-great-eye>.
<h1>lidless, wreathed in flame</h1>. jasmine
.

1. describe('Unit testing great quotes', function() {


2. var $compile;
3. var $rootScope;
4.
5. // myApp,
6. beforeEach(module('myApp'));
7.
8. // $rootScope $compile
9. // describe
10. beforeEach(inject(function(_$compile_, _$rootScope_){
11. // (_)
12. $compile = _$compile_;
13. $rootScope = _$rootScope_;
14. }));
15.
16. it('Replaces the element with the appropriate content', function() {
17. // HTML
18. var element = $compile("<a-great-eye></a-great-eye>")($rootScope);
19. // ,
20. expect(element.html()).toContain("lidless, wreathed in flame");
21. });
22. });

$compile $rootScope jasmine. $compile


aGreatEye.
"lidless, wreathed in flame".

Mocks
oue

Global State Isolation


oue

Preferred way of Testing


uo

JavaScriptTestDriver
ou
Jasmine
ou

Sample project
uoe