web-dev-qa-db-fra.com

Directive enfant personnalisée accédant à la portée du parent

J'ai deux directives personnalisées dans mon application angularJS. Un acte en tant que parent et un autre en tant qu'enfant. J'essaie d'accéder à la portée du parent dans la directive enfant. Mais je n'obtiens pas la sortie souhaitée.

<div ng-controller="CountryCtrl">
{{myName}}
    <div ng-controller="StateCtrl">
        <state nameofthestate="'Tamilnadu'">
            <city nameofthecity="'Chennai'"></city>
        </state>
    </div>
</div>

et mon script ressemble

var app = angular.module("sampleApp",[]);
app.controller("CountryCtrl",function($scope){
    $scope.myName = "India";
});
app.controller("StateCtrl",function($scope){
});
app.directive("state",function(){return {
    restrict : 'E',
    transclude: true,
    scope : { myName  : '=nameofthestate'},
    template:"**   {{myName}} is inside {{$parent.myName}}<br/><ng-transclude></ng-transclude>"
}});
app.directive("city",function(){return {
    restrict : 'E',
    require:'^state',
    scope : { myName  : '=nameofthecity'},
    template:"****   {{myName}} is inside {{$parent.myName}} which is in {{$parent.$parent.myName }}<br/> "
}});

JSFiddle correspondant disponible dans https://jsbin.com/nozuri/edit?html,js,output

La sortie que je reçois est

India
** Tamilnadu is inside India
**** Chennai is inside India which is in Tamilnadu

et la sortie attendue est

India
** Tamilnadu is inside India
**** Chennai is inside Tamilnadu which is in India

Quelqu'un peut-il m'informer de ce que je fais mal ici?

40

La directive city $ parent est une portée transclue de la directive state.

La portée transclue de la directive state est héritée pour $ parent de la directive state qui est contrôleur, c'est pourquoi $ parent.MyName = India.

Le $ parent de la portée transclue est la portée isolée de la directive d'état (scope = {}), c'est pourquoi $ parent. $ Parent.MyName = Tamilnadu (Partie de Angular 1.3 update)

enter image description here

Petit détail de ce qui se passe: Comment accéder à la portée parent à partir d'une directive personnalisée * avec sa propre portée * dans AngularJS?

transclude: true - la directive crée une nouvelle portée enfant "transclude", qui hérite de manière prototypique de la portée parent. Si la directive crée également une étendue isolée, les étendues transclues et isolées sont des frères et sœurs. La propriété $ parent de chaque étendue fait référence à la même étendue parent.

Mise à jour angulaire v1.3: si la directive crée également une portée isolée, la portée transclue est désormais une enfant de la portée isolée. Les portées transclues et isolées ne sont plus des frères et sœurs. La propriété $ parent de la portée transclude fait désormais référence à la portée isolate.

La réponse de Matthew est également correcte pour les communications de la directive parent-enfant.

28
kwangsa

Est-ce que ça marche pour toi? Adapté de cette réponse .

Il n'y a pas de moyen simple d'accéder à l'élément parent du contenu transclu, nous injectons donc le contrôleur parent dans l'enfant pour accéder à sa portée.

  var app = angular.module('myApp', []);

  app.controller("CountryCtrl",function($scope){
      $scope.myName = "India";
  });

  app.controller("StateCtrl",function($scope){
  });

  app.directive("state",function(){return {
      restrict : 'E',
      transclude: true,
      scope : { myName  : '=nameofthestate'},
      template:"**   {{myName}} is inside {{$parent.myName}}<br/><ng-transclude></ng-transclude>",
      controller: function ($scope) {
        this.getName = function () {
          return $scope.myName;
        }
      }
  }});

  app.directive("city",function(){return {
      restrict : 'E',
      require:'^state',
      scope : { myName  : '=nameofthecity'},
      template:"****   {{myName}} is inside {{parentName}} which is in {{$parent.myName }}<br/> ",
      link: function(scope, element, attrs, ctrl) {
        scope.parentName = ctrl.getName();
      }
  }});
15
Matthew King

Lorsque AngularJS rencontre la transclude, il clone le code HTML avant de le remplacer par le contenu template ou templateUrl. Puis, lorsqu'il rencontre ng-transclude, il compile le contenu transclu, mais le lie à la portée parent au lieu de la portée isolée de la directive. Ainsi, le contenu transclu a toujours accès au contrôleur parent et à son contenu, tandis que la directive HTML a une portée isolée (ou une nouvelle portée, selon le cas).

AngularJS opérationnel

2
gr3g

Consultez la sollicution de ma directive, cela fonctionne avec beaucoup de parents. Ce que j'ai fait a été de supprimer la transclude et d'exiger des paramètres. Ne vous embêtez pas à propos de html sale, regardez juste js, simple comme f ..: D

    CRM.directive('inputwv', function ($compile) {
    var getTemplate = function(contentType) {
        var template = '';

        switch(contentType) {
                case '3':
                    template = '<input type="number" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px;width:100px">'
                    break;
                case '0':
                    template = '<input type="text" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px">'
                    break;
                case '1':
                    template = '<input type="text" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px">'
                    break;
                case '2':
                    template = '<textarea class="materialize-textarea teal-text" type="text" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px">'
                    break;
                case '4':
                    template = '<input type="text" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px">'
                    break;
                case '5':
                    template = '<input type="date" class="datepicker" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px"><script type="text/javascript">$(\'.datepicker\').pickadate({selectMonths: true, selectYears: 15});</script>'
                    break;
                default:
                    template = '<textarea class="materialize-textarea teal-text" type="text" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px">'
            }

        return template;
}

    var linker = function(scope, element, attrs) {
        element.html(getTemplate(attrs.typ)).show();

        $compile(element.contents())(scope);
    }

    return {
        restrict: "E",
        link: linker
    };
});
1
Paweł Smołka