Compare commits

...

16 Commits

Author SHA1 Message Date
Jeff Cross ef6fed3ef8 revert: fix(form): ignore properties in $error prototype chain
This reverts commit adf91fe6ee.
2015-01-26 14:20:52 -08:00
Caitlin Potter 473dee5786 docs(CHANGELOG.md): add changelog notes for v1.3.11 and v1.4.0-beta.2
Closes #10876
2015-01-26 16:12:24 -05:00
Caitlin Potter 779e3f6b5f fix(htmlAnchorDirective): remove "element !== target element" check
It's not really needed due to the way click events are dispatched and propagated

Closes #10866
2015-01-25 23:42:25 -05:00
Vinti Maheshwari 71bca00651 chore(gruntFile): ensure build is run before test:modules
Closes #10188
2015-01-25 02:33:29 +00:00
Peter Bacon Darwin 9a9fce0abc test($location): ensure that link rewriting is actually being tested
If the link URL is not within the given base URL then the link would not
be rewritten anyway.

See https://github.com/angular/angular.js/pull/9906/files#r19813651
2015-01-25 00:40:57 +00:00
Peter Bacon Darwin 939ca37cfe fix($location): don't rewrite when link is shift-clicked
Closes #9904
Closes #9906
2015-01-25 00:36:44 +00:00
Peter Bacon Darwin 4ae8a2a4b6 docs(input): update example to use ngModel best practices
Update the rest of the directives to use object properties for models.

Closes #10851
2015-01-24 22:42:50 +00:00
Mark Hoffmeyer 113d3954b9 docs(input[checkbox]): update example to use ngModel best practices
It's not required for the example to function, but it prevents scope weirdness/unexpected
behavior when using directives (especially with ngTransclude!). I think it's a good pattern
to encourage and might prevent a bug down the road for for people who just scan for the
monospace font. See
[Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
for mgModel best practices.

Closes #10851
2015-01-24 22:41:55 +00:00
samilamti 7cb5983750 docs(guide/Introduction): define CRUD and add punctuation
Added description of what CRUD means.
Improved readability: Ensured that colons were followed by a capital letter
and added some sprinkled commas.

Closes #10804
2015-01-24 10:57:53 +00:00
Caitlin Potter 2b149ca6d4 fix(openPlunkr): enable cmd+click for us mac users :> 2015-01-23 16:49:00 -05:00
Mike Haggerty e77866c18c feat(openPlunkr): enable ctrl+click
This change allows users to ctrl+click on the "Edit in Plunker"
button which will set the posted form's target attribute to
"_blank" instead of "_self" which is the default.

Closes #10641
Closes #10826
2015-01-23 16:49:00 -05:00
Rouven Weßling 0dc6418d20 test($rootScope) test the correct setting of the constructor in Internet Explorer 11
Closes #10759
2015-01-23 21:33:15 +00:00
Caitlin Potter 837a077578 fix(htmlAnchorDirective): don't add event listener if replaced, ignore event if target is different element
Previously, when an `a` tag element used a directive with a replacing template, and did not include an `href` or `name` attribute
before linkage, the anchor directive would always prevent default.

Now, the anchor directive will not register an event listener at all if the original directive is replaced with a non-anchor, and
will ignore events which do not target the linked element.

Closes #4262
Closes #10849
2015-01-23 15:40:23 -05:00
Caitlin Potter adf91fe6ee fix(form): ignore properties in $error prototype chain
Closes #10469
Closes #10727
2015-01-23 14:37:48 +00:00
Boshen Chen dea1c0d34c docs(ngInit): fix code block not being displayed in the note section
Closes #10791
2015-01-20 23:23:43 +01:00
Pawel Kozlowski f533acc9aa docs(CHANGELOG): add changes for 1.3.10 and 1.4.0-beta.1 2015-01-20 20:48:20 +01:00
12 changed files with 361 additions and 94 deletions
+138
View File
@@ -1,3 +1,141 @@
<a name="1.4.0-beta.2"></a>
# 1.4.0-beta.2 holographic-rooster (2015-01-26)
## Bug Fixes
- **$location:** don't rewrite when link is shift-clicked
([8b33de6f](https://github.com/angular/angular.js/commit/8b33de6fd0ec0eb785fed697f062763b5c1d8d23),
[#9904](https://github.com/angular/angular.js/issues/9904), [#9906](https://github.com/angular/angular.js/issues/9906))
- **$templateRequest:** cache downloaded templates as strings
([b3a9bd3a](https://github.com/angular/angular.js/commit/b3a9bd3ae043e3042ea7ccfe08e3b36a84feb35e),
[#10630](https://github.com/angular/angular.js/issues/10630), [#10646](https://github.com/angular/angular.js/issues/10646))
- **filterFilter:** throw error if input is not an array
([cea8e751](https://github.com/angular/angular.js/commit/cea8e75144e6910b806b63a6ec2a6d118316fddd),
[#9992](https://github.com/angular/angular.js/issues/9992), [#10352](https://github.com/angular/angular.js/issues/10352))
- **form:** ignore properties in $error prototype chain
([31a5b835](https://github.com/angular/angular.js/commit/31a5b8353ae5f1a5cb283322829880995e877833),
[#10469](https://github.com/angular/angular.js/issues/10469), [#10727](https://github.com/angular/angular.js/issues/10727))
- **htmlAnchorDirective:**
- remove "element !== target element" check
([2958cd30](https://github.com/angular/angular.js/commit/2958cd308b5ebaf223a3e5df3fb5bf0f23408447),
[#10866](https://github.com/angular/angular.js/issues/10866))
- don't add event listener if replaced, ignore event if target is different element
([b146af11](https://github.com/angular/angular.js/commit/b146af11271de8fa4c51c6db87df104269f41a33),
[#4262](https://github.com/angular/angular.js/issues/4262), [#10849](https://github.com/angular/angular.js/issues/10849))
- **ngPluralize:** fix wrong text content when count is null/undefined
([3228d3b4](https://github.com/angular/angular.js/commit/3228d3b4991af681e57de5ab079c1e1c11cf35cb),
[#10836](https://github.com/angular/angular.js/issues/10836), [#10841](https://github.com/angular/angular.js/issues/10841))
## Breaking Changes
- **filterFilter:** due to [cea8e751](https://github.com/angular/angular.js/commit/cea8e75144e6910b806b63a6ec2a6d118316fddd),
Previously, the filter was not applied if used with a non array.
Now, it throws an error. This can be worked around by converting an object to an array, using
a filter such as https://github.com/petebacondarwin/angular-toArrayFilter
Closes #9992
Closes #10352
<a name="1.3.11"></a>
# 1.3.11 spiffy-manatee (2015-01-26)
## Bug Fixes
- **$location:** don't rewrite when link is shift-clicked
([939ca37c](https://github.com/angular/angular.js/commit/939ca37cfe5f6fc35b09b6705caabd1fcc3cf9d3),
[#9904](https://github.com/angular/angular.js/issues/9904), [#9906](https://github.com/angular/angular.js/issues/9906))
- **form:** ignore properties in $error prototype chain
([adf91fe6](https://github.com/angular/angular.js/commit/adf91fe6ee77a84e8159c9a95e36f65276fe67bd),
[#10469](https://github.com/angular/angular.js/issues/10469), [#10727](https://github.com/angular/angular.js/issues/10727))
- **htmlAnchorDirective:**
- remove "element !== target element" check
([779e3f6b](https://github.com/angular/angular.js/commit/779e3f6b5f8d2550e758cb0c5f64187ba8e00e29),
[#10866](https://github.com/angular/angular.js/issues/10866))
- don't add event listener if replaced, ignore event if target is different element
([837a0775](https://github.com/angular/angular.js/commit/837a077578081bbd07863bef85241537d19fa652),
[#4262](https://github.com/angular/angular.js/issues/4262), [#10849](https://github.com/angular/angular.js/issues/10849))
<a name="1.4.0-beta.1"></a>
# 1.4.0-beta.1 trepidatious-salamander (2015-01-20)
## Bug Fixes
- **$animate:** ensure no transitions are applied when an empty inline style object is provided
([0db5b21b](https://github.com/angular/angular.js/commit/0db5b21b1d09431535e0c0bf8ac63d4b5b24d349),
[#10613](https://github.com/angular/angular.js/issues/10613), [#10770](https://github.com/angular/angular.js/issues/10770))
- **$compile:** support class directives on SVG elements
([23c8a90d](https://github.com/angular/angular.js/commit/23c8a90d22f7c7b41b5a756b89498ffac828980a),
[#10736](https://github.com/angular/angular.js/issues/10736), [#10756](https://github.com/angular/angular.js/issues/10756))
- **form:** clean up success state of controls when they are removed
([2408f2de](https://github.com/angular/angular.js/commit/2408f2ded5ead6e678c241e38ef474c1fadff92b),
[#10509](https://github.com/angular/angular.js/issues/10509))
- **ngController:** allow bound constructor fns as controllers
([d17fbc38](https://github.com/angular/angular.js/commit/d17fbc3862e0a2e646db1222f184dbe663da4a1f),
[#10784](https://github.com/angular/angular.js/issues/10784), [#10790](https://github.com/angular/angular.js/issues/10790))
- **ngRepeat:** do not sort object keys alphabetically
([c260e738](https://github.com/angular/angular.js/commit/c260e7386391877625eda086480de73e8a0ba921),
[#6210](https://github.com/angular/angular.js/issues/6210), [#10538](https://github.com/angular/angular.js/issues/10538))
## Features
- **$http:** provide a config object as an argument to header functions
([d435464c](https://github.com/angular/angular.js/commit/d435464c51d3912f56cfc830d86bfc64a1578327),
[#7235](https://github.com/angular/angular.js/issues/7235), [#10622](https://github.com/angular/angular.js/issues/10622))
## Breaking Changes
- **ngRepeat:** due to [c260e738](https://github.com/angular/angular.js/commit/c260e7386391877625eda086480de73e8a0ba921),
Previously, the order of items when using ngRepeat to iterate
over object properties was guaranteed to be consistent by sorting the
keys into alphabetic order.
Now, the order of the items is browser dependent based on the order returned
from iterating over the object using the `for key in obj` syntax.
It seems that browsers generally follow the strategy of providing
keys in the order in which they were defined, although there are exceptions
when keys are deleted and reinstated. See
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_issues
The best approach is to convert Objects into Arrays by a filter such as
https://github.com/petebacondarwin/angular-toArrayFilter
or some other mechanism, and then sort them manually in the order you need.
Closes #6210
Closes #10538
<a name="1.3.10"></a>
# 1.3.10 heliotropic-sundial (2015-01-20)
## Bug Fixes
- **$animate:** ensure no transitions are applied when an empty inline style object is provided
([9b8df52a](https://github.com/angular/angular.js/commit/9b8df52aa960b9b6288fc150d55ea2e35f56555e),
[#10613](https://github.com/angular/angular.js/issues/10613), [#10770](https://github.com/angular/angular.js/issues/10770))
- **$compile:** support class directives on SVG elements
([7a9e3360](https://github.com/angular/angular.js/commit/7a9e3360284d58197a1fe34de57f5e0f6d1f4a76),
[#10736](https://github.com/angular/angular.js/issues/10736), [#10756](https://github.com/angular/angular.js/issues/10756))
- **form:** clean up success state of controls when they are removed
([cdc7280d](https://github.com/angular/angular.js/commit/cdc7280dd3d5a2ded784c06dd55fe36c2053fb6f),
[#10509](https://github.com/angular/angular.js/issues/10509))
- **ngController:** allow bound constructor fns as controllers
([d015c8a8](https://github.com/angular/angular.js/commit/d015c8a80b28754633c846fc50d11c9437519486),
[#10784](https://github.com/angular/angular.js/issues/10784), [#10790](https://github.com/angular/angular.js/issues/10790))
<a name="1.4.0-beta.0"></a>
# 1.4.0-beta.0 photonic-umbrakinesis (2015-01-13)
+2 -2
View File
@@ -316,9 +316,9 @@ module.exports = function(grunt) {
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'jscs', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:protractor']);
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']);
grunt.registerTask('test:jquery', 'Run the jQuery unit tests with Karma', ['tests:jquery']);
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['tests:modules']);
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['build', 'tests:modules']);
grunt.registerTask('test:docs', 'Run the doc-page tests with Karma', ['package', 'tests:docs']);
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', ['tests:jqlite', 'tests:jquery', 'tests:modules']);
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', ['test:jqlite', 'test:jquery', 'test:modules']);
grunt.registerTask('test:protractor', 'Run the end to end tests with Protractor and keep a test server running in the background', ['webdriver', 'connect:testserver', 'protractor:normal']);
grunt.registerTask('test:travis-protractor', 'Run the end to end tests with Protractor for Travis CI builds', ['connect:testserver', 'protractor:travis']);
grunt.registerTask('test:ci-protractor', 'Run the end to end tests with Protractor for Jenkins CI builds', ['webdriver', 'connect:testserver', 'protractor:jenkins']);
+11 -7
View File
@@ -1,13 +1,16 @@
angular.module('examples', [])
.factory('formPostData', ['$document', function($document) {
return function(url, fields) {
return function(url, newWindow, fields) {
/**
* Form previously posted to target="_blank", but pop-up blockers were causing this to not work.
* If a user chose to bypass pop-up blocker one time and click the link, they would arrive at
* a new default plnkr, not a plnkr with the desired template.
* If the form posts to target="_blank", pop-up blockers can cause it not to work.
* If a user choses to bypass pop-up blocker one time and click the link, they will arrive at
* a new default plnkr, not a plnkr with the desired template. Given this undesired behavior,
* some may still want to open the plnk in a new window by opting-in via ctrl+click. The
* newWindow param allows for this possibility.
*/
var form = angular.element('<form style="display: none;" method="post" action="' + url + '"></form>');
var target = newWindow ? '_blank' : '_self';
var form = angular.element('<form style="display: none;" method="post" action="' + url + '" target="' + target + '"></form>');
angular.forEach(fields, function(value, name) {
var input = angular.element('<input type="hidden" name="' + name + '">');
input.attr('value', value);
@@ -21,9 +24,10 @@ angular.module('examples', [])
.factory('openPlunkr', ['formPostData', '$http', '$q', function(formPostData, $http, $q) {
return function(exampleFolder) {
return function(exampleFolder, clickEvent) {
var exampleName = 'AngularJS Example';
var newWindow = clickEvent.ctrlKey || clickEvent.metaKey;
// Load the manifest for the example
$http.get(exampleFolder + '/manifest.json')
@@ -71,7 +75,7 @@ angular.module('examples', [])
postData.private = true;
postData.description = exampleName;
formPostData('http://plnkr.co/edit/?p=preview', postData);
formPostData('http://plnkr.co/edit/?p=preview', newWindow, postData);
});
};
}]);
@@ -2,7 +2,7 @@
is HTML and wrap each line in a <p> - thus breaking the HTML #}
<div>
<a ng-click="openPlunkr('{$ doc.path $}')" class="btn pull-right">
<a ng-click="openPlunkr('{$ doc.path $}', $event)" class="btn pull-right">
<i class="glyphicon glyphicon-edit">&nbsp;</i>
Edit in Plunker</a>
+12 -12
View File
@@ -12,7 +12,7 @@ succinctly. Angular's data binding and dependency injection eliminate much of th
would otherwise have to write. And it all happens within the browser, making it
an ideal partner with any server technology.
Angular is what HTML would have been had it been designed for applications. HTML is a great
Angular is what HTML would have been, had it been designed for applications. HTML is a great
declarative language for static documents. It does not contain much in the way of creating
applications, and as a result building web applications is an exercise in *what do I have to do
to trick the browser into doing what I want?*
@@ -28,10 +28,10 @@ The impedance mismatch between dynamic applications and static documents is ofte
Angular takes another approach. It attempts to minimize the impedance mismatch between document
centric HTML and what an application needs by creating new HTML constructs. Angular teaches the
browser new syntax through a construct we call directives. Examples include:
browser new syntax through a construct we call *directives*. Examples include:
* Data binding, as in `{{}}`.
* DOM control structures for repeating/hiding DOM fragments.
* DOM control structures for repeating, showing and hiding DOM fragments.
* Support for forms and form validation.
* Attaching new behavior to DOM elements, such as DOM event handling.
* Grouping of HTML into reusable components.
@@ -42,20 +42,20 @@ browser new syntax through a construct we call directives. Examples include:
Angular is not a single piece in the overall puzzle of building the client-side of a web
application. It handles all of the DOM and AJAX glue code you once wrote by hand and puts it in a
well-defined structure. This makes Angular opinionated about how a CRUD application should be
built. But while it is opinionated, it also tries to make sure that its opinion is just a
starting point you can easily change. Angular comes with the following out-of-the-box:
well-defined structure. This makes Angular opinionated about how a CRUD (Create, Read, Update, Delete)
application should be built. But while it is opinionated, it also tries to make sure that its opinion
is just a starting point you can easily change. Angular comes with the following out-of-the-box:
* Everything you need to build a CRUD app in a cohesive set: data-binding, basic templating
directives, form validation, routing, deep-linking, reusable components, dependency injection.
* Testability story: unit-testing, end-to-end testing, mocks, test harnesses.
* Everything you need to build a CRUD app in a cohesive set: Data-binding, basic templating
directives, form validation, routing, deep-linking, reusable components and dependency injection.
* Testability story: Unit-testing, end-to-end testing, mocks and test harnesses.
* Seed application with directory layout and test scripts as a starting point.
## Angular Sweet Spot
## Angular's sweet spot
Angular simplifies application development by presenting a higher level of abstraction to the
developer. Like any abstraction, it comes at a cost of flexibility. In other words not every app
developer. Like any abstraction, it comes at a cost of flexibility. In other words, not every app
is a good fit for Angular. Angular was built with the CRUD application in mind. Luckily CRUD
applications represent the majority of web applications. To understand what Angular is
good at, though, it helps to understand when an app is not a good fit for Angular.
@@ -78,7 +78,7 @@ expressing business logic.
* It is an excellent idea to decouple the client side of an app from the server side. This
allows development work to progress in parallel, and allows for reuse of both sides.
* It is very helpful indeed if the framework guides developers through the entire journey of
building an app: from designing the UI, through writing the business logic, to testing.
building an app: From designing the UI, through writing the business logic, to testing.
* It is always good to make common tasks trivial and difficult tasks possible.
+3
View File
@@ -18,6 +18,9 @@ var htmlAnchorDirective = valueFn({
compile: function(element, attr) {
if (!attr.href && !attr.xlinkHref && !attr.name) {
return function(scope, element) {
// If the linked element is not an anchor tag anymore, do nothing
if (element[0].nodeName.toLowerCase() !== 'a') return;
// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
'xlink:href' : 'href';
+87 -65
View File
@@ -61,19 +61,21 @@ var inputType = {
<script>
angular.module('textInputExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.text = 'guest';
$scope.word = /^\s*\w*\s*$/;
$scope.example = {
text: 'guest',
word: /^\s*\w*\s*$/
};
}]);
</script>
<form name="myForm" ng-controller="ExampleController">
Single word: <input type="text" name="input" ng-model="text"
ng-pattern="word" required ng-trim="false">
Single word: <input type="text" name="input" ng-model="example.text"
ng-pattern="example.word" required ng-trim="false">
<span class="error" ng-show="myForm.input.$error.required">
Required!</span>
<span class="error" ng-show="myForm.input.$error.pattern">
Single word only!</span>
<tt>text = {{text}}</tt><br/>
<tt>text = {{example.text}}</tt><br/>
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
@@ -81,9 +83,9 @@ var inputType = {
</form>
</file>
<file name="protractor.js" type="protractor">
var text = element(by.binding('text'));
var text = element(by.binding('example.text'));
var valid = element(by.binding('myForm.input.$valid'));
var input = element(by.model('text'));
var input = element(by.model('example.text'));
it('should initialize to model', function() {
expect(text.getText()).toContain('guest');
@@ -145,18 +147,20 @@ var inputType = {
<script>
angular.module('dateInputExample', [])
.controller('DateController', ['$scope', function($scope) {
$scope.value = new Date(2013, 9, 22);
$scope.example = {
value: new Date(2013, 9, 22)
};
}]);
</script>
<form name="myForm" ng-controller="DateController as dateCtrl">
Pick a date in 2013:
<input type="date" id="exampleInput" name="input" ng-model="value"
<input type="date" id="exampleInput" name="input" ng-model="example.value"
placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
<span class="error" ng-show="myForm.input.$error.required">
Required!</span>
<span class="error" ng-show="myForm.input.$error.date">
Not a valid date!</span>
<tt>value = {{value | date: "yyyy-MM-dd"}}</tt><br/>
<tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
@@ -164,9 +168,9 @@ var inputType = {
</form>
</file>
<file name="protractor.js" type="protractor">
var value = element(by.binding('value | date: "yyyy-MM-dd"'));
var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
var valid = element(by.binding('myForm.input.$valid'));
var input = element(by.model('value'));
var input = element(by.model('example.value'));
// currently protractor/webdriver does not support
// sending keys to all known HTML5 input controls
@@ -236,18 +240,20 @@ var inputType = {
<script>
angular.module('dateExample', [])
.controller('DateController', ['$scope', function($scope) {
$scope.value = new Date(2010, 11, 28, 14, 57);
$scope.example = {
value: new Date(2010, 11, 28, 14, 57)
};
}]);
</script>
<form name="myForm" ng-controller="DateController as dateCtrl">
Pick a date between in 2013:
<input type="datetime-local" id="exampleInput" name="input" ng-model="value"
<input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
<span class="error" ng-show="myForm.input.$error.required">
Required!</span>
<span class="error" ng-show="myForm.input.$error.datetimelocal">
Not a valid date!</span>
<tt>value = {{value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
<tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
@@ -255,9 +261,9 @@ var inputType = {
</form>
</file>
<file name="protractor.js" type="protractor">
var value = element(by.binding('value | date: "yyyy-MM-ddTHH:mm:ss"'));
var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
var valid = element(by.binding('myForm.input.$valid'));
var input = element(by.model('value'));
var input = element(by.model('example.value'));
// currently protractor/webdriver does not support
// sending keys to all known HTML5 input controls
@@ -328,18 +334,20 @@ var inputType = {
<script>
angular.module('timeExample', [])
.controller('DateController', ['$scope', function($scope) {
$scope.value = new Date(1970, 0, 1, 14, 57, 0);
$scope.example = {
value: new Date(1970, 0, 1, 14, 57, 0)
};
}]);
</script>
<form name="myForm" ng-controller="DateController as dateCtrl">
Pick a between 8am and 5pm:
<input type="time" id="exampleInput" name="input" ng-model="value"
<input type="time" id="exampleInput" name="input" ng-model="example.value"
placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
<span class="error" ng-show="myForm.input.$error.required">
Required!</span>
<span class="error" ng-show="myForm.input.$error.time">
Not a valid date!</span>
<tt>value = {{value | date: "HH:mm:ss"}}</tt><br/>
<tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
@@ -347,9 +355,9 @@ var inputType = {
</form>
</file>
<file name="protractor.js" type="protractor">
var value = element(by.binding('value | date: "HH:mm:ss"'));
var value = element(by.binding('example.value | date: "HH:mm:ss"'));
var valid = element(by.binding('myForm.input.$valid'));
var input = element(by.model('value'));
var input = element(by.model('example.value'));
// currently protractor/webdriver does not support
// sending keys to all known HTML5 input controls
@@ -419,18 +427,20 @@ var inputType = {
<script>
angular.module('weekExample', [])
.controller('DateController', ['$scope', function($scope) {
$scope.value = new Date(2013, 0, 3);
$scope.example = {
value: new Date(2013, 0, 3)
};
}]);
</script>
<form name="myForm" ng-controller="DateController as dateCtrl">
Pick a date between in 2013:
<input id="exampleInput" type="week" name="input" ng-model="value"
<input id="exampleInput" type="week" name="input" ng-model="example.value"
placeholder="YYYY-W##" min="2012-W32" max="2013-W52" required />
<span class="error" ng-show="myForm.input.$error.required">
Required!</span>
<span class="error" ng-show="myForm.input.$error.week">
Not a valid date!</span>
<tt>value = {{value | date: "yyyy-Www"}}</tt><br/>
<tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
@@ -438,9 +448,9 @@ var inputType = {
</form>
</file>
<file name="protractor.js" type="protractor">
var value = element(by.binding('value | date: "yyyy-Www"'));
var value = element(by.binding('example.value | date: "yyyy-Www"'));
var valid = element(by.binding('myForm.input.$valid'));
var input = element(by.model('value'));
var input = element(by.model('example.value'));
// currently protractor/webdriver does not support
// sending keys to all known HTML5 input controls
@@ -510,18 +520,20 @@ var inputType = {
<script>
angular.module('monthExample', [])
.controller('DateController', ['$scope', function($scope) {
$scope.value = new Date(2013, 9, 1);
$scope.example = {
value: new Date(2013, 9, 1)
};
}]);
</script>
<form name="myForm" ng-controller="DateController as dateCtrl">
Pick a month int 2013:
<input id="exampleInput" type="month" name="input" ng-model="value"
Pick a month in 2013:
<input id="exampleInput" type="month" name="input" ng-model="example.value"
placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
<span class="error" ng-show="myForm.input.$error.required">
Required!</span>
<span class="error" ng-show="myForm.input.$error.month">
Not a valid month!</span>
<tt>value = {{value | date: "yyyy-MM"}}</tt><br/>
<tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
@@ -529,9 +541,9 @@ var inputType = {
</form>
</file>
<file name="protractor.js" type="protractor">
var value = element(by.binding('value | date: "yyyy-MM"'));
var value = element(by.binding('example.value | date: "yyyy-MM"'));
var valid = element(by.binding('myForm.input.$valid'));
var input = element(by.model('value'));
var input = element(by.model('example.value'));
// currently protractor/webdriver does not support
// sending keys to all known HTML5 input controls
@@ -607,17 +619,19 @@ var inputType = {
<script>
angular.module('numberExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.value = 12;
$scope.example = {
value: 12
};
}]);
</script>
<form name="myForm" ng-controller="ExampleController">
Number: <input type="number" name="input" ng-model="value"
Number: <input type="number" name="input" ng-model="example.value"
min="0" max="99" required>
<span class="error" ng-show="myForm.input.$error.required">
Required!</span>
<span class="error" ng-show="myForm.input.$error.number">
Not valid number!</span>
<tt>value = {{value}}</tt><br/>
<tt>value = {{example.value}}</tt><br/>
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
@@ -625,9 +639,9 @@ var inputType = {
</form>
</file>
<file name="protractor.js" type="protractor">
var value = element(by.binding('value'));
var value = element(by.binding('example.value'));
var valid = element(by.binding('myForm.input.$valid'));
var input = element(by.model('value'));
var input = element(by.model('example.value'));
it('should initialize to model', function() {
expect(value.getText()).toContain('12');
@@ -695,16 +709,18 @@ var inputType = {
<script>
angular.module('urlExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.text = 'http://google.com';
$scope.url = {
text: 'http://google.com'
};
}]);
</script>
<form name="myForm" ng-controller="ExampleController">
URL: <input type="url" name="input" ng-model="text" required>
URL: <input type="url" name="input" ng-model="url.text" required>
<span class="error" ng-show="myForm.input.$error.required">
Required!</span>
<span class="error" ng-show="myForm.input.$error.url">
Not valid url!</span>
<tt>text = {{text}}</tt><br/>
<tt>text = {{url.text}}</tt><br/>
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
@@ -713,9 +729,9 @@ var inputType = {
</form>
</file>
<file name="protractor.js" type="protractor">
var text = element(by.binding('text'));
var text = element(by.binding('url.text'));
var valid = element(by.binding('myForm.input.$valid'));
var input = element(by.model('text'));
var input = element(by.model('url.text'));
it('should initialize to model', function() {
expect(text.getText()).toContain('http://google.com');
@@ -784,16 +800,18 @@ var inputType = {
<script>
angular.module('emailExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.text = 'me@example.com';
$scope.email = {
text: 'me@example.com'
};
}]);
</script>
<form name="myForm" ng-controller="ExampleController">
Email: <input type="email" name="input" ng-model="text" required>
Email: <input type="email" name="input" ng-model="email.text" required>
<span class="error" ng-show="myForm.input.$error.required">
Required!</span>
<span class="error" ng-show="myForm.input.$error.email">
Not valid email!</span>
<tt>text = {{text}}</tt><br/>
<tt>text = {{email.text}}</tt><br/>
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
@@ -802,9 +820,9 @@ var inputType = {
</form>
</file>
<file name="protractor.js" type="protractor">
var text = element(by.binding('text'));
var text = element(by.binding('email.text'));
var valid = element(by.binding('myForm.input.$valid'));
var input = element(by.model('text'));
var input = element(by.model('email.text'));
it('should initialize to model', function() {
expect(text.getText()).toContain('me@example.com');
@@ -851,7 +869,9 @@ var inputType = {
<script>
angular.module('radioExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.color = 'blue';
$scope.color = {
name: 'blue'
};
$scope.specialValue = {
"id": "12345",
"value": "green"
@@ -859,20 +879,20 @@ var inputType = {
}]);
</script>
<form name="myForm" ng-controller="ExampleController">
<input type="radio" ng-model="color" value="red"> Red <br/>
<input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
<input type="radio" ng-model="color" value="blue"> Blue <br/>
<tt>color = {{color | json}}</tt><br/>
<input type="radio" ng-model="color.name" value="red"> Red <br/>
<input type="radio" ng-model="color.name" ng-value="specialValue"> Green <br/>
<input type="radio" ng-model="color.name" value="blue"> Blue <br/>
<tt>color = {{color.name | json}}</tt><br/>
</form>
Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
</file>
<file name="protractor.js" type="protractor">
it('should change state', function() {
var color = element(by.binding('color'));
var color = element(by.binding('color.name'));
expect(color.getText()).toContain('blue');
element.all(by.model('color')).get(0).click();
element.all(by.model('color.name')).get(0).click();
expect(color.getText()).toContain('red');
});
@@ -902,28 +922,30 @@ var inputType = {
<script>
angular.module('checkboxExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.value1 = true;
$scope.value2 = 'YES'
$scope.checkboxModel = {
value1 : true,
value2 : 'YES'
};
}]);
</script>
<form name="myForm" ng-controller="ExampleController">
Value1: <input type="checkbox" ng-model="value1"> <br/>
Value2: <input type="checkbox" ng-model="value2"
Value1: <input type="checkbox" ng-model="checkboxModel.value1"> <br/>
Value2: <input type="checkbox" ng-model="checkboxModel.value2"
ng-true-value="'YES'" ng-false-value="'NO'"> <br/>
<tt>value1 = {{value1}}</tt><br/>
<tt>value2 = {{value2}}</tt><br/>
<tt>value1 = {{checkboxModel.value1}}</tt><br/>
<tt>value2 = {{checkboxModel.value2}}</tt><br/>
</form>
</file>
<file name="protractor.js" type="protractor">
it('should change state', function() {
var value1 = element(by.binding('value1'));
var value2 = element(by.binding('value2'));
var value1 = element(by.binding('checkboxModel.value1'));
var value2 = element(by.binding('checkboxModel.value2'));
expect(value1.getText()).toContain('true');
expect(value2.getText()).toContain('YES');
element(by.model('value1')).click();
element(by.model('value2')).click();
element(by.model('checkboxModel.value1')).click();
element(by.model('checkboxModel.value2')).click();
expect(value1.getText()).toContain('false');
expect(value2.getText()).toContain('NO');
+1 -1
View File
@@ -19,7 +19,7 @@
* **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
* sure you have parenthesis for correct precedence:
* <pre class="prettyprint">
* <div ng-init="test1 = (data | orderBy:'name')"></div>
* `<div ng-init="test1 = (data | orderBy:'name')"></div>`
* </pre>
* </div>
*
+1 -1
View File
@@ -837,7 +837,7 @@ function $LocationProvider() {
// TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
// currently we open nice url link and redirect then
if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.which == 2) return;
if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
var elm = jqLite(event.target);
+53
View File
@@ -3,6 +3,25 @@
describe('a', function() {
var element, $compile, $rootScope;
beforeEach(module(function($compileProvider) {
$compileProvider.
directive('linkTo', valueFn({
restrict: 'A',
template: '<div class="my-link"><a href="{{destination}}">{{destination}}</a></div>',
replace: true,
scope: {
destination: '@linkTo'
}
})).
directive('linkNot', valueFn({
restrict: 'A',
template: '<div class="my-link"><a href>{{destination}}</a></div>',
replace: true,
scope: {
destination: '@linkNot'
}
}));
}));
beforeEach(inject(function(_$compile_, _$rootScope_) {
$compile = _$compile_;
@@ -76,6 +95,40 @@ describe('a', function() {
});
it('should not preventDefault if anchor element is replaced with href-containing element', function() {
spyOn(jqLite.prototype, 'on').andCallThrough();
element = $compile('<a link-to="https://www.google.com">')($rootScope);
$rootScope.$digest();
var child = element.children('a');
var preventDefault = jasmine.createSpy('preventDefault');
child.triggerHandler({
type: 'click',
preventDefault: preventDefault
});
expect(preventDefault).not.toHaveBeenCalled();
});
it('should preventDefault if anchor element is replaced with element without href attribute', function() {
spyOn(jqLite.prototype, 'on').andCallThrough();
element = $compile('<a link-not="https://www.google.com">')($rootScope);
$rootScope.$digest();
var child = element.children('a');
var preventDefault = jasmine.createSpy('preventDefault');
child.triggerHandler({
type: 'click',
preventDefault: preventDefault
});
expect(preventDefault).toHaveBeenCalled();
});
if (isDefined(window.SVGElement)) {
describe('SVGAElement', function() {
it('should prevent default action to be executed when href is empty', function() {
+51 -4
View File
@@ -1272,7 +1272,7 @@ describe('$location', function() {
it('should not rewrite links with target="_blank"', function() {
configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true, attrs: 'target="_blank"'});
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true, attrs: 'target="_blank"'});
inject(
initBrowser(),
initLocation(),
@@ -1285,7 +1285,7 @@ describe('$location', function() {
it('should not rewrite links with target specified', function() {
configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true, attrs: 'target="some-frame"'});
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true, attrs: 'target="some-frame"'});
inject(
initBrowser(),
initLocation(),
@@ -1480,7 +1480,7 @@ describe('$location', function() {
});
it('should not rewrite when clicked with ctrl pressed', function() {
configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true});
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true});
inject(
initBrowser(),
initLocation(),
@@ -1493,7 +1493,7 @@ describe('$location', function() {
it('should not rewrite when clicked with meta pressed', function() {
configureService({linkHref: '/a?b=c', html5Mode: true, supportHist: true});
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true});
inject(
initBrowser(),
initLocation(),
@@ -1504,6 +1504,53 @@ describe('$location', function() {
);
});
it('should not rewrite when right click pressed', function() {
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true});
inject(
initBrowser(),
initLocation(),
function($browser) {
var rightClick;
if (document.createEvent) {
rightClick = document.createEvent('MouseEvents');
rightClick.initMouseEvent('click', true, true, window, 1, 10, 10, 10, 10, false,
false, false, false, 2, null);
link.dispatchEvent(rightClick);
} else if (document.createEventObject) { // for IE
rightClick = document.createEventObject();
rightClick.type = 'click';
rightClick.cancelBubble = true;
rightClick.detail = 1;
rightClick.screenX = 10;
rightClick.screenY = 10;
rightClick.clientX = 10;
rightClick.clientY = 10;
rightClick.ctrlKey = false;
rightClick.altKey = false;
rightClick.shiftKey = false;
rightClick.metaKey = false;
rightClick.button = 2;
link.fireEvent('onclick', rightClick);
}
expectNoRewrite($browser);
}
);
});
it('should not rewrite when clicked with shift pressed', function() {
configureService({linkHref: 'base/a?b=c', html5Mode: true, supportHist: true});
inject(
initBrowser(),
initLocation(),
function($browser) {
browserTrigger(link, 'click', { keys: ['shift'] });
expectNoRewrite($browser);
}
);
});
it('should not mess up hash urls when clicking on links in hashbang mode', function() {
var base;
+1 -1
View File
@@ -14,7 +14,7 @@ describe('Scope', function() {
it('should expose the constructor', inject(function($rootScope) {
/* jshint -W103 */
if (msie) return;
if (msie < 11) return;
expect($rootScope.__proto__).toBe($rootScope.constructor.prototype);
}));