Directive function parameter is undefined - angularjs

Directive Template URL:
<div class="filter-input" ng-click="changeVisualization('trocaparaeste')">
Directive:
app.directive('asideFilter', function() {
return {
restrict: 'E',
scope: {
categories: "=",
change: "&onChange",
changeVisualization: '&onChangeVisualization'
},
templateUrl: 'assets/directives/asideFilter/asideFilter.html',
controller: function($scope){
}
};
});;
Directive usage:
<aside-filter change-visualization="onChangeVisualization()"/>
Controller that im trying to get the parameter data:
$scope.onChangeVisualization = function(option) {
console.log('option', option);
}
SOLUTION:
Directive Template URL:
<aside-filter on-change-visualization="onChangeVisualization(option)"/>
Directive:
app.directive('asideFilter', function() {
return {
restrict: 'E',
scope: {
categories: "=",
change: "&onChange",
changeVisualization: '&onChangeVisualization'
},
templateUrl: 'assets/directives/asideFilter/asideFilter.html',
link: function(scope){
// pass 'option' variable so it can be used in the callback
scope.changeVisualization({ option: "worked!" });
}
};
});;
Directive usage:
<aside-filter change-visualization="onChangeVisualization(option)"/>

You have your names switched:
scope: {
// prefixed with 'on'
// so usage: <my-directive on-change-visualization="someFunc(option)"/>
changeVisualization: '&onChangeVisualization'
},
// example:
link: function($scope) {
scope.changeVisualization = scope.changeVisualization || angular.noop;
// pass 'option' variable so it can be used in the callback
scope.changeVisualization({ option: "worked!" });
}
And change your html to:
<!-- with the prefixed 'on-' -->
<aside-filter on-change-visualization="onChangeVisualization(option)" />
In your controller:
$scope.onChangeVisualization = function(option) {
console.log('option', option); // logs: 'option worked!'
}

Related

How to use require (webpack) with dynamic string, angularjs

export function triMenuItemDirective() {
var directive = {
restrict: 'E',
require: '^triMenu',
scope: {
item: '='
},
// replace: true,
template: require('./menu-item-dropdown.tmpl.html'),
controller: triMenuItemController,
controllerAs: 'triMenuItem',
bindToController: true
};
return directive;
}
I need to load different html depending on item.
With the old way you could do:
template: '<div ng-include="::triMenuItem.item.template"></div>',
And in Controller
triMenuItem.item.template = 'app/components/menu/menu-item-' + triMenuItem.item.type + '.tmpl.html';
How do I achive this with webpack?
Something like
template: require('./menu-item-{{triMenuItem.item.type}}.tmpl.html'),
I think that to do this, you have at least three different approaches:
1- Use $templateCache and then pass a string variable to ng-include
.directive('myDirective', ['$templateCache', function ($templateCache) {
return {
scope: {
item: '='
},
template: '<div ng-include="content"></div>',
link: function (scope) {
$templateCache.put('a.tpl.html', require('./a.html'));
$templateCache.put('b.tpl.html', require('./b.html'));
scope.content = (scope.item === 'a') ? 'a.tpl.html' : 'b.tpl.html';
}
}
}]);
2- Use ng-bind-html.
app.directive('myDirective', ['$sce', function ($sce) {
return {
scope: {
item: '='
},
template: '<div ng-bind-html="content"></div>',
link: function (scope) {
if(scope.item === 'a')
scope.content = $sce.trustAsHtml(require('./a.html'));
}
}
}]);
3- Use ng-if. Maybe the less dynamic solution of the three, but is pretty simple if your requirements let you do it.
app.directive('myDirective', function () {
return {
scope: {
bool: '='
},
template: `
<div>
<div ng-if="item === 'a'">${require('./a.html')}</div>
<div ng-if="item === 'b'">${require('./b.html')}</div>
</div>
`
}
});

Directive attribute unit test

I have the below directive
return {
restrict: 'E',
scope: {
data: '=',
getLink: '='
},
templateUrl: 'abc.html',
controller: 'abcController'
};
Inside abcController i have this below function that i want to test.
$scope.printData = function()
{
$scope.getLink().then(
function(url) {
$window.open(url);
$window.focus();
},
function(response) {
$log.error('Error opening ' + response);
}
);
};
i am trying to test the printData function, this is the below test i am trying to write.
it('should print the visualizer report', inject(function(mockObjects) {
scope.mockData = mockObjects.mockData;
element = angular.element("<my-directive data='mockData' get-link='test'/>");
compile(element)(scope);
scope.$digest();
var childScope = scope.$$childTail;
childScope.getPdfLink = getPdfLink();
childScope.printData();
}));
I am getting the following error:
“$scope.getLink is not a function
Anything wrong that i am doing ?
Pass the function with '&' as describe on docs:
return {
restrict: 'E',
scope: {
data: '=',
getLink: '&'
},
templateUrl: 'abc.html',
controller: 'abcController'
};
<div your-directive get-link="yourDelegatedMethod()"></div>

AngularJS : Change parent scope value from custom directive

For some reason I can't make this work based on the other examples I've seen here on SO.
Here's my directive:
(function () {
angular.module('materialDesign')
.directive('aSwitch', directive);
function directive() {
return {
templateUrl: 'elements/material/switch/switch.html',
transclude: false, // I've tried true here
restrict: 'E',
scope: {
enabled: '=',
toggleState: '=',
},
link: function(scope, element) {
element.on('click touchstart', function() {
scope.toggleState = !scope.toggleState;
});
}
};
}
})();
And the controller scope value that I want to change when toggling the switch/checkbox:
$scope.hideInactive = true;
The html:
<a-switch toggle-state="hideInactive"></a-switch>
and further down in my html page, I have this:
<div ng-show="!hideInactive">
<!-- stuff -->
</div>
EDIT:
This version is "working now", but as soon as I click my switch/checkbox a second time, the element.on fires twice, this flipping my scope value back to what it was.....basically, it's not letting me "un-check" my toggle.
angular.module('material')
.directive('aSwitch', [
'$timeout', function($timeout) {
return {
templateUrl: 'elements/material/switch/switch.html',
transclude: false,
restrict: 'E',
scope: {
enabled: '=',
toggleState: '=',
},
link: function (scope, element) {
element.on('click touchstart', function () {
$timeout(function () {
scope.toggleState.state = !scope.toggleState.state;
scope.$apply();
});
});
}
};
}
]);
EDIT and FINAL SOLUTION:
Here's the updated directive link property that fixed everything. I'd like to add that Oleg Yudovich's answer was also used (passing an object as the property instead of a true/false by itself)
link: function (scope, element) {
element.on('click touchstart', function (event) {
if (event.srcElement && event.srcElement.id && event.srcElement.id === "switch") {
event.stopPropagation();
$timeout(function() {
scope.toggleState.state = !scope.toggleState.state;
});
}
});
}
Try to pass object instead of primitive variable like this:
$scope.hideInactive = {
state: false;
}
html without changes:
<a-switch toggle-state="hideInactive"></a-switch>
in your directive:
scope.toggleState.state = !scope.toggleState.state;
Reed this awesome article: https://github.com/angular/angular.js/wiki/Understanding-Scopes
You need to run digest cycle after changes in scope, because changing scope binding from event will not run angular digest cycle, you need to run it manually by doing scope.$apply()
Directive
(function () {
angular.module('materialDesign')
.directive('aSwitch', directive);
function directive($timeout) {
return {
templateUrl: 'elements/material/switch/switch.html',
transclude: false, // I've tried true here
restrict: 'E',
scope: {
enabled: '=',
toggleState: '=',
},
link: function(scope, element) {
element.on('click touchstart', function() {
$timeout(function(){
scope.toggleState = !scope.toggleState;
});
});
}
};
}
})();
Try below code:
angular.module('material').directive('aSwitch', ['$timeout', function($timeout) {
return {
templateUrl: 'elements/material/switch/switch.html',
transclude: false,
restrict: 'E',
scope: {
enabled: '=',
toggleState: '=',
},
link: function(scope, element) {
element.on('click touchstart', function() {
$timeout(function() {
scope.toggleState.state = !scope.toggleState.state;
scope.$apply();
});
});
}
};
}]);

Accessing properties of directive's isolated scope from controller

I'm trying to access the properties of my directive's isolated scope. Im slightly new to angularJS so I'm unsure if this is actually possible or not.
Below is my code:
angular.module('myModule').directive('myDirective', function() {
return {
restrict: 'EA',
require: 'ngModel',
scope: {
type: '=',
fName: '=',
lName: '=',
},
templateUrl: '...'
};
}
);
angular.module(myModule).controller('myCtrl', [
'$scope',
function($scope) {
$scope.openLink= function() {
if ($scope.type === 'member') { //Here is where I want to access the type from the scope of the directive!
$window.open('http://wwww.google.com, 'myWindow', 'menubar=0, width=600, height=680, scrollbars=yes, resizable=yes, top=180, left=350');
}
};
}
]);
I would appreciate if someone could assist.
Many thanks
Yes you can do that.you have to add 'type' property to your controller scope and you already passing 'type' to directive as value(refrence) and then set your 'type ' in directive either in link function or directive controller.
angular.module(myModule).controller('myCtrl', [
'$scope',
function($scope) {
$scope.type="";
$scope.openLink= function() {
if ($scope.type === 'member') { //Here is where I want to access the type from the scope of the directive!
$window.open('http://wwww.google.com, 'myWindow', 'menubar=0, width=600, height=680, scrollbars=yes, resizable=yes, top=180, left=350');
}
};
}
angular.module('myModule').directive('myDirective', function() {
return {
restrict: 'EA',
require: 'ngModel',
scope: {
type: '=',
fName: '=',
lName: '=',
},
templateUrl: '...',
controller:function($scope){
$scope.type="member";
}
};
}
);

Scope Isolation & nested directives

Dealing with '&' and isolated scope.
Is it possible to pass a value up through a parent directive? I want to pass id from the textdisp directive to the controller.
HTML:
<body ng-controller="MainCtrl">
<builder removequest="deleteQuestion(id)"></builder>
</body>
ANGULAR:
app.controller('MainCtrl', function($scope) {
$scope.deleteQuestion = function(id) {
alert(id);
}
});
app.directive('builder', function() {
return {
restrict: 'E',
scope: {
removequest: '&'
},
template: '<div>Hello how are you? <textdisp removequest=removequest(id)></textdisp></div>'
}
});
app.directive('textdisp', function() {
return {
restrict: 'E',
scope: {
removequest: '&'
},
template: '<div ng-click="remove()">Click here!</div>',
link: function (scope, el) {
scope.remove = function(id) {
console.log('workin')
scope.removequest(1);
}
}
}
});
I believe there are 2 things going on with your code:
When you're placing removequest="removequest(id)" that is calling the function, and not just referring to the function.
I believe that the &attr binding isn't returning the function that you're expecting.
Try this Plunker; it essentially uses { removequest: '=' } for bi-directional binding, and removequest="deleteQuestion" / removequest="removequest" for function references rather than calling the function.
It's a little confusing, but you can use object parameter when you need to pass values into your function invoked via & binding. Take a look at this code it will make everything clear:
app.controller('MainCtrl', function($scope) {
$scope.deleteQuestion = function(id) {
alert(id);
}
});
app.directive('builder', function() {
return {
restrict: 'E',
scope: {
removequest: '&'
},
template: '<div>Hello how are you? <textdisp removequest="removequest({id: id})"></textdisp></div>'
}
});
app.directive('textdisp', function() {
return {
restrict: 'E',
scope: {
removequest: '&'
},
template: '<div ng-click="remove()">Click here!</div>',
link: function(scope, el) {
scope.remove = function(id) {
scope.removequest({id: 34534}); // <-- 1.
}
}
}
});
Demo: http://plnkr.co/edit/3OEy39UQlS4EyOu5cq4y?p=preview
Note how you specify scope.removequest({id: 34534}) parameter to be passed into <textdisp removequest="removequest({id: id})">.

Resources