自定义指令未获取模型初始化
Custom directive not picking up model initialization
我编写了一个自定义 AngularJS 指令,它实现了一个基于 Bootstrap Toggle. I added support for angular-translate, but that is beyond my actual proplem. Furthermore, I wanted to use angular-cookies 的切换复选框,以保存和恢复特定复选框的当前状态。
但是,我的指令没有正确获取数据模型的初始值。
这是我的指令:
app.directive('toggleCheckbox', ['$rootScope', '$translate', '$timeout', function($rootScope, $translate, $timeout) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attributes, ngModelController) {
// Change model, when checkbox is toggled
element.on('change.toggle', function(event) {
var checked = element.prop('checked');
console.log('change.toggle was called: ' + checked + ' vs. ' + ngModelController.$viewValue);
if (checked != ngModelController.$viewValue) {
scope.$apply(function changeViewModel() {
ngModelController.$setViewValue(checked);
console.log('change.toggle:', checked);
});
}
});
// Render element
ngModelController.$render = function() {
element.bootstrapToggle(ngModelController.$viewValue ? 'on' : 'off')
};
// Translate checkbox labels
var updateLabels = function() {
var offLabel = (attributes['off'] ? $translate.instant(attributes['off']) : 'Off');
var onLabel = (attributes['on'] ? $translate.instant(attributes['on']) : 'On');
angular.element(document).find('label.btn.toggle-off').html(offLabel);
angular.element(document).find('label.btn.toggle-on').html(onLabel);
};
// Update labels, when language is changed at runtime
$rootScope.$on('$translateChangeSuccess', function() {
updateLabels();
});
// Initialize labels for the first time
$timeout(function() {
updateLabels();
});
// Clean up properly
scope.$on('$destroy', function() {
element.off('change.toggle');
element.bootstrapToggle('destroy');
});
// Initialize element based on model
var initialValue = scope.$eval(attributes.ngModel);
console.log('initialValue:', initialValue);
element.prop('checked', initialValue);
}
};
}]);
这是我从 cookie 初始化数据模型的方式:
mainController.controller('MainCtrl', ['$scope', '$cookies', 'Main', function($scope, $cookies, Main) {
this.$onInit = function() {
$scope.settings.foobar = $cookies.get('foobar');
console.log('$onInit(): ', $scope.settings.foobar);
};
// ...
}]);
这就是我最终使用指令的方式:
<div id="foobar-switcher" ng-if="isAdmin()">
<label for="foobar_toggle"><span translate="foobar"></span>:</label>
<input id="foobar_toggle" type="checkbox"
ng-model="settings.foobar" ng-change="setFoobarCookie(settings.foobar)" toggle-checkbox
data-off="foo_label" data-offstyle="success"
data-on="bar_label" data-onstyle="danger" />
</div>
最终,我得到了这个调试输出:
controllers.js:33 $onInit(): true
directives.js:76 initialValue: true
directives.js:37 change.toggle was called: false vs. false
因此,如果值 true
存储在 cookie 中,模型将在全局范围内正确初始化,甚至指令使用正确的值来初始化 element
。 change.toggle
事件处理程序也被触发,但是元素的值现在是 false
.
为什么会这样,我该如何解决这个问题?
事实证明,$cookies.get('foobar')
returns 字符串和复选框无法处理该类型的 ng-model
。相反,必须评估 cookie 值,以便可以在数据模型中设置布尔值:
var cookie = $cookies.get('foobar');
$scope.settings.foobar = (cookie === 'true');
然后在页面加载时正确初始化复选框。
我编写了一个自定义 AngularJS 指令,它实现了一个基于 Bootstrap Toggle. I added support for angular-translate, but that is beyond my actual proplem. Furthermore, I wanted to use angular-cookies 的切换复选框,以保存和恢复特定复选框的当前状态。
但是,我的指令没有正确获取数据模型的初始值。
这是我的指令:
app.directive('toggleCheckbox', ['$rootScope', '$translate', '$timeout', function($rootScope, $translate, $timeout) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attributes, ngModelController) {
// Change model, when checkbox is toggled
element.on('change.toggle', function(event) {
var checked = element.prop('checked');
console.log('change.toggle was called: ' + checked + ' vs. ' + ngModelController.$viewValue);
if (checked != ngModelController.$viewValue) {
scope.$apply(function changeViewModel() {
ngModelController.$setViewValue(checked);
console.log('change.toggle:', checked);
});
}
});
// Render element
ngModelController.$render = function() {
element.bootstrapToggle(ngModelController.$viewValue ? 'on' : 'off')
};
// Translate checkbox labels
var updateLabels = function() {
var offLabel = (attributes['off'] ? $translate.instant(attributes['off']) : 'Off');
var onLabel = (attributes['on'] ? $translate.instant(attributes['on']) : 'On');
angular.element(document).find('label.btn.toggle-off').html(offLabel);
angular.element(document).find('label.btn.toggle-on').html(onLabel);
};
// Update labels, when language is changed at runtime
$rootScope.$on('$translateChangeSuccess', function() {
updateLabels();
});
// Initialize labels for the first time
$timeout(function() {
updateLabels();
});
// Clean up properly
scope.$on('$destroy', function() {
element.off('change.toggle');
element.bootstrapToggle('destroy');
});
// Initialize element based on model
var initialValue = scope.$eval(attributes.ngModel);
console.log('initialValue:', initialValue);
element.prop('checked', initialValue);
}
};
}]);
这是我从 cookie 初始化数据模型的方式:
mainController.controller('MainCtrl', ['$scope', '$cookies', 'Main', function($scope, $cookies, Main) {
this.$onInit = function() {
$scope.settings.foobar = $cookies.get('foobar');
console.log('$onInit(): ', $scope.settings.foobar);
};
// ...
}]);
这就是我最终使用指令的方式:
<div id="foobar-switcher" ng-if="isAdmin()">
<label for="foobar_toggle"><span translate="foobar"></span>:</label>
<input id="foobar_toggle" type="checkbox"
ng-model="settings.foobar" ng-change="setFoobarCookie(settings.foobar)" toggle-checkbox
data-off="foo_label" data-offstyle="success"
data-on="bar_label" data-onstyle="danger" />
</div>
最终,我得到了这个调试输出:
controllers.js:33 $onInit(): true
directives.js:76 initialValue: true
directives.js:37 change.toggle was called: false vs. false
因此,如果值 true
存储在 cookie 中,模型将在全局范围内正确初始化,甚至指令使用正确的值来初始化 element
。 change.toggle
事件处理程序也被触发,但是元素的值现在是 false
.
为什么会这样,我该如何解决这个问题?
事实证明,$cookies.get('foobar')
returns 字符串和复选框无法处理该类型的 ng-model
。相反,必须评估 cookie 值,以便可以在数据模型中设置布尔值:
var cookie = $cookies.get('foobar');
$scope.settings.foobar = (cookie === 'true');
然后在页面加载时正确初始化复选框。