angularjs - Angular-direktiv som tar emot objekt som attribut med Typescript


Jag utvecklar med Angular 1.5.8 och Typescript. Jag har en direktiv som används under scope av en annan direktiv (och en annan controller förstås). Låt oss säga Directive1, Controller1 och Directive2, Controller2. Givet att Controller1 redan har användarinformationen, skulle jag vilja skicka denna användarinformation till Controller2 genom Directive2, för att undvika att hämta informationen igen från backend. Jag är inte säker på om detta kan göras, men det skulle vara trevligt om så var fallet :)

Nedan är koden för att hjälpa min förklaring:

Direktiv1 HTML:

<div>
    ...
    <directive2 user="{{ctrl.loggedUser}}"></directive2>
    ...
</div>

loggedUser laddas i Controller1-konstruktören genom ett anrop till backend.

Directive2 och Directive2Ctrl Typescript-kod:

class Directive2 implements ng.IDirective {
    controller = "Directive2Ctrl";
    controllerAs = "d2Ctrl";
    bindToController = {
        user: "@"
    };
    restrict = "E";
    templateUrl = "directive2.html";

    static factory(): ng.IDirectiveFactory {
        const directive = () => new Directive2();
        return directive;
    }
}
angular
    .module("app")
    .controller("Directive2Ctrl", Directive2Ctrl)
    .directive("directive2", Directive2.factory());


class Directive2Ctrl implements IDirective2Ctrl {
    public user: User;

    constructor(user: User) {
         // user is undefined
    }

    $onInit(user: User): void {
        // user is undefined
    }
}

Jag kunde inte hitta ett sätt att skicka användarobjektet till Directive2Ctrl (inte ens säker på om det är möjligt).

Svar #1

Använd egenskapen "scope" istället för egenskapen "bindToController" och ersätt din "@" med "=". Sedan använder jag ett gränssnitt för min specifika scope för att få autokomplettering.

export interface IMyDirectiveScope extends ng.IScope {
    user: any;
}

export class Myirective {
    public restrict: string = 'E';
    public templateUrl = "/mytemplate.html";
    public link: (scope: IMyDirectiveScope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes, ngModel: ng.INgModelController) => void;
    public scope = {
        user: "="
    };

    constructor() {
        var context = this;
        context.link = (scope: IMyDirectiveScope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes, ngModel: ng.INgModelController) => {
           //INSERT YOUR CODE
           //console.log(scope.user);
        };
    }

    public static Factory() {
        var directive = () => {
            return new MyDirective();
        };

        return directive;
    }
}

I din HTML, ta bort dina måsvingar.

<div>
    ...
    <directive2 user="ctrl.loggedUser"></directive2>
    ...
</div>

Svar #2

Om du vill dela data mellan olika platser i din applikation, lägg bara den i en tjänst och använd DI där du behöver datan.

Det vill säga, hämta datan, lagra den i en tjänst och använd DI för att göra datan tillgänglig på olika platser. Det finns inget behov av att skicka data genom bindningar över flera lager, mycket enklare att använda en tjänst.

var mod = angular.module('testApp', ['ngRoute']);

mod.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider.
      when('/intern', {
        template: '<div class="outer" ng-controller="InternController">{{User.firstName}} <div class="nested" ng-controller="NestedController">{{NestedUser.lastName}}<test-dir></test-dir></div></div>',
        resolve: {
          userResolve: function($q, $timeout, User) {
            var deferred = $q.defer();
          
            // mock server call, which returns server data
            $timeout(function() {
              var mockUserResp = {
                firstName: 'John',
                lastName: 'Rambo'
              };
              User.setUser(mockUserResp);
            
              deferred.resolve();
            }, 1000);
          
            return deferred.promise;
          }
        }
      }).
      otherwise({
        redirectTo: '/intern'
      });
  }]);

mod.factory('User', function() {
  var _user = null;
  return {
    setUser: function(user) {
      _user = user;
    },
    getUser: function() {
      return _user;
    }
  }  
});

mod.controller('InternController', function($scope, User) {
  $scope.User = User.getUser();
});

mod.controller('NestedController', function($scope, User) {
  $scope.NestedUser = User.getUser();
});

mod.directive('testDir', function(User) {
  return {
    restrict: 'EA',
    scope: {},
    template: '<div class="dir">{{firstName}} is a cool guy.</div>',
    link: function(scope) {
      scope.firstName = User.getUser().firstName;
    }
  };
});
.outer {
  border: 1px solid green;
}

.nested {
  border: 1px solid blue;
}

.dir {
  border: 1px solid orange;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.12/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.12/angular-route.min.js"></script>


<div ng-app="testApp">
  <div ng-view></div>
</div>

Relaterade artiklar