使用TypeScript编写的Angular指令如何接收对象作为属性?

8
我正在使用Angular 1.5.8和Typescript进行开发。 我有一个指令,它在另一个指令(和另一个控制器)的范围内使用。假设有指令1、控制器1和指令2、控制器2。 鉴于控制器1已经具有用户信息,我希望通过Directive2将此用户信息传递给Controller2,以防止再次从后端获取信息。 我不确定是否可以这样做,但如果可以那就太好了 :)
以下是代码,用以说明我的问题:
Directive1 HTML:
<div>
    ...
    <directive2 user="{{ctrl.loggedUser}}"></directive2>
    ...
</div>

在Controller1构造函数中,通过调用后端加载loggedUser。

Directive2和Directive2Ctrl TypeScript代码:

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
    }
}

我找不到将用户对象传递给Directive2Ctrl的方法(甚至不确定是否可能)。


2
在视图中应该是 user="ctrl.loggedUser"(没有花括号),在 bindToController 定义中应该是 user: "="(而不是 @)。 - Aleksey L.
我应该在控制器内部使用作用域还是指令?或者它是否可以在不使用作用域的情况下工作? - gmesorio
不需要显式地使用作用域,如果你正在使用绑定到控制器的语法。 - Aleksey L.
5个回答

4
使用“scope”属性替代“bindToController”属性,并将您的“@”替换为“=”。 然后我使用特定范围的接口来获得自动完成。
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;
    }
}

在你的HTML中,删除花括号。
<div>
    ...
    <directive2 user="ctrl.loggedUser"></directive2>
    ...
</div>

我尝试创建一个Plunker,但不确定如何在Plunker上编译TypeScript。 - gmesorio
为了编译,您需要在.ts文件中添加导入。 - Codrut TG

2
如果您想在应用程序的不同位置共享数据,只需将其放入服务中,并在需要数据的任何位置使用DI。
也就是说,获取数据,将其存储在服务中,并使用DI使数据在不同位置可用。无需通过多个层传递数据绑定,使用服务更加简单。

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>


但我不想再次获取数据。因为Controller1已经获取了用户数据,而我正在使用的指令位于Controller1 HTML内部,所以我想将其作为参数传递。我认为$scope用于此目的,但我不清楚如何在我的TypeScript实现中使其工作。 - gmesorio
啊,也许我误解了你的意思。你是说从后端拉取数据一次,然后通过服务使其对任何控制器可用?我认为这会更好。你有这方面的样例吗? - gmesorio
没错,我添加了一个简短的代码片段,展示了 Angular 应用程序中常见的问题。通常,需要从服务器获取某些状态数据(使用 $timeout 调用模拟)。然后,这些数据经常在多个位置共享。希望这个例子有所帮助。 - dinony

2

应该是这样的。但如果对你仍然无效,你可以创建一个简单的plunker,我会在那里修复它。干杯!

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

`

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

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


class Directive2Ctrl implements IDirective2Ctrl {
    public user: User;

    $onInit(user: User): void {
        // user should be available
        console.log(this.user);
    }
}

我创建了这个Plunker,尽管它还没有工作(我不知道如何在Plunker中编译TypeScript)。<a href="https://plnkr.co/edit/0VSQhvrG2yIKhCQ2nJny?p=info">Plunker</a> - gmesorio

0

0

抱歉,我想知道您是否仍然需要设置 scope = {}


Directive2不需要Directive1。它需要一个用户。在这种情况下,它被用在具有用户的控制器范围内,但它不一定是Controller1。 - gmesorio
我想我有点困惑,你能否将作用域设置为user:“=”而不是user:'@',在绑定到控制器时? - Maccurt
我已经尝试了 scope = { }; 以及将 @ 更改为 =,但仍然没有成功。 - gmesorio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接