在經歷過了 AngularJS browser autofill workaround by using a directive 之後過了幾週,有一天我嘗試對著 login 用的表單亂來(?),發現上的 workaround 其實只能針對在頁面一載入時的自動填入,如果是先清除它,在經過人為的操作之後的自動填入,還是都抓不到… (畢竟 $timeout
只用了一次當然…)
revisit
既然一次的 $timeout
不夠用,而現在要解決的情況就是它「隨時」會在 AngularJS 預設無法察覺的情況下被填入資料,我想最直覺的選擇就是改跑 interval 了。
$interval
在 AngularJS 1.2.0 之後加入了 $interval
這個 service,使用上要注意的是它預設每一個 tick 都會觸發一次 $digest
,而我現在其實並不希望每個 tick 都觸發,而是在真的有被自動填入之後。
因此這邊在 $interval
的第四個參數帶入 false
,讓它不會自動做 $apply()
的動作,靠我判斷後再決定是否 $apply()
。
/* file: auto-fill-sync.js */
app
.directive('autoFillSync', function($interval) {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ngModel) {
var INTERVAL_DELAY = 100;
var intervalPromise;
intervalPromise = $interval(function () {
var newVal = elem.val();
if (ngModel.$viewValue !== newVal) {
scope.$apply(function () {
ngModel.$setViewValue(newVal);
});
}
}, INTERVAL_DELAY, 0, false);
elem.bind('$destroy', function () {
$interval.cancel(intervalPromise);
});
}
};
});
$window.setInterval
其實應該很多人已上線的產品都還沒有升到 1.2.x (或著還在 1.0.x),在沒有 $interval
可以用的情況下,用 $window.setInterval
來擋一下也是合情合理的。
/* file: auto-fill-sync.js */
.directive('autoFillSync', function($window) {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ngModel) {
var INTERVAL_DELAY = 100;
var intervalHandle;
intervalHandle = $window.setInterval(function () {
var newVal = elem.val();
if (ngModel.$viewValue !== newVal) {
scope.$apply(function () {
ngModel.$setViewValue(newVal);
});
}
}, INTERVAL_DELAY);
elem.bind('$destroy', function () {
$window.clearInterval(intervalHandle);
});
}
};
});
後記
自動完成實在太方便了… 請務必一定要讓你的 AngularJS app 支援啊!