I have a directive which, when called, passes in a controller
and an array
.
In the controller I pass in, there is an object I want to loop over.
my html looks like this:
<div class="row">
<div class="col-md-6">
<div class="jumbotron" ng-controller="protocolCtrl as pctrl">
<button type="button" id="protocol" class="btn btn-primary btn-lg" ng-click="pctrl.getUpdatedList()"
data-toggle="modal" data-target="#modal">Modify Current Protocols</button>
<!--IN THIS MODAL YOU CAN ADD/CHANGE/DELETE DATA-->
<modal-directive list="pctrl" headers="['ID', 'Protocol']"></modal-directive>
</div>
</div>
<div class="col-md-6">
<div class="jumbotron" ng-controller="categoryCtrl as cctrl">
<button type="button" id="category" class="btn btn-primary btn-lg" ng-click="cctrl.getUpdatedList()"
data-toggle="modal" data-target="#modal">Modify Current Categories</button>
<!--IN THIS MODAL YOU CAN ADD/CHANGE/DELETE DATA-->
<modal-directive list="cctrl" headers="['ID', 'Category']"></modal-directive>
</div>
</div>
</div>
My problem is that no matter what I do, it's always the FIRST directive in the html that showes up, no matter what button I press.
My directive
looks like this:
.directive('modalDirective', function(){
return {
restrict: 'E',
templateUrl: '/directives/modal-directive.html',
scope: {
list: '=',
headers: '='
},
link: function(scope, element, attrs){
console.log(attrs.list + ' | ' + attrs.headers);
}
};
});
My modal-directive.html
looks like this:
<table class="table table-striped">
<thead>
<tr>
<th ng-repeat="h in headers"> {{ h }} </th>
</tr>
</thead>
<tbody>
<!-- Loop through -->
<tr ng-repeat="l in list.list">
<!--Access the actual values inside each of the objects in the array-->
<td ng-repeat="data in l"> {{ data }} </td>
<td>
<button type="button" class="btn btn-primary btn-sm"
data-toggle="modal">Edit</button>
</td>
<td>
<button type="button" class="btn btn-danger btn-sm" ng-click="list.removeData(l)"
data-dismiss="modal">Remove</button>
</td>
</tr>
</tbody>
</table>
Am I using isolated scopes wrong, or is it something else I need to change in order to make this work?
Update
Here is a fiddle, that demonstrates the problem.
No matter which button i click, it displays the same text in the modal body.
You don't really need two controllers and two directives to achieve this. Below is an example of how you can do this. Notice I moved the controller to the row instead of having separate controllers for each column. The controller myCtrl
now handles the click functions which are bound to the buttons using the ng-click
attribute. This then determines the which text should be placed where by calling there respective functions. IE proto()
and cat()
Now this may not be ideal for your situation depending on how you plan on the architecture of your application. But it works for your current problem in terms of what you have provided.
HTML
<body ng-app="TM">
<div class="row" ng-controller="myCtrl as modalControl">
<div class="col-md-6">
<div class="jumbotron" >
<button
ng-click='proto()'
type="button" id="protocol"
class="btn btn-primary btn-lg"
data-toggle="modal"
data-target="#modal">Modify Current Protocols
</button>
</div>
</div>
<div class="col-md-6">
<div class="jumbotron">
<button
ng-click='cat()'
type="button"
id="category"
class="btn btn-primary btn-lg"
data-toggle="modal"
data-target="#modal">Modify Current Categories
</button>
</div>
</div>
<!--IN THIS MODAL YOU CAN ADD/CHANGE/DELETE DATA-->
<modal-directive ctrl="modalControl"></modal-directive>
</div>
</body>
Angular JS
angular.module('TM', [])
.controller('myCtrl', function($scope){
$scope.text ='default';
$scope.proto = function() {
this.text = 'Now looking at the protocol part'
}
$scope.cat = function() {
this.text = 'Now looking at the category part'
}
})
.directive('modalDirective', function(){
return {
restrict: 'E',
scope: true,
template: ['<div id="modal" class="modal fade" role="dialog">',
'<div class="modal-dialog">',
'<div class="modal-content">',
'<div class="modal-header">',
'<h4 class="modal-title">Modal Header</h4>',
'</div>',
'<div class="modal-body">',
'<p> {{ text }} </p>',
'</div>',
'<div class="modal-footer">',
'<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>',
'</div>',
'</div>',
'</div>',
'</div>'].join('')
}
});
Demo:
https://jsfiddle.net/DTcHh/10193/
UPDATE:
Okay, I took another look. And even though the above example works. I noticed that I have a few extra things that I didn't necessarily need. For example myCtrl as modalControl
doesn't need the as modalControl
part. Below is an updated example. I did this one with some different simplified markup.
HTML:
<body ng-app="TestApp">
<div ng-controller="myCtrl">
<button ng-click="one()">One</button>
<button ng-click="two()">Two</button>
<test-directive></test-directive>
</div>
</body>
Angular Example (without Isolated Scope)
angular.module('TestApp', [])
.controller('myCtrl', function($scope){
$scope.text ='default';
$scope.one = function() {
this.text = 'this is one'
}
$scope.two = function() {
this.text = 'this is two'
}
})
.directive('testDirective', function(){
return {
template: "<div id='test'>{{text}}</div>"
}
});
Demo 2:
https://jsfiddle.net/krishollenbeck/v8tczaea/12/
Note this..
restrict: 'E',
scope: true
Was also not needed because I am not using Isolated scope in this example. More info here https://docs.angularjs.org/guide/directive
Please check this JSFiddle.
The reason is that data-target
value points to the DOM element id of the modal. If you fixed this id in the directive template, clicking on the button will always initiate the modal with id modal
. So you need to make the modalId
as another parameter of the directive.
By the way, you can pass a controller to a directive. Just like this JSFiddle:
angular.module('Joy', [])
.controller('MyCtrl', ['$scope', function ($scope) {
this.value = 'Joy';
}])
.directive('passMeContrller', [function () {
return {
restrict: 'A',
scope: {
ctrl: '=',
},
template: '<div>Value: {{ctrl.value}}</div>'
};
}]);
The HTML:
<div ng-app="Joy" ng-controller="MyCtrl as c">
<div pass-me-contrller ctrl="c"></div>
<hr>
<div ng-bind="c.value"></div>
</div>
Because the controller itself is just a JavaScript object.
Just a reminder: you are using protocolCtrl as pctrl
, so you need to specify like this.list=...
.
If you want to pass in a function to the isolated scope, use &
.
However, I suggest not to pass in the whole controller
to a directive. A controller is designed to:
- Set up the initial state of the $scope object.
- Add behavior to the $scope object.
Controllers are not supposed to be reused. Usually there are many properties on the $scope
, while some of them passed to the directive will not be used by it.