多个指令的共享控制器不起作用

时间:2016-01-19 00:25:50

标签: angularjs ng-class

Plunker Code

我遇到一个问题,让ng-class在flipCard指令的模板中工作。从技术上讲,它确实有效,如果我在控制器中立即设置属性,它将添加css类。

在我看来,子指令可能是获取控制器的独立副本而不是共享基本flipCard指令的控制器。因此,当我调用flipCtrl.move时,它调用flipCardOver指令的控制器实例,因为在flipCtrl.move函数中设置控制器上的属性不会更新基本父项flipped属性虽然控制台记录它说它设置为true。

目标flipCard上的控制器与flipCardBackflipCardFrontflipCardOverflipCardReset共享在页面上允许多个flipCard指令并且没有冲突。

我错过了什么?

angular.module('cardFlip', [])
  .controller('flipCardController', ['$scope', '$element', '$timeout', '$window',
    function($scope, $element, $timeout, $window) {
      var vm = this;

      vm.flipped = false;
      vm.moved = false;

      vm.originalTop = -1;
      vm.originalLeft = -1;


      vm.move = function(e) {

        vm.flipped = true;
        console.log(vm.flipped);
      };


      vm.reset = function() {
        vm.flipped = false;
      };
    }
  ])
  .directive('flipCard', function() {

    return {
      restrict: 'AE',
      controller: 'flipCardController',
      controllerAs: 'flipCtrl',
      scope: true,
      transclude: true,

      // LOOK: this is the template that I am expecting to change
      template: '<div class="container"><div class="panel" ng-class="{ flip: flipCtrl.flipped, slide: flipCtrl.moved }" ng-transclude></div></div>'
    }

  })
  .directive('flipCardFront', function() {
    return {
      restrict: 'AE',
      require: '^flipCard',
      transclude: true,
      template: '<div class="front" ng-transclude></div>'
    }
  })
  .directive('flipCardBack', function() {
    return {
      restrict: 'AE',
      require: '^flipCard',
      transclude: true,
      template: '<div class="back" ng-transclude></div>'
    }
  })
  .directive('flipCardOver', function() {

    return {
      restrict: 'AE',
      require: '^flipCard',
      link: function(scope, element, attribs, flipCtrl) {


        // LOOK: this is the event I am expecting to call move that sets flipped to true
        element.on('click', flipCtrl.move);
      }
    }
  })
  .directive('flipCardReset', function() {
    return {
      restrict: 'AE',
      require: '^flipCard',
      link: function(scope, element, attribs, flipCtrl) {

        element.on('click', flipCtrl.reset);

      }
    }
  });
/* Styles go here */

[ng-click] {
  cursor: pointer;
}
.panel .pad {
  padding: 0 15px;
}
.panel.flip .action {
  display: none;
}
.panel {
  float: left;
  width: 200px;
  height: 200px;
  margin: 20px;
  position: relative;
  font-size: .8em;
  -webkit-perspective: 600px;
  perspective: 600px;
}
/* -- make sure to declare a default for every property that you want animated -- */

/* -- general styles, including Y axis rotation -- */

.panel .front {
  float: none;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 900;
  width: inherit;
  height: inherit;
  background: #6b7077;
  -webkit-transform: rotateX(0) rotateY(0);
  transform: rotateX(0) rotateY(0);
  -webkit-transform-style: preserve-3d;
  transform-style: preserve-3d;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  /* -- transition is the magic sauce for animation -- */
  -webkit-transition: all .4s ease-in-out;
  transition: all .4s ease-in-out;
}
.panel.flip .front {
  z-index: 900;
  -webkit-transform: rotateY(179deg);
  transform: rotateY(179deg);
}
.panel.slide {
  top: 15%;
  left: 15%;
  -webkit-transition: all 5s ease-in-out;
  transition: all 5s ease-in-out;
}
.panel .back {
  float: none;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 800;
  width: inherit;
  height: inherit;
  box-shadow: 0 2px 15px rgba(0, 0, 0, 0.2);
  -webkit-transform: rotateY(-179deg);
  transform: rotateY(-179deg);
  -webkit-transform-style: preserve-3d;
  transform-style: preserve-3d;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  /* -- transition is the magic sauce for animation -- */
  -webkit-transition: all .4s ease-in-out;
  transition: all .4s ease-in-out;
}
.panel.flip .back {
  z-index: 1000;
  -webkit-transform: rotateX(0) rotateY(0);
  transform: rotateX(0) rotateY(0);
}
<!DOCTYPE html>
<html>

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
</head>

<body>
  <div ng-app="cardFlip">
    <div ui-view="main">
      <flip-card>
        <flip-card-front>
          <div style="width:50px;height:50px;" flip-card-over="function(){return true;}">
            FRONT1
          </div>
        </flip-card-front>
        <flip-card-back>
          <div style="width:100px;height:100px;" flip-card-reset="function(){return true;}">
            BACK1
          </div>
        </flip-card-back>
      </flip-card>
    </div>
  </div>
</body>

</html>

1 个答案:

答案 0 :(得分:2)

起初我也很难过,但后来我意识到 - 你还没有告诉Angular使用scope.$evalAsync()进行更改(比$apply()$digest()更安全,以防万一已经是一个消化发生了)。这是因为您自己处理点击,而不是使用ng-click(触发摘要,因此不会出现此问题)。

这是forked Plunkr,它有效。

&#13;
&#13;
angular.module('cardFlip', [])
  .controller('flipCardController', ['$scope', '$element', '$timeout', '$window',
    function($scope, $element, $timeout, $window) {
      var vm = this;

      vm.flipped = false;
      vm.moved = false;

      vm.originalTop = -1;
      vm.originalLeft = -1;


      vm.move = function(e) {

        vm.flipped = true;
        console.log(vm.flipped);
      };


      vm.reset = function() {
        vm.flipped = false;
      };
    }
  ])
  .directive('flipCard', function() {

    return {
      restrict: 'AE',
      controller: 'flipCardController',
      controllerAs: 'flipCtrl',
      scope: true,
      transclude: true,

      // LOOK: this is the template that I am expecting to change
      template: '<div class="container"><div class="panel" ng-class="{ flip: flipCtrl.flipped, slide: flipCtrl.moved }" ng-transclude></div></div>'
    }

  })
  .directive('flipCardFront', function() {
    return {
      restrict: 'AE',
      require: '^flipCard',
      transclude: true,
      template: '<div class="front" ng-transclude></div>'
    }
  })
  .directive('flipCardBack', function() {
    return {
      restrict: 'AE',
      require: '^flipCard',
      transclude: true,
      template: '<div class="back" ng-transclude></div>'
    }
  })
  .directive('flipCardOver', function() {

    return {
      restrict: 'AE',
      require: '^flipCard',
      link: function(scope, element, attribs, flipCtrl) {


        // LOOK: this is the event I am expecting to call move that sets flipped to true
        element.on('click', function () {
            flipCtrl.move();
            scope.$evalAsync(); // tell Angular we did something
        });
      }
    }
  })
  .directive('flipCardReset', function() {
    return {
      restrict: 'AE',
      require: '^flipCard',
      link: function(scope, element, attribs, flipCtrl) {

        element.on('click', function () {
            flipCtrl.reset();
            scope.$evalAsync(); // tell Angular
        });
      }
    }
  });
&#13;
/* Styles go here */

[ng-click] {
  cursor: pointer;
}
.panel .pad {
  padding: 0 15px;
}
.panel.flip .action {
  display: none;
}
.panel {
  float: left;
  width: 200px;
  height: 200px;
  margin: 20px;
  position: relative;
  font-size: .8em;
  -webkit-perspective: 600px;
  perspective: 600px;
}
/* -- make sure to declare a default for every property that you want animated -- */

/* -- general styles, including Y axis rotation -- */

.panel .front {
  float: none;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 900;
  width: inherit;
  height: inherit;
  background: #6b7077;
  -webkit-transform: rotateX(0) rotateY(0);
  transform: rotateX(0) rotateY(0);
  -webkit-transform-style: preserve-3d;
  transform-style: preserve-3d;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  /* -- transition is the magic sauce for animation -- */
  -webkit-transition: all .4s ease-in-out;
  transition: all .4s ease-in-out;
}
.panel.flip .front {
  z-index: 900;
  -webkit-transform: rotateY(179deg);
  transform: rotateY(179deg);
}
.panel.slide {
  top: 15%;
  left: 15%;
  -webkit-transition: all 5s ease-in-out;
  transition: all 5s ease-in-out;
}
.panel .back {
  float: none;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 800;
  width: inherit;
  height: inherit;
  box-shadow: 0 2px 15px rgba(0, 0, 0, 0.2);
  -webkit-transform: rotateY(-179deg);
  transform: rotateY(-179deg);
  -webkit-transform-style: preserve-3d;
  transform-style: preserve-3d;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  /* -- transition is the magic sauce for animation -- */
  -webkit-transition: all .4s ease-in-out;
  transition: all .4s ease-in-out;
}
.panel.flip .back {
  z-index: 1000;
  -webkit-transform: rotateX(0) rotateY(0);
  transform: rotateX(0) rotateY(0);
}
&#13;
<!DOCTYPE html>
<html>

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
</head>

<body>
  <div ng-app="cardFlip">
    <div ui-view="main">
      <flip-card>
        <flip-card-front>
          <div style="width:50px;height:50px;" flip-card-over="function(){return true;}">
            FRONT1
          </div>
        </flip-card-front>
        <flip-card-back>
          <div style="width:100px;height:100px;" flip-card-reset="function(){return true;}">
            BACK1
          </div>
        </flip-card-back>
      </flip-card>
    </div>
  </div>
</body>

</html>
&#13;
&#13;
&#13;