Passing parameter to isolated scope inside directive - angularjs

I am trying to pass two different parameter to isolated scope inside directive.When I log out values in console then for collapse I am getting true but for infoCard I am getting false value.My question is why I am getting false value for infoCard Thanks in advance.Here is my directive.
<display-info user="user" collapse="true" infoCard="true"></display-
info>
In my controller i am receiving the parameter,
angular.module('myApp').directive('displayInfo', function() {
return {
templateUrl: "displayInfo.html",
restrict: "EA",
scope: {
user: '=',
initialCollapse:'#collapse',
showInfo:'#infoCard'
},
controller: function($scope) {
$scope.collapse = ($scope.initialCollapse === 'true');
$scope.infoCard = ($scope.showInfo === 'true');
console.log("collapse---->",$scope.collapse);
console.log("displyInfo---->",$scope.infoCard);
}
}
});
Here is plunker link https://plnkr.co/edit/Gng7e4RRVvg8wPOnqQrk?p=preview

camel case convention have problem in directive
Try this.
<display-info user="user" collapse="true" test="true"></display-info>
angular.module('myApp').directive('displayInfo', function() {
return {
templateUrl: "displayInfo.html",
restrict: "EA",
scope: {
user: '=',
initialCollapse:'#collapse',
showInfo:'#test'
},
controller: function($scope) {
$scope.collapse = ($scope.initialCollapse === 'true');
$scope.infoCard = ($scope.showInfo === 'true');
console.log("collapse---->",$scope.collapse);
console.log("displyInfo---->",$scope.infoCard);
}
}
});

Related

Angular 1.x directive scope

I want to transform the scoped variable, like trimming the passed string.
but it shows always as it passed.
here is my sample code,
export function testDirective() {
return {
restrict: 'E',
template: `<a>{{vm.testText}}</a>`,
scope: {
testText: '#'
},
controller: TestController,
controllerAs: 'vm',
bindToController: true
}
}
export class TestController {
testText: string;
constructor(private $scope: angular.IScope) {
// when getting variable, I need to transform the value
$scope.$watch( () => this.testText, (newVal: string) => {
this.testText = newVal.trim() + ' Edited'; // this doesn't affact
});
}
}
why that code is not working?
To make it work I added additional variable(trimmedText), but I don't think this is right approach,
export function testDirective() {
return {
restrict: 'E',
template: `<a>{{vm.trimmedText}}</a>`,
scope: {
testText: '#'
},
controller: TestController,
controllerAs: 'vm',
bindToController: true
}
}
export class TestController {
testText: string;
trimmedText: string;
constructor(private $scope: angular.IScope) {
// when getting variable, I need to transform the value
$scope.$watch( () => this.testText, (newVal: string) => {
this.trimmedText = newVal.trim() + ' Edited'; // it works
});
}
}
Please advice me
#Expert wanna be, using the = sign in the isolated scope of the directive definition sets up two way data binding within the directive.
Check the below code snippet, here's the jsfiddle link.You can find more information about the different types of data binding in directives here
The HTML
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<custom-directive test-text="ctrl.text"></custom-directive>
</div>
</div>
The Angular code
angular
.module('demo', [])
.controller('DefaultController', DefaultController)
.controller('CustomDirectiveController', CustomDirectiveController)
.directive('customDirective', customDirective);
function DefaultController() {
var vm = this;
vm.text = 'Hello, ';
}
function customDirective() {
var directive = {
restrict: 'E',
template: `{{vm.testText}}`,
scope: {
testText: '='
},
controller: CustomDirectiveController,
controllerAs: 'vm',
bindToController: true
};
return directive;
}
function CustomDirectiveController() {
var vm = this;
// transforming/updating the value here
vm.testText = vm.testText + 'World!';
}
$scope.$watch( () => this.testText, // <-- use this.textText here
'#' is not right binding, if you want to modify it - use '='.
But using additional variable is actually correct approach.
Another good way for simple transformation is using filter.

Directive function parameter is undefined

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!'
}

accessing controller from a seperate directive causing unexpected erros

I am following the joe eames tutorials on pluralsight. It seems to be fairly straightforward. I am setting up one directive inside of another, and setting up * require: on a child controller*
Here is the code that I have from the demo. I am using angular 1.5 I haven't changed the $scope to controllerAs as I am focused on figuring out communication between directive controllers.
(function() {
'use strict';
angular
.module('app', [])
.controller('mainCtrl', function($scope) {
})
.directive('swTabstrip', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
controller: function($scope) {
$scope.panes = [];
$scope.select = function(pane) {
pane.selected = true;
$scope.panes.forEach(function(curPane) {
if(curPane !== pane) {
curPane.selected = false;
}
})
}
this.addPane = function(pane) {
$scope.panes.push(pane);
if($scope.panes.length ===1) {
pane.selected = true;
}
}
},
templateUrl: 'swTabstrip.html'
}
})
.directive('swPane', function() {
return {
restrict: 'E',
transclude: true,
scope: {
title: '#'
},
require: '^swTabstrip',
link: function(scope, el, attrs, tabstripCtrl) {
tabstripCtrl.addPane(scope);
},
templateUrl: 'swPane.html'
}
})
})();
The tutorial calls for me to set up directive swPane to require 'swTabstrip'. However, I am getting an error in the console
3angular.js:13156 Error: [$compile:ctreq]
Controller 'swTabstrip', required by directive 'swPane', can't be found!
You have to actually create your tabstripCtrl that your directive uses and at the same time then you can pass it in:
(function () {
'use strict';
angular
.module('app', [])
.controller('mainCtrl', function ($scope) {})
.controller('tabstripCtrl', function($scope) {
$scope.panes = [];
$scope.select = function (pane) {
pane.selected = true;
$scope.panes.forEach(function (curPane) {
if (curPane !== pane) {
curPane.selected = false;
}
})
}
this.addPane = function (pane) {
$scope.panes.push(pane);
if ($scope.panes.length === 1) {
pane.selected = true;
}
}
})
.directive('swTabstrip', function () {
return {
restrict : 'E',
transclude : true,
scope : {},
controller : 'tabstripCtrl' ,
templateUrl : 'swTabstrip.html'
}
})
.directive('swPane', function () {
return {
restrict : 'E',
transclude : true,
scope : {
title : '#'
},
require : '^tabstripCtrl',
link : function (scope, el, attrs, tabstripCtrl) {
tabstripCtrl.addPane(scope);
},
templateUrl : 'swPane.html'
}
})
})();
If you are trying to share data between your directives, look into services.

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

Resources