多个指令的共享控制器不起作用
Sharing controller for multiple directives not working
我在让 ng-class 在 flipCard
指令的模板中工作时遇到问题。从技术上讲它确实有效,如果我在控制器中立即设置 属性 它将添加 css class.
在我看来,子指令可能正在获取控制器的独立副本,而不是共享基础 flipCard
指令的控制器。因此,当我调用 flipCtrl.move
时,它正在调用 flipCardOver
指令的控制器实例,因为在 flipCtrl.move
函数中设置控制器上的 属性 不会更新基本父级 flipped
属性,虽然控制台记录它说它设置为 true。
目标: 在 flipCard
上拥有一个与 flipCardBack
、flipCardFront
、flipCardOver
、[= 共享的控制器23=] 同时还允许在一个页面上使用多个 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>
起初我也被难住了,但后来我意识到 - 你没有告诉 Angular 使用 scope.$evalAsync()
的更改(比 $apply()
或 [=15= 更安全] 以防已经有摘要发生)。这是因为您自己处理点击,而不是使用 ng-click
(触发摘要,所以没有这个问题)。
这里有一个 forked Plunkr 可以正常工作。
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
});
}
}
});
/* 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>
我在让 ng-class 在 flipCard
指令的模板中工作时遇到问题。从技术上讲它确实有效,如果我在控制器中立即设置 属性 它将添加 css class.
在我看来,子指令可能正在获取控制器的独立副本,而不是共享基础 flipCard
指令的控制器。因此,当我调用 flipCtrl.move
时,它正在调用 flipCardOver
指令的控制器实例,因为在 flipCtrl.move
函数中设置控制器上的 属性 不会更新基本父级 flipped
属性,虽然控制台记录它说它设置为 true。
目标: 在 flipCard
上拥有一个与 flipCardBack
、flipCardFront
、flipCardOver
、[= 共享的控制器23=] 同时还允许在一个页面上使用多个 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>
起初我也被难住了,但后来我意识到 - 你没有告诉 Angular 使用 scope.$evalAsync()
的更改(比 $apply()
或 [=15= 更安全] 以防已经有摘要发生)。这是因为您自己处理点击,而不是使用 ng-click
(触发摘要,所以没有这个问题)。
这里有一个 forked Plunkr 可以正常工作。
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
});
}
}
});
/* 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>