Skip to content

Commit 35f3a4a

Browse files
fix($compile): ensure that hidden input values are correct after history.back
Due to the nature of some browser's PageCache/BFCache, returning to an Angular app sometimes causes `input[hidden]` elements to retain the last value that was stored before the page was navigated away from previously. This is particularly problematic if the input has an interpolated value. E.g. `<input type="hidden" value="{{ 1 + 2 }}">` since when the browser returns, instead of the original interpolation template, the HTML contains the previous value `<input type="hidden" value="3">`. This commit instructs the browser not to attempt to reinstate the previous value when navigating back in history by setting `autocomplete="off"` on the hidden input element element.
1 parent ff74511 commit 35f3a4a

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

src/ng/compile.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1538,13 +1538,17 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15381538
var nodeType = node.nodeType,
15391539
attrsMap = attrs.$attr,
15401540
match,
1541+
nodeName,
15411542
className;
15421543

15431544
switch (nodeType) {
15441545
case NODE_TYPE_ELEMENT: /* Element */
1546+
1547+
nodeName = nodeName_(node);
1548+
15451549
// use the node name: <directive>
15461550
addDirective(directives,
1547-
directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
1551+
directiveNormalize(nodeName), 'E', maxPriority, ignoreDirective);
15481552

15491553
// iterate over the attributes
15501554
for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
@@ -1585,6 +1589,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15851589
attrEndName);
15861590
}
15871591

1592+
if (nodeName === 'input' && node.getAttribute('type') === 'hidden') {
1593+
// Hidden input elements can have strange behaviour when navigating back to the page
1594+
// This tells the browser not to try to cache and reinstate previous values
1595+
node.setAttribute('autocomplete', 'off');
1596+
}
1597+
15881598
// use class as directive
15891599
className = node.className;
15901600
if (isObject(className)) {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html ng-app>
3+
<body>
4+
<form>
5+
<input type="hidden" value="{{value}}" />
6+
<button ng-click="value = '{{ 7 * 6 }}'">Click me</button>
7+
</form>
8+
<script src="angular.js"></script>
9+
</body>
10+
</html>

test/e2e/tests/input-hidden.spec.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
3+
describe('hidden thingy', function() {
4+
it('should pass', function() {
5+
6+
loadFixture('input-hidden');
7+
expect(element(by.css('input')).getAttribute('value')).toEqual('');
8+
9+
element(by.css('button')).click();
10+
expect(element(by.css('input')).getAttribute('value')).toEqual('{{ 7 * 6 }}');
11+
12+
loadFixture('sample');
13+
browser.driver.executeScript('history.back()');
14+
var expectedValue = browser.params.browser === 'safari' ? '{{ 7 * 6 }}' : '';
15+
expect(element(by.css('input')).getAttribute('value')).toEqual(expectedValue);
16+
});
17+
});

0 commit comments

Comments
 (0)