how to call function after append html to the directive - javascript

viewBannerCtrl is the controller in that i'm using "customTable" directive
Here i'm not able to access "VBC.bannerAlert()" function from the directive
and i appended the code to directive but not able to access controller functions with append tag
.controller('viewBannerCtrl',function(){
vbc.bannerAlert = function(){
alert('success called in inside directive.....Hurry!!!!!!!!!!!!!!!!!!');
};
});
.directive('customTable', function customTable($compile) {
return {
restrict: 'EA',
templateUrl: 'app/admin/modules/common/views/custom_table.html',
scope: {
data: '=data',
dataLength: '=datalength',
filterDataArray: '=filterData',
imageData: '=imageData'
},
controller: customTableCtrl,
link:function(scope,element,attr){
var el = angular.element(document.getElementById('dyanamicActions'));
el.append('<button class="btn btn-danger btn-rounded btn-ef btn-ef-5 btn-ef-5b" ng-click="VBC.bannerAlert()"><i class="fa fa-trash"></i> <span>Deletess</span></button>');
$compile(el)(scope);
},
controllerAs: 'CTC',
bindToController: true
};
});
function customTableCtrl(MainService) {
var ctc = this;
};
}
<div custom-table data="VBC.getBannerlistData" datalength="VBC.totalItems"
table-headers="VBC.tableInit" image-data="'image'"
table-actions="VBC.editData" delete-model="VBC.openBannerDeleteModal">
</div>

You current directive has implemented using isolated scope like scope: { ... }. So directive don't have outer scope methods are available in it(didn't follow prototypal inheritance when scope are isolated).
You have to pass bannerAlert function expression to directive from its isolated scope using &. So that that function will get available inside directive scope.
For passing that function to directive you have to write attribute bannerAlert="bannerAlert()" on directive element. Like I've shown below.
Markup
<div custom-table data="VBC.getBannerlistData"
datalength="VBC.totalItems"
table-headers="VBC.tableInit"
image-data="'image'"
table-actions="VBC.editData"
delete-model="VBC.openBannerDeleteModal"
bannerAlert="bannerAlert()">
</div>
Code
scope: {
data: '=data',
dataLength: '=datalength',
filterDataArray: '=filterData',
imageData: '=imageData',
bannerAlert: '&bannerAlert' //<--added expression binding here
},

Related

Passing Function Arguments with Isolated and Share scopes with Angular Directives

I have 3 directive with isolate scope and share scope and I want pass a function beteween outermost a innermost directive. The outer and middle has isolate scopes and the middle with inner share the scope. Any suggest ?
Pass the functions of my controller as shown below .
<outer on-edit="helloWorld" ng-model="model" ng-repeat="items in items.objects" ></outer>
In my controller:
$scope.helloWorld = function(){
alert('Hello world');
}
My directive:
angular.module('myApp')
.directive('outer', function () {
return {
restrict: 'E',
replace: true,
scope: {
item: "=ngModel",
onEdit: '&'
},
template: '<div><middle on-edit='onEdit'></middle></div>',
controller : function($scope){
$scope.edit = function(){
$scope.onEdit()();
}
}
};
})
.directive('middle', function () {
return {
restrict: 'E',
replace: true,
scope: {
item : '=ngModel',
onEdit : '&'
},
templateUrl: '<div><inner on-edit='onEdit'></inner></div>'
};
})
.directive('inner', function () {
return {
restrict: 'E',
template: '<div><a ng-click='edit()'>Edit</a></div>'
};
})
And this not work, any ideas?
Thanks
This looks a bad design though, but in the middle directive's template you are using inner directive as follows:
<div><inner on-edit='onEdit'></inner></div>
If you look at it, inner directive has no scope, so the attribute on-edit doesn't make sense there.
If you want to use any method that is present in middle directive can be directly used in inner directive because of shared scope. Think of inner directive as a part of html written in some other html file which will be replaced at run time.
So anything you pass to middle directive is implicitly passed to inner.

isolate scope on a directive restricted to attributes

In the documentation for directives you can isolate scope with the following:
.directive('myDialog', function() {
return {
restrict: 'E',
transclude: true,
scope: {
'close': '&onClose'
},
templateUrl: 'my-dialog-close.html'
};
});
I'm trying to write a directive that is restricted to attributes. How do I get the same isolate functionality when restricting with 'A'?
.directive('doSomething', function() {
return {
restrict: 'A',
scope: {
'close': '&???'
},
link: function(scope, element, attrs) {
element.on('click', function() {
scope.close();
});
}
};
});
I would use the directive like so:
<button do-something="doSomething()" type="button">Do Something</button>
Isolated scope doesn't depends on the the restrict property. You need to mention those variable/ method in isolated scope which you are going to pass from the parent scope.
As in below isolate scope declaration you have used close as isolated scope variable which will accept method, that means you should pass that method instance in close attribute.
scope: {
close: '&' //it shouldn't be with quotes
},
Markup
<button do-something close="doSomething()" type="button">Do Something</button>
Edit
If you wanted to alias your attribute name, then it that alias would be there after the & like close: '&myAlias', by using alias you could avoid the execution of other directive (Ideally your directive shouldn't have name like that)
scope: {
close: '&myAlias' //it shouldn't be with quotes
},
Markup
<button do-something my-alias="doSomething()" type="button">Do Something</button>

Pass array in directive attributes

I want to pass array in the directive attribute. It doesn't work. I tried to pass an array in the attribute of a directive and nothing happened.
class Directive {
constructor () {
'ngInject';
let directive = {
restrict: 'E',
template: '<div class="btn-group">
<label class="btn btn-primary classButton"
ng-model="radioModel" uib-btn-radio="'First'"
config="{{config[0]}}">{{config[0]}}
</label>
</div>',
controller: Controller,
controllerAs: 'vm',
bindToController: true,
scope: {
config: '='
}
};
return directive;
}
}
class Controller {
constructor() {
'ngInject';
}
}
<directive config="First, Second"></directive>
How should I pass the array to the directive?
Maksim,
You need to pass a scope variable instead of a array constant here,
That is, declare a scope variable and assign this value to that variable like this,
$scope.myArray = ['Firs', 'Second'];
and now you can pass this scope variable to your directive.
<directive config="myArray"></directive>
It should work !!!

Directive accessing to parent controller function without $scope

So I have this directive that has its own scope but I want to access to a function inside its parent controller. I can do this if the parent controller exposes the function with a $scope.getElementsList(), although I'm trying to avoid the use of $scope and I have the function exposed with self.getElementsList() and the directive cannot reach it.
Directive:
angular.module('myApp').directive('accountBalance', function() {
return {
scope: {
elementId: '=elementid'
},
transclude: true,
restrict: 'E',
templateUrl: '../views_directives/account-balance.html',
controller: function($scope) {
$scope.removeElement = function(){
//this where I want to access the parent function
console.log($scope.$parent.getElementsList());
console.log("ALSO I WANT TO ACCESS THIS DIRECTIVE elementId WITHOUT USING $scope", $scope.elementId);
}
}
};
});
ParentController:
angular.module('myApp').controller('AppDesignCtrl', function ($scope) {
var self = this;
self.elementsList = [];
self.getElementsList = function(){
return self.elementsList;
}
});
I also want to know what is the best way to access, inside the directive controller, the data passed to the directive's $scope.
scope: {
elementId: '=elementid'
},
UPDATE
<div>
<i class="fa fa-arrows element-drag"></i>
<i class="fa fa-trash-o element-remove" ng-click="removeElement()"></i>
</div>
And what about calling functions from the directive template inside the controller of the directive? Do I need to expose them with something like $scope.removeElement()? How do I use this.removeElement() and be able to access it from the template?
Sorry about the long question. I'm trying to set the best practices to my new project since I've been away from angular for a year+.
Thanks in advance
(Going from bottom to top...)
To call functions in the controller without using the scope in Angular >= 1.2, use the controllerAs syntax:
<div ng-controller="AppDesignCtrl as appDesignCtrl">
...
<i class="fa fa-trash-o element-remove" ng-click="appDesignCtrl.removeElement()"></i>
</div>
And removeElement() must be a method of the controller:
angular.module('myApp').controller('AppDesignCtrl', function ($scope) {
...
this.removeElement = function() {
...
};
});
To access the scope data from the controller in Angular >= 1.3, use the new bindToController: true configuration (this is especially useful when combined with the new controllerAs syntax):
angular.module('myApp').directive('accountBalance', function() {
return {
...
scope: {
elementId: '=elementid'
},
controller: function() {
// now elementId is a member of the controller:
console.log(this.elementId);
}
};
});
Having said these, the answer to how you can call getElementsList from the directive would be:
angular.module('myApp').directive('accountBalance', function() {
return {
...
scope: {
elementId: '=elementid',
getElementList: '&'
},
controller: function() {
...
// invoking the expression that was passed to us
var theElements = this.getElementList();
}
};
});
The correct expression should be passed as:
<div ng-controller="AppDesignCtrl as appDesignCtrl">
<account-balance element-id="xxx"
get-elements-list="appDesignCtrl.getElementsList()"></account-balance>
</div>
It is generally not recommended, because directives are meant to be self-contained. It isn't critical if you don't plan to reuse the directive. And wise usage of isolate scope can solve this.
angular.module('myApp').directive('accountBalance', function() {
return {
scope: {
outerScope: '#'
elementId: '='
},
transclude: true,
restrict: 'E',
templateUrl: '../views_directives/account-balance.html',
controller: function($scope) {
console.log("we can use anything from other controller", $scope.outerScope.elementsList)
$scope.elementId = "and share data with any other scope";
}
};
});
Controller is defined as ng-controller="AppDesignCtrl as appDesign", and directive usage is
<account-balance element-id="sharedParentScopeVar" outer-scope="appDesign">
So there won't be any problem if the directive should be moved to other controller.
I guess 'best practice' may be to set up a service that embraces the data and is used by both app controller and directive, so directive controller operates on data items and not DOM elements.
And what about calling functions from the directive template inside
the controller of the directive? Do I need to expose them with
something like $scope.removeElement()?
You surely don't. If there's a need to use functions from outside, you're doing something wrong. Send a message to respective element to run the function if it is DOM-related. Or put the function into the service if it is data-related.

Call directive method from transcluded content

I'm trying to access a method in a directive from translcuded content. My HTML looks like:
<typeahead class="typeahead" model="customers" filtered-model="customersfiltered" ng-model="selectedcustomer">
<ul>
<li ng-click="select(customer)" ng-repeat="customer in customersfiltered | filter:filter | limitTo:10">
{{customer.firstname}} {{customer.lastname}}
</li>
</ul>
</typeahead>
And my AngularJS directive:
directive('typeahead', function ($filter) {
return {
restrict: 'E',
transclude: true,
replace: true,
scope: {
model: '=',
filteredModel: '='
},
template: '<div class="typeahead"><form><input type="text" autocomplete="off" class="col-lg-12" ng-model="filter"></form><div ng-transclude></div></div>', //
controller: function($scope){
$scope.filterArray = function(filterString){
$scope.filteredModel= $filter('filter')($scope.model, filterString);
}
$scope.clear = function(){
$scope.filteredModel = [];
}
$scope.$watch('filter', function(){
if($scope.filter) {
$scope.filterArray($scope.filter);
} else {
$scope.clear();
}
});
},
link: function ($scope, $element, $attributes) {
$scope.select = function(customer){
console.log("dwadad");
}
}
}
})
The problem here is that I cannot access the select() function inside the link function() from the ng-click event of the transcluded content (list-element).
Have somebody an idea how to solve this?
Here is a Plunker of the current code: Plunker
I think you can't do that. From the Angular docs:
(...) The advantage of transclusion is that the linking function receives a
transclusion function which is pre-bound to the correct scope. In a
typical setup the widget creates an isolate scope, but the
transclusion is not a child, but a sibling of the isolate scope. This
makes it possible for the widget to have private state, and the
transclusion to be bound to the parent (pre-isolate) scope.
In other words, the scope of the transcluded DOM is a sibling, not a child, of the directive's scope. So you can't access it from there, and I think that's correct. Otherwise you wouldn't be able to bind the transcluded content to the right scope.
You can use $$nextSibling:
link: function($scope) {
$scope.$$nextSibling.select = function(customer) {
alert('used isolated scope using $$nextSibling');
}
},

Categories