2013-04-13 118 views
66

繼我以前的question,我現在正試圖從我的指令調用父控制器上的方法。我得到一個未定義的參數。這是我做的:從AngularJS中的指令調用父控制器的方法

<body ng-app="myApp" ng-controller="MainCtrl"> 
    <span>{{mandat.rum}}</span> 
    <span>{{mandat.surname}}</span> 
<input type="text" ng-model="mandat.person.firstname" /> 
<my-directive mandate-person="mandat.person" updateparent="updatePerson()" > 

    </my-directive> 
</body> 

和腳本:

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

    app.controller('MainCtrl', function ($scope) { 
     $scope.mandat = { name: "John", surname: "Doe", person: { id: 1408, firstname: "sam" } }; 
     $scope.updatePerson = function(person) { 
      alert(person.firstname); 
      $scope.mandat.person = person; 
     } 
    }); 


    app.directive('myDirective', function() { 
     return { 
      restrict: 'E', 
      template: "<div><span>{{mandatePerson.id}}<span><input type='text' ng-model='mandatePerson.firstname' /><button ng-click='updateparent({person: mandatePerson})'>click</button></div>", 
      replace: true, 
      scope: { mandatePerson: '=', updateparent: '&' } 
      } 
     } 
    ) 

時的updatePerson方法被調用,人是不確定的。

的jsfiddle這裏:http://jsfiddle.net/graphicsxp/Z5MBf/7/

回答

54

只是簡單的改變你的HTML如下

<my-directive mandate-person="mandat.person" updateparent="updatePerson(person)" > 

     </my-directive> 

你是不是通過 「人」 用的updatePerson這就是爲什麼它不工作

+0

所以我在做什麼是更新父範圍的正確方法,對嗎?我忘了通過「人」。 – Sam

+0

對其完美無缺 –

+4

對於最初被這個困惑的任何人:注意模板內的ng-click中的對象符號:'ng-click ='updateparent({person:missionsPerson})'' – ErikAGriffin

12

有兩種方法,我們可以使用&=來致電。

如果我使用=的scope屬性,然後

ng-click='updateparent({person: mandatePerson})' 

將改爲

ng-click='updateparent(mandatePerson)' 

而在該指令,

updateparent="updatePerson()" 

將變爲

updateparent="updatePerson" 

沒有必要在這裏提到的論點,他們將被傳遞給控制器​​的功能定義作爲參考。

在其他答案中解釋了使用&

+1

謝謝,通過使用'='的控制器方法比使用'&'更容易,因爲我不必在指令實例中聲明所有參數 –

+1

我剛花了整整一個下午的時間嘗試修復指令。問題是指令聲明中的參數(因爲它們存在的參數通過未定義)。 非常感謝! –

37

訪問控制器方法意味着從指令控制器/鏈接/範圍訪問父範圍的方法。

如果指令共享/繼承父範圍,那麼調用父範圍方法非常簡單。

當您想要從獨立指令作用域訪問父級作用域方法時,需要做更多的工作。

從獨立的指令範圍調用父範圍方法或查看父範圍變量(特別是選項#6),有幾個選項(可能超過以下列出)。

注意我在這些示例中使用了link function,但您也可以根據需要使用directive controller

選項#1。通過對象文本和指令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(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" 
    }] 

}); 

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

選項#2。通過對象文本,並從向鏈路/範圍

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" 
    }] 
}); 

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

選項#3。通過功能的參考和指導,從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" 
    }] 
}); 

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

第4個選項。通過功能的參考和從指令鏈路/範圍

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

}); 

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

選項#5:通過NG-模型和雙向綁定,您可以更新父作用域的變量。。所以,在某些情況下,您可能不需要調用父範圍函數。

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" 
    }] 
}); 

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

選項#6:通過$watch$watchCollection 它是雙向的所有上面的例子爲items結合,如果項目在父範圍修改,指導項目也將反映這些變化。

如果你想觀看從父範圍的其他屬性或對象,你可以做,使用$watch$watchCollection下面

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> 

腳本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" 
    }] 
}); 

你可以隨時參考呃AngularJs文檔詳細解釋有關指令。

+0

這在'link'方法中創建了一個包裝函數。當我將範圍函數從指令中傳遞給另一個指令時,這只是一個問題。原來的父控制器功能仍然被調用,但'arguments'是未定義的,直到我像你所建議的那樣包裝它。 – chovy

+0

我不得不從服務器觸發一次提取,所以鏈接函數示例對我來說工作得非常好,因爲我甚至不需要來回傳遞數據,只需調用ajax函數即可。你應得到3票贊成這樣一個準確和妥善的答案。 –

1

這裏是另一種模式(在Angular 1.5中工作)。

angular.module('module', []) 
 

 
    .controller('MyController', function() { 
 

 
     var self = this; 
 
     self.msg = 0; 
 
     // implement directive event listener interface 
 
     this.onEvent = function(arg) { 
 
      self.msg++; 
 
     }; 
 
    }) 
 

 
    .directive('myDirective', function() { 
 
     return { 
 
      scope: { 
 
      data: '=', 
 
      handler: '=' 
 
      }, 
 
      template: '<button ng-click="handler.onEvent(data)">Emit event</button>' 
 
     } 
 
    });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script> 
 

 

 
<div ng-app="module" ng-controller="MyController as ctrl"> 
 
<my-directive handler="ctrl" data="'...received'"></my-directive> 
 
    {{ctrl.msg}} 
 
</div>

相關問題