代码之家  ›  专栏  ›  技术社区  ›  user1438038

自定义指令不接受模型初始化

  •  0
  • user1438038  · 技术社区  · 6 年前

    我已经编写了一个自定义angularjs指令,它基于 Bootstrap Toggle . 我增加了对 angular-translate ,但这超出了我的实际问题。而且,我想用 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():真

    directives.js:76初始值:true

    指令:JS:37变更开关:FALSE vs FALSE

    所以如果这个值 true 存储在cookie中,模型在全局范围内正确初始化,甚至指令也使用正确的值来初始化 element . 这个 change.toggle 事件处理程序也被触发,但是元素的值现在是 false .

    为什么我要解决这个问题?

    1 回复  |  直到 6 年前
        1
  •  0
  •   user1438038    6 年前

    结果发现 $cookies.get('foobar') 返回字符串,复选框无法处理 ng-model 那种类型的。相反,必须评估Cookie值,这样可以在数据模型中设置布尔值:

    var cookie = $cookies.get('foobar');
    $scope.settings.foobar = (cookie === 'true');
    

    然后在页面加载时正确初始化复选框。