angularjs - this angular js




Come accedere all'ambito principale dall'interno di una direttiva personalizzata*con proprio ambito*in AngularJS? (4)

Accedere al metodo del controller significa accedere a un metodo sull'ambito genitore da controller / link / scope direttiva.

Se la direttiva condivide / eredita l'ambito genitore, allora è abbastanza semplice richiamare un metodo dell'ambito genitore.

Non è richiesto altro lavoro quando si desidera accedere al metodo dello scope principale dall'ambito della direttiva isolata.

Esistono alcune opzioni (che possono essere più di quelle elencate di seguito) per richiamare un metodo dell'ambito genitore dall'ambito delle direttive isolate o per osservare le variabili dell'ambito padre ( opzione # 6 in particolare).

Si noti che in questi esempi ho utilizzato la link function ma è possibile utilizzare anche un directive controller in base ai requisiti.

Opzione 1. Attraverso l'oggetto letterale e dal modello html direttivo

index.html

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <p> Directive Content</p>
    <sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged(selectedItems)" items="items"> </sd-items-filter>


    <P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}} </p>

  </body>

</html>

itemfilterTemplate.html

<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" ng-change="selectedItemsChanged({selectedItems:selectedItems})" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>

app.js

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

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems: '=',
      selectedItemsChanged: '&'
    },
    templateUrl: "itemfilterTemplate.html"
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.selectedItemsChanged = function(selectedItems1) {
    $scope.selectedItemsReturnedFromDirective = selectedItems1;
  }

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]

});

lavoro plnkr: http://plnkr.co/edit/rgKUsYGDo9O3tewL6xgr?p=preview

Opzione 2. Attraverso il letterale Object e dal link / scope della direttiva

index.html

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <p> Directive Content</p>
    <sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged(selectedItems)" items="items"> </sd-items-filter>


    <P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}} </p>

  </body>

</html>

itemfilterTemplate.html

<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" 
 ng-change="selectedItemsChangedDir()" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>

app.js

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

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems: '=',
      selectedItemsChanged: '&'
    },
    templateUrl: "itemfilterTemplate.html",
    link: function (scope, element, attrs){
      scope.selectedItemsChangedDir = function(){
        scope.selectedItemsChanged({selectedItems:scope.selectedItems});  
      }
    }
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.selectedItemsChanged = function(selectedItems1) {
    $scope.selectedItemsReturnedFromDirective = selectedItems1;
  }

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]
});

lavoro plnkr: http://plnkr.co/edit/BRvYm2SpSpBK9uxNIcTa?p=preview

Opzione # 3. Attraverso la funzione di riferimento e dalla direttiva template html

index.html

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <p> Directive Content</p>
    <sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged" items="items"> </sd-items-filter>


    <P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnFromDirective}} </p>

  </body>

</html>

itemfilterTemplate.html

<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" 
 ng-change="selectedItemsChanged()(selectedItems)" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>

app.js

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

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems:'=',
      selectedItemsChanged: '&'
    },
    templateUrl: "itemfilterTemplate.html"
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.selectedItemsChanged = function(selectedItems1) {
    $scope.selectedItemsReturnFromDirective = selectedItems1;
  }

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]
});

working plnkr: http://plnkr.co/edit/Jo6FcYfVXCCg3vH42BIz?p=preview

Opzione # 4. Attraverso la funzione di riferimento e dal link / scope della direttiva

index.html

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <p> Directive Content</p>
    <sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged" items="items"> </sd-items-filter>


    <P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}} </p>

  </body>

</html>

itemfilterTemplate.html

<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" ng-change="selectedItemsChangedDir()" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>

app.js

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

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems: '=',
      selectedItemsChanged: '&'
    },
    templateUrl: "itemfilterTemplate.html",
    link: function (scope, element, attrs){
      scope.selectedItemsChangedDir = function(){
        scope.selectedItemsChanged()(scope.selectedItems);  
      }
    }
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.selectedItemsChanged = function(selectedItems1) {
    $scope.selectedItemsReturnedFromDirective = selectedItems1;
  }

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]

});

lavoro plnkr: http://plnkr.co/edit/BSqx2J1yCY86IJwAnQF1?p=preview

Opzione n. 5: tramite il modello ng e l'associazione bidirezionale, è possibile aggiornare le variabili dell'ambito genitore. . Pertanto, in alcuni casi potrebbe non essere necessario richiamare le funzioni dell'ambito genitore.

index.html

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <p> Directive Content</p>
    <sd-items-filter ng-model="selectedItems" selected-items-changed="selectedItemsChanged" items="items"> </sd-items-filter>


    <P style="color:red">Selected Items (in parent controller) set to: {{selectedItems}} </p>

  </body>

</html>

itemfilterTemplate.html

<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" 
 ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>

app.js

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

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems: '=ngModel'
    },
    templateUrl: "itemfilterTemplate.html"
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]
});

lavoro plnkr: http://plnkr.co/edit/hNui3xgzdTnfcdzljihY?p=preview

Opzione n. 6: Attraverso $watch e $watchCollection È un $watchCollection due vie per gli items in tutti gli esempi precedenti, se gli elementi sono modificati nell'ambito genitore, gli articoli in direttiva riflettono anche le modifiche.

Se si desidera guardare altri attributi o oggetti dall'ambito principale, è possibile farlo utilizzando $watch e $watchCollection come indicato di seguito

html

<!DOCTYPE html>
<html ng-app="plunker">

<head>
  <meta charset="utf-8" />
  <title>AngularJS Plunker</title>
  <script>
    document.write('<base href="' + document.location + '" />');
  </script>
  <link rel="stylesheet" href="style.css" />
  <script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
  <script src="app.js"></script>
</head>

<body ng-controller="MainCtrl">
  <p>Hello {{user}}!</p>
  <p>directive is watching name and current item</p>
  <table>
    <tr>
      <td>Id:</td>
      <td>
        <input type="text" ng-model="id" />
      </td>
    </tr>
    <tr>
      <td>Name:</td>
      <td>
        <input type="text" ng-model="name" />
      </td>
    </tr>
    <tr>
      <td>Model:</td>
      <td>
        <input type="text" ng-model="model" />
      </td>
    </tr>
  </table>

  <button style="margin-left:50px" type="buttun" ng-click="addItem()">Add Item</button>

  <p>Directive Contents</p>
  <sd-items-filter ng-model="selectedItems" current-item="currentItem" name="{{name}}" selected-items-changed="selectedItemsChanged" items="items"></sd-items-filter>

  <P style="color:red">Selected Items (in parent controller) set to: {{selectedItems}}</p>
</body>

</html>

script app.js

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

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      name: '@',
      currentItem: '=',
      items: '=',
      selectedItems: '=ngModel'
    },
    template: '<select ng-model="selectedItems" multiple="multiple" style="height: 140px; width: 250px;"' +
      'ng-options="item.id as item.name group by item.model for item in items | orderBy:\'name\'">' +
      '<option>--</option> </select>',
    link: function(scope, element, attrs) {
      scope.$watchCollection('currentItem', function() {
        console.log(JSON.stringify(scope.currentItem));
      });
      scope.$watch('name', function() {
        console.log(JSON.stringify(scope.name));
      });
    }
  }
})

 app.controller('MainCtrl', function($scope) {
  $scope.user = 'World';

  $scope.addItem = function() {
    $scope.items.push({
      id: $scope.id,
      name: $scope.name,
      model: $scope.model
    });
    $scope.currentItem = {};
    $scope.currentItem.id = $scope.id;
    $scope.currentItem.name = $scope.name;
    $scope.currentItem.model = $scope.model;
  }

  $scope.selectedItems = ["allItems"];

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
  }]
});

È sempre possibile consultare la documentazione di AngularJs per spiegazioni dettagliate sulle direttive.

Sto cercando qualsiasi modo per accedere all'ambito "genitore" all'interno di una direttiva. Qualsiasi combinazione di scope, transclude, require, passando in variabili (o lo scope stesso) dall'alto, ecc. Sono assolutamente disposto a piegarmi all'indietro, ma voglio evitare qualcosa di totalmente hacky o non-compatibile. Ad esempio, so che potrei farlo adesso prendendo il $scope dai parametri preLink e iterando su di esso gli ambiti di $sibling di $sibling per trovare il "genitore" concettuale.

Quello che voglio veramente è essere in grado di $watch un'espressione nello scope genitore. Se posso farlo, allora posso realizzare ciò che sto cercando di fare qui: AngularJS - Come renderizzare un partial con le variabili?

Una nota importante è che la direttiva deve essere riutilizzabile nell'ambito dello stesso ambito genitore. Quindi il comportamento predefinito (scope: false) non funziona per me. Ho bisogno di un singolo ambito per istanza della direttiva, e quindi ho bisogno di $watch una variabile che vive nell'ambito genitore.

Un esempio di codice vale 1000 parole, quindi:

app.directive('watchingMyParentScope', function() {
    return {
        require: /* ? */,
        scope: /* ? */,
        transclude: /* ? */,
        controller: /* ? */,
        compile: function(el,attr,trans) {
            // Can I get the $parent from the transclusion function somehow?
            return {
                pre: function($s, $e, $a, parentControl) {
                    // Can I get the $parent from the parent controller?
                    // By setting this.$scope = $scope from within that controller?

                    // Can I get the $parent from the current $scope?

                    // Can I pass the $parent scope in as an attribute and define
                    // it as part of this directive's scope definition?

                    // What don't I understand about how directives work and
                    // how their scope is related to their parent?
                },
                post: function($s, $e, $a, parentControl) {
                    // Has my situation improved by the time the postLink is called?
                }
            }
        }
    };
});

Dopo aver provato tutto, ho finalmente trovato una soluzione.

Basta posizionare il seguente modello:

{{currentDirective.attr = parentDirective.attr; ''}}

Scrive solo l'attributo / variabile dell'ambito genitore che si desidera accedere all'ambito corrente.

Notare anche il ; '' ; '' alla fine della dichiarazione, è per assicurarsi che non ci sia output nel tuo modello. (Angolare valuta ogni affermazione, ma emette solo l'ultima).

È un po 'hacky, ma dopo alcune ore di tentativi ed errori, fa il lavoro.


Vedi Quali sono le sfumature dell'eredità prototipo / prototipo dell'oscilloscopio in AngularJS?

Riassumendo: il modo in cui una direttiva accede al suo ambito genitore ( $parent ) dipende dal tipo di ambito creato dalla direttiva:

  1. default ( scope: false ) - la direttiva non crea un nuovo scope, quindi non c'è ereditarietà qui. L'ambito della direttiva è lo stesso ambito del genitore / contenitore. Nella funzione di collegamento, utilizzare il primo parametro (in genere l' scope ).

  2. scope: true - la direttiva crea un nuovo ambito figlio che eredita prototipicamente dall'ambito principale. Le proprietà definite sull'ambito principale sono disponibili per l' scope della direttiva (a causa dell'ereditarietà di prototipo). State attenti solo a scrivere su una proprietà di un ambito primitivo, che creerà una nuova proprietà sull'ambito della direttiva (che nasconde / ombreggia la proprietà dell'ambito genitore con lo stesso nome).

  3. scope: { ... } - la direttiva crea un nuovo ambito isolato / isolato. Non eredita prototipicamente l'ambito genitore. È ancora possibile accedere all'ambito principale utilizzando $parent , ma questo non è normalmente raccomandato. Al contrario, è necessario specificare quali proprietà dell'ambito genitore (e / o funzione) necessarie per la direttiva tramite attributi aggiuntivi sullo stesso elemento in cui viene utilizzata la direttiva, utilizzando i = , @ e notazione.

  4. transclude: true - la direttiva crea un nuovo ambito figlio "transclusionato", che eredita prototipicamente dall'ambito principale. Se la direttiva crea anche un ambito isolato, gli ambiti transclusi e gli isolati sono fratelli. La proprietà $parent di ogni ambito fa riferimento allo stesso ambito genitore.
    Aggiornamento angolare v1.3 : se la direttiva crea anche un ambito isolato, l'ambito transcluso è ora un figlio dell'ambito isolato. Gli ambiti transclusi e isolati non sono più fratelli. La proprietà $parent dell'ambito transuso ora fa riferimento all'ambito isolato.

Il link sopra ha esempi e immagini di tutti e 4 i tipi.

Non è possibile accedere all'ambito nella funzione di compilazione della direttiva (come menzionato qui: https://github.com/angular/angular.js/wiki/Understanding-Directives ). È possibile accedere all'ambito della direttiva nella funzione di collegamento.

Guardando:

Per 1. e 2. sopra: normalmente si specifica quale proprietà genitore la direttiva ha bisogno tramite un attributo, quindi $ guardarlo:

<div my-dir attr1="prop1"></div>

scope.$watch(attrs.attr1, function() { ... });

Se stai guardando una proprietà dell'oggetto, dovrai usare $ parse:

<div my-dir attr2="obj.prop2"></div>

var model = $parse(attrs.attr2);
scope.$watch(model, function() { ... });

Per 3. sopra (isolare l'ambito), guarda il nome che dai la proprietà direttiva usando la notazione @ o = :

<div my-dir attr3="{{prop3}}" attr4="obj.prop4"></div>

scope: {
  localName3: '@attr3',
  attr4:      '='  // here, using the same name as the attribute
},
link: function(scope, element, attrs) {
   scope.$watch('localName3', function() { ... });
   scope.$watch('attr4',      function() { ... });

Se si utilizza la sintassi ES6 Classes e ControllerAs , è necessario fare qualcosa di leggermente diverso.

Vedere il frammento di seguito e notare che vm è il valore ControllerAs del controller padre utilizzato nell'HTML genitore

myApp.directive('name', function() {
  return {
    // no scope definition
    link : function(scope, element, attrs, ngModel) {

        scope.vm.func(...)




angularjs-directive