mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-04-25 00:54:46 +00:00
Update latest docs content from gdocs
This commit is contained in:
parent
e670a812fa
commit
e0ee3a0726
8 changed files with 119 additions and 131 deletions
|
|
@ -9,80 +9,80 @@ detection, and preventing invalid form submission.
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script>
|
<script>
|
||||||
UserForm.$inject = ['$invalidWidgets'];
|
UserForm.$inject = ['$invalidWidgets'];
|
||||||
function UserForm($invalidWidgets){
|
function UserForm($invalidWidgets){
|
||||||
this.$invalidWidgets = $invalidWidgets;
|
this.$invalidWidgets = $invalidWidgets;
|
||||||
this.state = /^\w\w$/;
|
this.state = /^\w\w$/;
|
||||||
this.zip = /^\d\d\d\d\d$/;
|
this.zip = /^\d\d\d\d\d$/;
|
||||||
this.master = {
|
this.master = {
|
||||||
name: 'John Smith',
|
name: 'John Smith',
|
||||||
address:{
|
address:{
|
||||||
line1: '123 Main St.',
|
line1: '123 Main St.',
|
||||||
city:'Anytown',
|
city:'Anytown',
|
||||||
state:'AA',
|
state:'AA',
|
||||||
zip:'12345'
|
zip:'12345'
|
||||||
},
|
},
|
||||||
contacts:[
|
contacts:[
|
||||||
{type:'phone', value:'1(234) 555-1212'}
|
{type:'phone', value:'1(234) 555-1212'}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
this.cancel();
|
this.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UserForm.prototype = {
|
UserForm.prototype = {
|
||||||
cancel: function(){
|
cancel: function(){
|
||||||
this.form = angular.copy(this.master);
|
this.form = angular.copy(this.master);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
save: function(){
|
save: function(){
|
||||||
this.master = this.form;
|
this.master = this.form;
|
||||||
this.cancel();
|
this.cancel();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<div ng:controller="UserForm">
|
<div ng:controller="UserForm">
|
||||||
|
|
||||||
|
|
||||||
<label>Name:</label><br/>
|
<label>Name:</label><br/>
|
||||||
<input type="text" name="form.name" ng:required/> <br/><br/>
|
<input type="text" name="form.name" ng:required/> <br/><br/>
|
||||||
|
|
||||||
|
|
||||||
<label>Address:</label><br/>
|
<label>Address:</label><br/>
|
||||||
<input type="text" name="form.address.line1" size="33" ng:required/> <br/>
|
<input type="text" name="form.address.line1" size="33" ng:required/> <br/>
|
||||||
<input type="text" name="form.address.city" size="12" ng:required/>,
|
<input type="text" name="form.address.city" size="12" ng:required/>,
|
||||||
<input type="text" name="form.address.state" size="2" ng:required ng:validate="regexp:state"/>
|
<input type="text" name="form.address.state" size="2" ng:required ng:validate="regexp:state"/>
|
||||||
<input type="text" name="form.address.zip" size="5" ng:required
|
<input type="text" name="form.address.zip" size="5" ng:required
|
||||||
ng:validate="regexp:zip"/><br/><br/>
|
ng:validate="regexp:zip"/><br/><br/>
|
||||||
|
|
||||||
|
|
||||||
<label>Phone:</label>
|
<label>Contacts:</label>
|
||||||
[ <a href="" ng:click="form.contacts.$add()">add</a> ]
|
[ <a href="" ng:click="form.contacts.$add()">add</a> ]
|
||||||
<div ng:repeat="contact in form.contacts">
|
<div ng:repeat="contact in form.contacts">
|
||||||
<select name="contact.type">
|
<select name="contact.type">
|
||||||
<option>email</option>
|
<option>email</option>
|
||||||
<option>phone</option>
|
<option>phone</option>
|
||||||
<option>pager</option>
|
<option>pager</option>
|
||||||
<option>IM</option>
|
<option>IM</option>
|
||||||
</select>
|
</select>
|
||||||
<input type="text" name="contact.value" ng:required/>
|
<input type="text" name="contact.value" ng:required/>
|
||||||
[ <a href="" ng:click="form.contacts.$remove(contact)">X</a> ]
|
[ <a href="" ng:click="form.contacts.$remove(contact)">X</a> ]
|
||||||
</div>
|
</div>
|
||||||
<button ng:click="cancel()" disabled="{{master.$equals(form)}}">Cancel</button>
|
<button ng:click="cancel()" disabled="{{master.$equals(form)}}">Cancel</button>
|
||||||
<button ng:click="save()" disabled="{{$invalidWidgets.visible() ||
|
<button ng:click="save()" disabled="{{$invalidWidgets.visible() ||
|
||||||
master.$equals(form)}}">Save</button>
|
master.$equals(form)}}">Save</button>
|
||||||
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
Debug View:
|
Debug View:
|
||||||
<pre>form={{form}}
|
<pre>form={{form}}
|
||||||
master={{master}}</pre>
|
master={{master}}</pre>
|
||||||
</div>
|
</div>
|
||||||
</doc:source>
|
</doc:source>
|
||||||
<doc:scenario>
|
<doc:scenario>
|
||||||
it('should enable save button', function(){
|
it('should enable save button', function(){
|
||||||
expect(element(':button:contains(Save)').attr('disabled')).toBeTruthy();
|
expect(element(':button:contains(Save)').attr('disabled')).toBeTruthy();
|
||||||
input('form.name').enter('');
|
input('form.name').enter('');
|
||||||
|
|
@ -100,7 +100,7 @@ master.$equals(form)}}">Save</button>
|
||||||
expect(element(':button:contains(Cancel)').attr('disabled')).toBeTruthy();
|
expect(element(':button:contains(Cancel)').attr('disabled')).toBeTruthy();
|
||||||
expect(element(':input[name=form.name]').val()).toEqual('John Smith');
|
expect(element(':input[name=form.name]').val()).toEqual('John Smith');
|
||||||
});
|
});
|
||||||
</doc:scenario>
|
</doc:scenario>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -109,15 +109,10 @@ master.$equals(form)}}">Save</button>
|
||||||
#Things to notice
|
#Things to notice
|
||||||
|
|
||||||
|
|
||||||
* Cancel & save buttons are only enabled if the form is dirty -- there is something to cancel or
|
* Cancel & save buttons are only enabled if the form is dirty — there is something to cancel or
|
||||||
save.
|
save.
|
||||||
* Save button is only enabled if there are no validation errors on the form.
|
* Save button is only enabled if there are no validation errors on the form.
|
||||||
* Cancel reverts the form changes back to original state.
|
* Cancel reverts the form changes back to original state.
|
||||||
* Save updates the internal model of the form.
|
* Save updates the internal model of the form.
|
||||||
* Debug view shows the two models. One presented to the user form and the other being the pristine
|
* Debug view shows the two models. One presented to the user form and the other being the pristine
|
||||||
copy master.
|
copy master.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ to retrieve Buzz activity and comments.
|
||||||
<img src="{{item.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
|
<img src="{{item.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
|
||||||
<a href="{{item.actor.profileUrl}}">{{item.actor.name}}</a>
|
<a href="{{item.actor.profileUrl}}">{{item.actor.name}}</a>
|
||||||
<a href="" ng:click="expandReplies(item)" style="float: right;">
|
<a href="" ng:click="expandReplies(item)" style="float: right;">
|
||||||
Expand replies: {{item.links.replies.count}}
|
Expand replies: {{item.links.replies[0].count}}
|
||||||
</a>
|
</a>
|
||||||
</h1>
|
</h1>
|
||||||
{{item.object.content | html}}
|
{{item.object.content | html}}
|
||||||
|
|
|
||||||
|
|
@ -78,27 +78,19 @@ ng:validate="regexp:zip"/><br/><br/>
|
||||||
|
|
||||||
it('should validate zip', function(){
|
it('should validate zip', function(){
|
||||||
expect(using('.example').element(':input[name=user.address.zip]').attr('className'))
|
expect(using('.example').element(':input[name=user.address.zip]').attr('className'))
|
||||||
.not().toMatch(/ng-validation-error/)
|
.not().toMatch(/ng-validation-error/);
|
||||||
|
|
||||||
|
|
||||||
using('.example').input('user.address.zip').enter('abc');
|
using('.example').input('user.address.zip').enter('abc');
|
||||||
|
|
||||||
|
|
||||||
expect(using('.example').element(':input[name=user.address.zip]').attr('className'))
|
expect(using('.example').element(':input[name=user.address.zip]').attr('className'))
|
||||||
.toMatch(/ng-validation-error/)
|
.toMatch(/ng-validation-error/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should validate state', function(){
|
it('should validate state', function(){
|
||||||
expect(using('.example').element(':input[name=user.address.state]').attr('className'))
|
expect(using('.example').element(':input[name=user.address.state]').attr('className'))
|
||||||
.not().toMatch(/ng-validation-error/)
|
.not().toMatch(/ng-validation-error/);
|
||||||
|
|
||||||
|
|
||||||
using('.example').input('user.address.state').enter('XXX');
|
using('.example').input('user.address.state').enter('XXX');
|
||||||
|
|
||||||
|
|
||||||
expect(using('.example').element(':input[name=user.address.state]').attr('className'))
|
expect(using('.example').element(':input[name=user.address.state]').attr('className'))
|
||||||
.toMatch(/ng-validation-error/)
|
.toMatch(/ng-validation-error/);
|
||||||
});
|
});
|
||||||
</doc:scenario>
|
</doc:scenario>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ no connection between the controller and the view.
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script>
|
<script>
|
||||||
function TicTacToeCntl($location){
|
function TicTacToeCntl($location){
|
||||||
this.$location = $location;
|
this.$location = $location;
|
||||||
|
|
@ -34,8 +34,8 @@ no connection between the controller and the view.
|
||||||
}
|
}
|
||||||
TicTacToeCntl.prototype = {
|
TicTacToeCntl.prototype = {
|
||||||
dropPiece: function(row, col) {
|
dropPiece: function(row, col) {
|
||||||
if (!this.winner && !this.board) {
|
if (!this.winner && !this.board[row][col]) {
|
||||||
this.board = this.nextMove;
|
this.board[row][col] = this.nextMove;
|
||||||
this.nextMove = this.nextMove == 'X' ? 'O' : 'X';
|
this.nextMove = this.nextMove == 'X' ? 'O' : 'X';
|
||||||
this.setUrl();
|
this.setUrl();
|
||||||
}
|
}
|
||||||
|
|
@ -51,15 +51,15 @@ no connection between the controller and the view.
|
||||||
this.setUrl();
|
this.setUrl();
|
||||||
},
|
},
|
||||||
grade: function(){
|
grade: function(){
|
||||||
var b = this.board;
|
var b = this.board;
|
||||||
this.winner =
|
this.winner =
|
||||||
row(0) || row(1) || row(2) ||
|
row(0) || row(1) || row(2) ||
|
||||||
col(0) || col(1) || col(2) ||
|
col(0) || col(1) || col(2) ||
|
||||||
diagonal(-1) || diagonal(1);
|
diagonal(-1) || diagonal(1);
|
||||||
function row(r) { return same(b, b, b);}
|
function row(row) { return same(b[row][0], b[row][1], b[row][2]);}
|
||||||
function col(c) { return same(b, b, b);}
|
function col(col) { return same(b[0][col], b[1][col], b[2][col]);}
|
||||||
function diagonal(i) { return same(b[1-i], b, b[1+i]);}
|
function diagonal(i) { return same(b[0][1-i], b[1][1], b[2][1+i]);}
|
||||||
function same(a, b, c) { return (a==b && b==c) ? a : '';};
|
function same(a, b, c) { return (a==b && b==c) ? a : '';};
|
||||||
},
|
},
|
||||||
setUrl: function(){
|
setUrl: function(){
|
||||||
var rows = [];
|
var rows = [];
|
||||||
|
|
@ -68,12 +68,12 @@ no connection between the controller and the view.
|
||||||
});
|
});
|
||||||
this.$location.hashSearch.board = rows.join(';') + '/' + this.nextMove;
|
this.$location.hashSearch.board = rows.join(';') + '/' + this.nextMove;
|
||||||
},
|
},
|
||||||
readUrl: function(scope, value) {
|
readUrl: function(value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
value = value.split('/');
|
value = value.split('/');
|
||||||
this.nextMove = value;
|
this.nextMove = value[1];
|
||||||
angular.forEach(value.split(';'), function(row, i){
|
angular.forEach(value[0].split(';'), function(row, col){
|
||||||
this.board = row.split(',');
|
this.board[col] = row.split(',');
|
||||||
}, this);
|
}, this);
|
||||||
this.grade();
|
this.grade();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -82,36 +82,38 @@ no connection between the controller and the view.
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<h3>Tic-Tac-Toe</h3>
|
<h3>Tic-Tac-Toe</h3>
|
||||||
<div ng:controller="TicTacToeCntl">
|
<div ng:controller="TicTacToeCntl">
|
||||||
Next Player: {{nextMove}}
|
Next Player: {{nextMove}}
|
||||||
<div class="winner" ng:show="winner">Player {{winner}} has won!</div>
|
<div class="winner" ng:show="winner">Player {{winner}} has won!</div>
|
||||||
<table class="board">
|
<table class="board">
|
||||||
<tr ng:repeat="row in board" style="height:15px;">
|
<tr ng:repeat="row in board" style="height:15px;">
|
||||||
<td ng:repeat="cell in row" ng:style="cellStyle"
|
<td ng:repeat="cell in row" ng:style="cellStyle"
|
||||||
ng:click="dropPiece($parent.$index, $index)">{{cell}}</td>
|
ng:click="dropPiece($parent.$index, $index)">{{cell}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<button ng:click="reset()">reset board</button>
|
<button ng:click="reset()">reset board</button>
|
||||||
</div>
|
</div>
|
||||||
</doc:source>
|
</doc:source>
|
||||||
<doc:scenario>
|
<doc:scenario>
|
||||||
it('should play a game', function(){
|
it('should play a game', function(){
|
||||||
piece(1, 1);
|
piece(1, 1);
|
||||||
expect(binding('nextMove')).toEqual('O');
|
expect(binding('nextMove')).toEqual('O');
|
||||||
piece(3, 1);
|
piece(3, 1);
|
||||||
expect(binding('nextMove')).toEqual('X');
|
expect(binding('nextMove')).toEqual('X');
|
||||||
piece(1, 2);
|
piece(1, 2);
|
||||||
piece(3, 2);
|
piece(3, 2);
|
||||||
piece(1, 3);
|
piece(1, 3);
|
||||||
expect(element('.winner').text()).toEqual('Player X has won!');
|
expect(element('.winner').text()).toEqual('Player X has won!');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function piece(row, col) {
|
function piece(row, col) {
|
||||||
element('.board tr:nth-child('+row+') td:nth-child('+col+')').click();
|
element('.board tr:nth-child('+row+') td:nth-child('+col+')').click();
|
||||||
}
|
}
|
||||||
</doc:scenario>
|
</doc:scenario>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -123,13 +125,12 @@ no connection between the controller and the view.
|
||||||
* The controller is defined in JavaScript and has no reference to the rendering logic.
|
* The controller is defined in JavaScript and has no reference to the rendering logic.
|
||||||
* The controller is instantiated by <angular/> and injected into the view.
|
* The controller is instantiated by <angular/> and injected into the view.
|
||||||
* The controller can be instantiated in isolation (without a view) and the code will still execute.
|
* The controller can be instantiated in isolation (without a view) and the code will still execute.
|
||||||
This makes it very testable.
|
This makes it very testable.
|
||||||
* The HTML view is a projection of the model. In the above example, the model is stored in the
|
* The HTML view is a projection of the model. In the above example, the model is stored in the
|
||||||
board variable.
|
board variable.
|
||||||
* All of the controller's properties (such as board and nextMove) are available to the view.
|
* All of the controller's properties (such as board and nextMove) are available to the view.
|
||||||
* Changing the model changes the view.
|
* Changing the model changes the view.
|
||||||
* The view can call any controller function.
|
* The view can call any controller function.
|
||||||
* In this example, the `setUrl()` and `readUrl()` functions copy the game state to/from the URL's
|
* In this example, the `setUrl()` and `readUrl()` functions copy the game state to/from the URL's
|
||||||
hash so the browser's back button will undo game steps. See deep-linking. This example calls
|
hash so the browser's back button will undo game steps. See deep-linking. This example calls {@link
|
||||||
{@link api/angular.scope.$watch $watch()} to set up a listener that invokes `readUrl()` when
|
api/angular.scope.$watch $watch()} to set up a listener that invokes `readUrl()` when needed.
|
||||||
needed.
|
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ The unit test now verifies that the default ordering property is set.
|
||||||
|
|
||||||
|
|
||||||
We used Jasmine's API to extract the controller construction into a `beforeEach` block, which is
|
We used Jasmine's API to extract the controller construction into a `beforeEach` block, which is
|
||||||
shared by all tests in the nearest `describe` block.
|
shared by all tests in the parent `describe` block.
|
||||||
|
|
||||||
|
|
||||||
To run the unit tests, once again execute the `./scripts/test.sh` script and you should see the
|
To run the unit tests, once again execute the `./scripts/test.sh` script and you should see the
|
||||||
|
|
@ -205,7 +205,7 @@ __`test/e2e/scenarios.js`:__
|
||||||
function() {
|
function() {
|
||||||
|
|
||||||
|
|
||||||
// let's narrow the dataset to make the test assertions shorter
|
// narrow the dataset to make the test assertions shorter
|
||||||
input('query').enter('tablet');
|
input('query').enter('tablet');
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ our model into the view.
|
||||||
|
|
||||||
__`app/partials/phone-details.html`:__
|
__`app/partials/phone-details.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
<img ng:src="{{phone.images}}" class="phone"/>
|
<img ng:src="{{phone.images[0]}}" class="phone"/>
|
||||||
|
|
||||||
|
|
||||||
<h1>{{phone.name}}</h1>
|
<h1>{{phone.name}}</h1>
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ function PhoneDetailCtrl($xhr) {
|
||||||
|
|
||||||
$xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
|
$xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
|
||||||
self.phone = response;
|
self.phone = response;
|
||||||
self.mainImageUrl = response.images;
|
self.mainImageUrl = response.images[0];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ function PhoneDetailCtrl(Phone_) {
|
||||||
|
|
||||||
|
|
||||||
self.phone = Phone_.get({phoneId: self.params.phoneId}, function(phone) {
|
self.phone = Phone_.get({phoneId: self.params.phoneId}, function(phone) {
|
||||||
self.mainImageUrl = phone.images;
|
self.mainImageUrl = phone.images[0];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue