Jesse
Jesse

Reputation: 825

binding variables to compiled elements in angular Js

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

Answers (1)

KayakDave
KayakDave

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

Related Questions