angularjs-入门
更新日期:
Hello World
1 2 3 4 5 6 7 8 9 10 11 | <!DOCTYPE html> <html> <body ng-app> <input type="text" ng-model="name" placeholder="Enter your name"> <h1>Hello <span ng-bind="name"></span></h1> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.js"> </script> </body> </html> |
AngularJS Convenience Function
angular.forEach
Iterator over objects and arrays, to help you write code in a functional manner.angular.fromJson
andangular.toJson
Convenience methods to convert from a string to a JSON object and back from a JSON object to a string.angular.copy
Performs a deep copy of a given object and returns the newly created copy.angular.equals
Determines if two objects, regular expressions, arrays, or values are equal. Does deep comparison in the case of objects or arrays.angular.isObject
,angular.isArray
, andangular.isFunction
Convenience methods to quickly check if a given variable is an object, array, or function.angular.isString
,angular.isNumber
, andangular.isDate
Convenience methods to check if a given variable is a string, number, or date object.
AngularJS Modules
Modules are AngularJS’s way of packaging relevant code under a single name.
The module can also depend on other modules as dependencies, which are defined when the module is instantiated.
Module to load as the main entry point for the application by passing the module name
to the ng-app
directive.
1 2 3 4 5 | // define a module angular.module('notesApp', ['notesApp.ui', 'thirdCompany.fusioncharts']); // get a module angular.module('notesApp', []); |
This example defines a module (note the empty array as the second argument), and then
lets AngularJS bootstrap the module through the ng-app
directive.
1 2 3 4 5 6 7 8 9 10 | <!-- File: chapter2/module-example.html --> <html ng-app="notesApp"> <head><title>Hello AngularJS</title></head> <body> Hello 2nd time AngularJS <script type="text/javascript"> angular.module('notesApp', []); </script> </body> </html> |
Controller
An AngularJS controller is almost always directly linked to a view or HTML. It acts as the gateway between our model, which is the data that drives our application, and the view, which is what the user sees and interacts with.
- Fetching the right data from the server for the current UI
- Deciding which parts of that data to show to the user
- Presentation logic, such as how to display elements, which parts of the UI to show, how to style them, etc.
- User interactions, such as what happens when a user clicks something or how a text input should be validated
The array holds all the dependencies for the controller as string variables, and the last argument in the array is the actual controller function. In this case, because we have no dependencies, the function is the only argument in the array.
We also introduce a new directive, ng-controller
. This is used to tell AngularJS to go
instantiate an instance of the controller with the given name, and attach it to the DOM
element.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <body ng-controller="MainCtrl as ctrl"> AngularJS. <button ng-click="ctrl.changeMessage()"> Change Message </button> <div ng-repeat="note in ctrl.notes"> <span class="label"> </span> <span class="status" ng-bind="note.done"></span> </div> <script type="text/javascript"> angular.module('notesApp', []) .controller('MainCtrl', [function() { var self = this; self.message= 'Hello '; self.changeMessage = function() { self.message = 'Goodbye'; }; self.notes = [ {id: 1, label: 'First Note', done: false}, {id: 2, label: 'Second Note', done: false}, {id: 3, label: 'Done Note', done: true}, {id: 4, label: 'Last Note', done: false} ]; }]); </script> </body> |
Use class="ng-cloak"
to hide \{\{\}\}
in angularjs when bootstrap.
1 2 3 | [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],.ng-cloak, .x-ng-cloak { display: none !important; } |
Each time it hits an ng-controller
or an ng-repeat
directive, it creates what we
call a scope in AngularJS. A scope is the context for that element. The scope dictates
what each DOM element has access to in terms of functions, variables, and the like.
Also note that while the ng-repeat
instances each get their own scope, they still have
access to the parent scope.
More Directives
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <style> .done { background-color: green;} .pending {background-color: red;} </style> <body ng-controller="MainCtrl as ctrl"> <div ng-repeat="note in ctrl.notes" ng-class="ctrl.getNoteClass(note.done)"> <span class="label"> </span> <span class="assignee" ng-show="note.assignee" ng-bind="note.assignee"> </span> </div> </body> <script type="text/javascript"> angular.module('notesApp', []).controller('MainCtrl', [ function() { var self = this; self.notes = [ {label: 'First Note', done: false, assignee: 'Shyam'}, {label: 'Second Note', done: false}, {label: 'Done Note', done: true}, {label: 'Last Note', done: false, assignee: 'Brad'} ]; self.getNoteClass = function(status) { return { done: status, pending: !status }; }; }]); </script> |
AngularJS treats true, nonempty strings, nonzero numbers, and nonnull JS objects as truthy.
The ng-class
directive can take
strings or objects as values. If it is a string,
it simply applies the CSS classes directly.
If it is an object, AngularJS takes a look at each key of the object,
and depending on whether the value for that key is true or false,
applies or removes the CSS class.
ng-repeat
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <div ng-repeat="(author, note) in ctrl.notes"> <span class="label"> </span> <span class="author" ng-bind="author"></span> </div> <script type="text/javascript"> angular.module('notesApp', []) .controller('MainCtrl', [function() { var self = this; self.notes = { shyam: { id: 1, label: 'First Note', done: false }, Misko: { id: 3, label: 'Finished Third Note', done: true }, brad: { id: 2, label: 'Second Note', done: false } }; }]); </script> |
Helper variables in ng-repeat
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <div ng-repeat="note in ctrl.notes"> <div>First Element: {\{$first}}</div> <div>Middle Element: {\{$middle}}</div> <div>Last Element: {\{$last}}</div> <div>Index of Element: {\{$index}}</div> <div>At Even Position: {\{$even}}</div> <div>At Odd Position: {\{$odd}}</div> <span class="label"> {\{note.label}}</span> <span class="status" ng-bind="note.done"></span> </div> <script type="text/javascript"> var self = this; self.notes = [ {id: 1, label: 'First Note', done: false}, {id: 2, label: 'Second Note', done: false}, {id: 3, label: 'Done Note', done: true}, {id: 4, label: 'Last Note', done: false} ]; </script> |
To optimize performance, ng-repeat
caches or reuses DOM elements if
the objects are exactly the same, according to the hash of the object
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <!-- DOM Elements are reused every time someone clicks --> <button ng-click="ctrl.changeNotes()">Change Notes</button> <div ng-repeat="note in ctrl.notes2 track by note.id"> \{\{note.$$hashKey}} <span class="label"> </span> <span class="author" ng-bind="note.done"></span> </div> <!-- ng-repeat Across Multiple HTML Elements --> <table> <tr ng-repeat-start="note in ctrl.notes"> <td></td> </tr> <tr ng-repeat-end> <td>Done: </td> </tr> </table> |
Karma
1 2 3 4 5 | sudo npm install karma-cli -g npm install karma npm install karma-jasmine karma-chrome-launcher karma init |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | // File: chapter3/karma.conf.js // Karma configuration module.exports = function(config) { config.set({ // base path that will be used to resolve files and exclude basePath: '', // testing framework to use (jasmine/mocha/qunit/...) frameworks: ['jasmine'], // list of files / patterns to load in the browser files: [ 'angular.min.js', 'angular-mocks.js', 'controller.js', 'simpleSpec.js', 'controllerSpec.js' ], // list of files / patterns to exclude exclude: [], // web server port port: 8080, // level of logging // possible values: LOG_DISABLE || LOG_ERROR || // LOG_WARN || LOG_INFO || LOG_DEBUG logLevel: config.LOG_INFO, // enable / disable watching file and executing tests // whenever any file changes autoWatch: true, // Start these browsers, currently available: // - Chrome // - ChromeCanary // - Firefox // - Opera // - Safari (only Mac) // - PhantomJS // - IE (only Windows) browsers: ['Chrome'], // Continuous Integration mode // if true, it captures browsers, runs tests, and exits singleRun: false }); }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | describe('My Function', function() { var t; // Similar to setup beforeEach(function() { t = true; }); afterEach(function() { t = null; }); it('should perform action 1', function() { expect(t).toBeTruthy(); }); it('should perform action 2', function() { var expectedValue = true; expect(t).toEqual(expectedValue); }); }); |
toEqual
, does a deep equality check between the two objects, like array.toBe
, expects both items passed to the expect and the matcher to be the exact same object reference.toBeTruthy
andtoBeFalsy
toBeDefined
,toBeUndefined
andtoBeNull
toContain
, array passed to the expect contains the element passed to the matchertoMatch
, Used for regular expression checks when the first argument to the expect is a string that needs to match a specific regular expression pattern.
Unit Test for Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | angular.module('notesApp', []) .controller('ListCtrl', [function() { var self = this; self.items = [ {id: 1, label: 'First', done: true}, {id: 2, label: 'Second', done: false} ]; self.getDoneClass = function(item) { return { finished: item.done, unfinished: !item.done }; }; }]); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | // File: chapter3/controllerSpec.js describe('Controller: ListCtrl', function() { // Instantiate a new version of my module before each test beforeEach(module('notesApp')); var ctrl; // Before each unit test, instantiate a new instance // of the controller beforeEach(inject(function($controller) { ctrl = $controller('ListCtrl'); })); it('should have items available on load', function() { expect(ctrl.items).toEqual([ {id: 1, label: 'First', done: true}, {id: 2, label: 'Second', done: false} ]); }); it('should have highlight items based on state', function() { var item = {id: 1, label: 'First', done: true}; var actualClass = ctrl.getDoneClass(item); expect(actualClass.finished).toBeTruthy(); expect(actualClass.unfinished).toBeFalsy(); item.done = false; actualClass = ctrl.getDoneClass(item); expect(actualClass.finished).toBeFalsy(); expect(actualClass.unfinished).toBeTruthy(); }); }); // karma start my.conf.js // The examples and tests in this book were run using version 0.12.16 // of Karma, and version 1.2.19 of AngularJS (both the angular.js and // angular-mocks.js files) |