Function inside directive not being triggered - angularjs

Why my function toggleCategory function is not being triggered?
Directive
app.directive('asideFilter', function() {
return {
restrict: 'E',
scope: {
toggleCategory: '=&onToggleCategory'
},
transclude: true,
templateUrl: 'assets/directives/asideFilter/asideFilter.html',
link: function(scope, element, attrs){
}
};
});;
Directive template
<div ng-click="toggleCategory({id: 'teste'})">TEST</div>
Parent scope
$scope.onToggleCategory = function () {
console.log('onToggleCategory');
}
Parent Caller
<aside-filter toggle-category="onToggleCategory({id: 'test '})" categories="categories" />

You can call the parent controller function like this also
app.directive('asideFilter', function() {
return {
restrict: 'E',
scope: {
toggleCategory: '&',
},
transclude: true,
templateUrl: 'assets/directives/asideFilter/asideFilter.html',
link: function(scope, element, attrs){
scope.toggleCategoryClick = function (value) {
scope.toggleCategory(value);
}
}
};
});
Directive template
<div ng-click="toggleCategoryClick({id: 'teste'})">TEST</div>
Directive Element
<aside-filter toggle-category="onToggleCategory({id: 'test '})" categories="categories" />

Related

Parent directive controller undefined when passing to child directive

I asked general question here in this post. I've got answer with working example; however when I try to use this example to modify existing code, I get error.
See my code below and in this Plunker page.
Html
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.3/angular.min.js"></script>
<div ng-app="myApp">
<tmp-menu ng-disabled="true">
<tmp-menu-link></tmp-menu-link>
<tmp-menu-link></tmp-menu-link>
</tmp-menu>
</div>
JavaScript(AngularJS):
angular.module('myApp', [])
.controller('MyDirectiveController', MyDirectiveController)
.directive('tmpMenu', function() {
return {
restrict: 'AE',
replace:true,
transclude:true,
scope:{
disabled: '=?ngDisabled'
},
controller: 'MyDirectiveController',
template: '<div>myDirective Disabled: {{ disabled }}<ng-transclude></ng-transclude></div>',
link: function(scope, element, attrs) {
}
};
})
.directive('tmpMenuLink', function() {
return {
restrict: 'AE',
replace:true,
transclude:true,
scope:{
},
required:'^^tmpMenu',
template: '<div>childDirective disabled: {{ disabled }}</div>',
link: function(scope, element, attrs, MyDirectiveCtrl) {
console.log(MyDirectiveCtrl);
scope.disabled = MyDirectiveCtrl.isDisabled();
}
};
})
function MyDirectiveController($scope) {
this.isDisabled = function() {
return $scope.disabled;
};
}
Inside directive tmpMenuLink, MyDirectiveCtrl is undefined.
Why is that?
You have a typo in your code:
required:'^^tmpMenu',
change it to
require:'^^tmpMenu',
Check this plunkr
https://plnkr.co/edit/DgyW3OFgr1GyAR8fuATi?p=preview
Because it's require not required.
angular.module('myApp', [])
.controller('MyDirectiveController', MyDirectiveController)
.directive('tmpMenu', function() {
return {
restrict: 'AE',
replace: true,
transclude: true,
scope: {
disabled: '=?ngDisabled'
},
controller: 'MyDirectiveController',
template: '<div>myDirective Disabled: {{ disabled }}<ng-transclude></ng-transclude></div>',
link: function(scope, element, attrs) {}
};
})
.directive('tmpMenuLink', function() {
return {
restrict: 'AE',
replace: true,
transclude: true,
require: '^^tmpMenu',
template: '<div>childDirective disabled: {{ disabled }}</div>',
link: function(scope, element, attrs, MyDirectiveController) {
scope.disabled = MyDirectiveController.isDisabled();
}
};
})
function MyDirectiveController($scope) {
this.isDisabled = function() {
return $scope.disabled;
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.3/angular.min.js"></script>
<div ng-app="myApp">
<tmp-menu ng-disabled="true">
<tmp-menu-link></tmp-menu-link>
<tmp-menu-link></tmp-menu-link>
</tmp-menu>
</div>

Passing arguments to nested directives in Angular

I am trying to pass arguments from a parent directive to a child directive but the arguments seem to be undefined. Is there a right way to do this?
}).directive('flipper', function ($timeout) {
return {
template: '<div class="flipper" ng-class="{big: big}"><div class="inner animated " ng-style="rotatorTop()"><ul><li ng-repeat="app in apps">{{app.name}}</li></ul></div></div>',
restrict: 'E',
replace: false,
scope: {
apps: "=",
big: "=",
sizes: "="
},
link: function ($scope, $element, $attrs) {
// undefined!
alert($scope.apps);
...
}
};
}).directive('slogan', function ($window) {
return {
template: '<div class="message"><div class="message-big"><div class="black">{{lines[0]}}<flipper apps="apps" class="big" sizes="flipperSize"></flipper>' +
'</div><div class="black">{{lines[1]}}</div><div class="black">{{lines[2]}}</div></div></div>',
restrict: 'E',
replace: false,
transclude: true,
scope: {
apps: "=",
lines: "="
},
link: function ($scope, $element, $attrs) {
...
}
};
});
Yes there is. As your code is quite incomplete, I've made this simple directive to demonstrate how you can pass values from the controller to a parent directive and a child directive.
myApp.directive('cdParent', function() {
return {
restrict: "AE",
template: "<div cd-child option=\"option\" text=\"text\">",
scope: {
option: "="
},
link: function(scope, elem, attrs) {
console.log("inside parent directive: " + scope.option); // will log the color for the controller
scope.text = "Hello nested directives";
}
}
});
myApp.directive('cdChild', function() {
return {
restrict: "AE",
template: "<pre style=\"color: {{option}}\">{{text}} ({{option}})</pre>",
scope: {
option: "=",
text: "="
},
link: function(scope, elem, attrs) {
console.log("inside child directive: " + scope.option);
}
}
});
also, the link function doesn't do dependency injection as a controller does, so it's arguments should be scope, element, attrs not $scope, $element, $attrs, argument order makes a difference here

AngularJs : Variable from directive to controller

How can pass the variable itemSelect inside my directive to my controller?
mDirective.directive('directive', function() {
return {
restrict: 'A',
scope: {
options: "="
},
templateUrl: '',
link: function(scope, element, attrs) {
.........
$(element).find('.typeY').on('change', function() {
var itemSelect = $(element).find('.typeY').val();
});
} ,
};
});
Something like
mDirective.directive('directive', function() {
return {
restrict: 'A',
scope: {
options: "=",
selected:"=",
},
templateUrl: '',
link: function(scope, element, attrs) {
.........
$(element).find('.typeY').on('change', function() {
scope.$apply(function() {
scope.selected=value; // value from the element
});
});
} ,
};
});
At html level
<div directive options='expression' selected='expressionToTheScopeProperty'/>

How to add ngshow directive inside compile/link?

I want to add ngshow in the following custom element in a dynamic way... How to do that?
<toggler on-enable="main.enable()" on-disable="main.disable()">
<div style="width:100px;height:100px;background-color:#2fa">
<on>On state</on>
<off>Off state</off>
</div>
</toggler>
cf.directive('toggler', function () {
return {
restrict: 'AE',
scope: {
state: true,
onEnable: '&',
onDisable: '&'
},
compile: function (elem, attrs) {
var onElem = elem.find('on');
var offElem = elem.find('off');
// WANT TO DO THIS
// onElem.ngShow = 'state';
// offElem.ngShow = '!state';
}
};
});
You're doing it in the wrong way. Don't forget a rule of thumb in AngularJS: avoid DOM manipulation when it's not mandatory.
I guess that <on> and <off> are also custom directives, because you can't simply add tags without any defined behaviour. So, why don't put the ngShow attribute directly in this directives? Then, a directive's controller (see the documentation) will handle the communication between <on>/<off> and <toggler>:
myApp.directive('toggler', function () {
return {
restrict: 'AE',
scope: {
state: '=',
},
controller : [
'$scope',
function ($scope) {
this.isOn = function () {
return $scope.state;
};
},
],
};
});
myApp.directive('on', function () {
return {
restrict: 'AE',
require: '^toggler',
template: '<div ng-show="isOn()" ng-transclude />',
replace: true,
scope: true,
transclude: true,
link : function ($scope, element, attributes, togglerController) {
$scope.isOn = togglerController.isOn;
},
};
});
myApp.directive('off', function () {
return {
restrict: 'AE',
require: '^toggler',
template: '<div ng-hide="isOn()" ng-transclude />',
replace: true,
scope: true,
transclude: true,
link : function ($scope, element, attributes, togglerController) {
$scope.isOn = togglerController.isOn;
},
};
});
Fiddle
This way, you will be able to simply unit test your toggler, and extend his behaviour when needed.

AngularJS - Share ngModel with nested directives and transcluded directives

I am trying to create 3 directives:
.directive('dirOne', function () {
return {
restrict: 'E',
transclude: true,
replace: true,
controller: function ($scope, $element, $attrs) {
this.add = function (tag) {
tag && $scope.tags.push(tag);
};
},
template: '<div><p>Bucket from directive: {{tags}}</p><div ng-transclude></div></div>'
};
})
.directive('dirTwo', function () {
return {
restrict: 'A',
replace: true,
require: '^dirOne',
link: function (scope, element, attrs, dirOne) {
scope.add = function (tag) {
dirOne.add(tag);
};
},
template: '<div>'+
' <input type="text" ng-model="query" datum="sugestions" dir-three>' +
' <button ng-click="add(query)">add</button>' +
'</div>'
};
})
.directive('dirThree', ['$compile', function ($compile) {
var itemsTemplate = '<span class="sugestions"><span ng-repeat="item in datum|filter:query">{{item.name||item}}</span></span>';
return {
restrict: 'A',
transclude: true,
replace: true,
require: 'ngModel',
scope: {
datum: '=',
query: '=ngModel'
},
link: function (scope, element, attrs) {
var parent;
element.wrap('<span>');
parent = element.parent();
parent.append(angular.element($compile(itemsTemplate)(scope)));
}
};
}])
In the dirTwo and dirThree, I have an input <input type="text" ng-model="query" datum="sugestions" dir-three> with ngModel, this input needs to access and modify the content of ngModel, so that the scope is not isolated.
http://jsfiddle.net/joaoneto/hbABU/3/
Update
I Updated version, fix some mistakes I had committed, the content that was being transcluded in dirTwo, should not have the "ADD" function, and belongs to dirTree, hope it helps someone and apologize for peopl take to update this entry... see in http://jsfiddle.net/hbABU/4/

Resources