Reputation: 825
I am dynamically creating an element with angular. When the app initally runs using app.run() the element is created and I compile the element, after compiling the element I add an ng-show="active" so I can toggle the visibility of the element and possibly animate a transition later using that directive. The only problem is the compiled element only binds once it looks like to the variable active. Once its set to true it won't hide again. Do I need to use digest or some other method to get it the binding to work properly?
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<script src="lib/angular/angular.min.js"></script>
<link rel="stylesheet" href="lib/bootstrap/dist/css/bootstrap.min.css" />
<style>
.message-app { width:100px; height:30px; background-color:#005cab; color:white; text-align:center; line-height:30px; margin-bottom:5px; }
.app-console { width:300px; height:30px; border:1px solid red; }
</style>
</head>
<body ng-controller="AppCtrl">
<div class="message-app" val=''>click</div>
<div class="message-app" val='true'>click</div>
</body>
</html>
<script>
var app = angular.module("messageApp", []);
app.run(function($rootScope){
$rootScope.message = angular.element("<div class='app-console' ng-show='active'></div>");
angular.element(document.body).append($rootScope.message);
})
function AppCtrl($scope, $compile, $rootScope){
$scope.active = false;
$compile($rootScope.message)($scope);
$scope.setActive = function(val){
$scope.active = val;
$scope.$apply();
}
}
app.directive("messageApp", function(){
return {
restrict:"C",
controller:"AppCtrl",
scope:{
val:"@"
},
link:function(scope, element, attr){
element.bind("click", function(){
scope.setActive(Boolean(scope.val));
})
}
}
})
angular.element(document).ready(function(){
angular.bootstrap(document.querySelector("html"), ["messageApp"])
})
</script>
To make this simple I didn't put the js in a separate file. Is there something that I am doing wrong with this?
Upvotes: 1
Views: 940
Reputation: 24676
Glossing over the downsides of doing DOM manipulation in .run
the issue you're having is related to your directive's isolated scopes.
When you call setActive()
from the directive all the scope references inside setActive()
are to the calling object's scope (which is the directive's isolate scope). So you're currently manipulating a property active
on each directive's isolate scope. What you want, however, is to change active
on the appCtrl
scope.
To accomplish this I'd get rid of setActive()
and do this entirely in your directive with these 3 steps:
1) Add active
to your directive's scope:
scope:{
val:"@",
isactive: "="
},
2) Pass active
to your directive:
<div class="message-app" val='' isactive="active">click</div>
<div class="message-app" val='true' isactive="active">click</div>
3) Change active
directly in your click handler:
element.bind("click", function(){
scope.$apply(function() {
scope.isactive =Boolean(scope.val);
});
});
Now you don't need to worry about having your directive talk to your controller, or about which scope you're on. And you've got a clear interface to your directive.
Here's a working fiddle
Upvotes: 1