2016-10-05 30 views
8

Pracuję przy użyciu Angular 1.5.8 i maszynopisu Mam dyrektywę, która jest używana w ramach innej dyrektywy (i oczywiście innego kontrolera). Powiedzmy, że dyrektywa1, kontroler1 i dyrektywa2, kontroler2. Biorąc pod uwagę, że kontroler1 ma już informacje o użytkowniku, chciałbym przekazać te informacje użytkownika do kontrolera2 za pośrednictwem dyrektywy2, aby zapobiec ponownemu pobieraniu informacji z zaplecza. Nie jestem pewien, czy można to zrobić, ale byłoby miło, gdyby to przypadek :)Kątowa dyrektywa odbierająca obiekt jako atrybut za pomocą maszynopisu

Poniżej znajduje się kod, aby pomóc mojemu wyjaśnienie:

dyrektywy1 HTML:

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

loggedUser jest ładowany do konstruktora Controller1 poprzez wywołanie backendu.

kod dyrektywy2 i 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 
    } 
} 

nie mogłem znaleźć sposób na przekazanie obiektu użytkownika do Directive2Ctrl (nawet nie wiem, czy to jest możliwe).

+2

Należy 'user =„ctrl.loggedUser”' w widoku (bez nawiasów klamrowych) i 'użytkownika: "=" 'w definicji bindToController (zamiast @) –

+0

Czy powinienem używać zakresu w kontrolerze lub dyrektywie?A może powinien działać bez potrzeby korzystania z zakresu? – gmesorio

+0

Nie, nie musisz używać tego zakresu jawnie, jeśli używasz wiązania do składni kontrolera. –

Odpowiedz

0

Niestety, zastanawiam się, czy trzeba jeszcze ustawić zakres = {}

+0

Dyrektywa2 nie wymaga dyrektywy1. Wymaga użytkownika. W tym przypadku jest on wykorzystywany w ramach kontrolera, który ma użytkownika, ale niekoniecznie musi to być Controller1. – gmesorio

+0

Chyba jestem nieco zdezorientowany, czy nie mógłbyś ustawić swojego zakresu na użytkownika: "=", zamiast użytkownika: "@", na twoim powiązaniu z kontrolerem – Maccurt

+0

Próbowałem już zasięgu = {}; jak również zmianę @ z = ale nadal nie ma sukcesu. – gmesorio

2

Jeśli chcesz udostępnić dane między różnymi adresami w aplikacji, wystarczy umieścić go w służbie i używać DI gdziekolwiek potrzebne dane.

Oznacza to, że pobierasz dane, przechowujesz je w usłudze i używasz DI do udostępniania danych w różnych lokalizacjach. Nie ma potrzeby przekazywania danych przez wiązania na kilku warstwach, o wiele łatwiej korzystać z usługi.

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>

+0

Ale nie chcę ponownie pobierać danych. Ponieważ Controller1 już pobrał dane użytkownika, a dyrektywa, której używam, znajduje się wewnątrz HTML sterownika 1, więc chciałbym po prostu przekazać go jako parametr. Myślę, że w tym celu użyto zakresu $, ale nie wiem, jak sprawić, by działał on w mojej implementacji Typescript. – gmesorio

+0

Ach, może nie rozumiem cię .. Chodzi ci o to, żeby raz wyciągnąć dane z backendu, a następnie udostępnić je każdemu kontrolerowi za pośrednictwem usługi? Myślę, że byłoby znacznie lepiej. Czy masz próbkę tego? – gmesorio

+0

Dokładnie dodałem krótki fragment kodu, który pokazuje typowy problem w aplikacjach kątowych. Zwykle, dla niektórych stanów dane muszą być pobierane z serwera (wyśmiewane za pomocą $ timeout call). Dane te są często udostępniane w wielu lokalizacjach. Mam nadzieję, że ten przykład pomaga. – dinony

3

Use "zakres" własność zamiast "bindToController" własności i zastąpić "@" z "=". Następnie używam interfejsu dla mojego określonego zakresu, aby uzyskać autouzupełnianie.

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

W swoim html usuń klamry.

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

Próbowałem stworzyć plunkera, ale nie wiem, jak skompilować maszynopis na plunkerze. – gmesorio

+0

https://plnkr.co/edit/0VSQhvrG2yIKhCQ2nJny – gmesorio

+0

Aby skompilować, należy dodać import do pliku .ts. –

2

Tak powinno być. Ale jeśli to nadal nie działa, możesz stworzyć prostego plunkera, a ja go naprawię. Twoje zdrowie!

<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); 
    } 
} 
+0

Stworzyłem tego plunkera, chociaż jeszcze nie działa (nie wiem jak skompilować maszynopis w Plunkerze). Plunker gmesorio