2

I am continuing my quest to learn Typescript and AngularJS and had a question on scope. I am working on a project, where each person in the project is responsible for a directive. However I recently hit a road block in my understanding.

Currently I have an html page that has the following

<html ng-app ="helloworld">
    <head>
        <!--insert scripts here-->
    </head>
    <body>
       <direct-a></direct-a>
       <hello-world></hello-world>
    </body>
</html>

We have set the directive to be something along the lines of this:

/// <reference path="../../../typings/tsd.d.ts" />
module helloWorld{

var app :angular.IModule = angular.module('helloWorld');

app.directive('helloWorld', HelloWorldDirective);

    function HelloWorldDirective() :ng.IDirective{

        return <ng.IDirective>{
            controller: 'HelloWorldController',
            controllerAs : 'vm',
            templateUrl: './app/HelloWorld/HelloWorld.html'          

        };

};

}

I had similar code to this on the <direct-a> directive, but with the code, I was unable to see anything from the <hello-world> tag, until we changed controllerAs to something other than 'vm'. Which leads me to wonder if we need to devise naming conventions for our custom directives, and not use the 'vm' phrase for controllerAs? Or is there a trick I am missing here?

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
PhoenixLament
  • 741
  • 1
  • 11
  • 32

1 Answers1

3

I created two examples:

BROKEN

This is the way how I created <hello-world> directive (related to this How can I define my controller using TypeScript?)

module HelloWorld
{
    var app = angular.module('TheApp');
    
    export class HelloWorldDirective implements ng.IDirective
    {
        public restrict: string = "E";
        public replace: boolean = true;
        public template: string = "<div>" +
            "<input ng-model=\"vm.MyValue\" />" +
            "<button ng-click=\"vm.Show()\" >Show my value</button>" +
            "<p> my value <b>{{vm.MyValue}}</b></p>" +
            "</div>";
        public controller: string = 'HelloWorldCtrl';
        public controllerAs: string = 'vm';
        //public scope = {};
    }    
    app.directive("helloWorld", [() => new HelloWorld.HelloWorldDirective()]);

    export interface IHelloWorldScope  extends ng.IScope
    {
        // properties for isolated scope
    }
    export class HelloWorldCtrl
    {
        static $inject = ["$scope"];
        constructor(protected $scope: HelloWorld.IHelloWorldScope){ }
        public MyValue: string = "InitValue";
        public Show(): void
        {
            alert(this.MyValue)
        }
    }
    app.controller('HelloWorldCtrl',  HelloWorld.HelloWorldCtrl);
}

And this is <other-directive> TypeScript code:

module OtherDirective
{
    var app = angular.module('TheApp');
    
    export class OtherDirectiveDirective implements ng.IDirective
    {
        public restrict: string = "E";
        public replace: boolean = true;
        public template: string = "<h4>" +
            "OtherValue: {{vm.OtherValue}}" +
            "</h4>";
        public controller: string = 'OtherDirectiveCtrl';
        public controllerAs: string = 'vm';
        //public scope = {};
    }

    app.directive("otherDirective", [() => new OtherDirective.OtherDirectiveDirective()]);

    export interface IOtherDirectiveScope  extends ng.IScope
    {
      // properties for isolated scope
    }
    export class OtherDirectiveCtrl
    {
        static $inject = ["$scope"];
        constructor(protected $scope: OtherDirective.IOtherDirectiveScope) {}
        public OtherValue: string = "This is other Value";
    }
    app.controller('OtherDirectiveCtrl',  OtherDirective.OtherDirectiveCtrl);
}

So, if we would place these two side by side:

<div>
    <hello-world></hello-world>
    <other-directive></other-directive>
</div>

The <hello-world> won't work. It will be broken. The reason is "shared", not isolated scope, which both directives access.

make it WORKING

To fix it, we have to change both (at least one in this simple example). Or use different names for controllerAs.

check the doc (Angular Directive Guide)

Isolating the Scope of a Directive

Our myCustomer directive above is great, but it has a fatal flaw. We can only use it once within a given scope.
...
What we want to be able to do is separate the scope inside a directive from the scope outside, and then map the outer scope to a directive's inner scope. We can do this by creating what we call an isolate scope. To do this, we can use a directive's scope option:

Here we will ask for isolated scope:

export class HelloWorldDirective implements ng.IDirective
{
    public restrict: string = "E";
    public replace: boolean = true;
    public template: string = "<div>" +
        "<input ng-model=\"vm.MyValue\" />" +
        "<button ng-click=\"vm.Show()\" >Show my value</button>" +
        "<p> my value <b>{{vm.MyValue}}</b></p>" +
        "</div>";
    public controller: string = 'HelloWorldCtrl';
    public controllerAs: string = 'vm';
    // isolated scope requested
    public scope = {};
}

export class OtherDirectiveDirective implements ng.IDirective
{
    public restrict: string = "E";
    public replace: boolean = true;
    public template: string = "<h4>" +
        "OtherValue: {{vm.OtherValue}}" +
        "</h4>";
    public controller: string = 'OtherDirectiveCtrl';
    public controllerAs: string = 'vm';
    // isolated scope requested as well
    public scope = {};
}

Check it in action here More about this approach:

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335