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.
Related
The following code works as expected and the scope.checked value is reflected in the UI normally
.directive('comparisonSlider',
function () {
return{
restrict: 'E',
templateUrl: '/app/reports/comparison-slider.html',
controller: function ($scope, $rootScope) {
$scope.checked = false;
$rootScope.$on('compare',
function () {
$scope.checked = true;
},
true);
}
}
}
)
but the following code also works, but the changes to scope aren't reflected in the UI.
.directive('comparisonSlider',
function () {
return{
restrict: 'E',
templateUrl: '/app/reports/comparison-slider.html',
controller: function ($scope, $rootScope) {
$scope.checked = false;
$rootScope.$on('compare',
function () {
$scope.checked = !$scope.checked;
},
true);
}
}
}
)
Any ideas?
This works as expected, not sure why the other one doesn't
.directive('comparisonSlider',
function () {
return{
restrict: 'E',
templateUrl: '/app/reports/comparison-slider.html',
controllerAs: 'sliderCtrl',
controller: function ($scope, $rootScope) {
var self = this;
self.checked = false;
$rootScope.$on('compare',
function () {
self.checked = !self.checked;
},
true);
}
}
}
)
Try changing:
self.checked = !self.checked;
to:
self.checked = false;
I am trying to lazy load ($ocLazyLoad) some non-angular libraries (jQuery + css files) through the route (using angular ui.router).
In this code snippet I am trying to load the iCheck library, and only use it in my InputsCtrl
here's my config:
.state('dashboard.inputs', {
url: "/elements/inputs",
templateUrl: templateProvider.getTemplate('inputs'),
controller: 'InputsCtrl',
controllerAs: 'inputs',
resolve: {
loadPlugin: function ($ocLazyLoad) {
return $ocLazyLoad.load([
{
files: [
'bower_components/iCheck/skins/polaris/polaris.css',
'bower_components/iCheck/icheck.min.js'
]
}
]);
}
}
})
and it is causing the following error:
here's my empty controller:
(function () {
'use strict';
angular
.module('mega-app')
.controller('InputsCtrl', ctrl);
function ctrl() {
var vm = this;
}
})();
and here's the directive I am using:
(function () {
'use strict';
angular
.module('mega-app')
.directive('icheck', icheck);
function icheck($timeout) {
return {
restrict: 'A',
require: 'ngModel',
link: function($scope, element, $attrs, ngModel) {
return $timeout(function() {
var value;
value = $attrs['value'];
$scope.$watch($attrs['ngModel'], function(newValue){
$(element).iCheck('update');
})
return $(element).iCheck({
checkboxClass: 'icheckbox_square-green',
radioClass: 'iradio_square-green'
}).on('ifChanged', function(event) {
if ($(element).attr('type') === 'checkbox' && $attrs['ngModel']) {
$scope.$apply(function() {
return ngModel.$setViewValue(event.target.checked);
});
}
if ($(element).attr('type') === 'radio' && $attrs['ngModel']) {
return $scope.$apply(function() {
return ngModel.$setViewValue(value);
});
}
});
});
}
};
}
})();
I want to accomplish scroll-able content by clicking on Bootstrap module. Its working fine. This is following code of my directive:
'use strict';
angular.module('cbookApp')
.directive('scrollTo', scrollTo);
scrollTo.$inject = ['$anchorScroll'];
function scrollTo($anchorScroll) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.bind('click', function (event) {
event.stopPropagation();
var location = attrs.scrollTo;
if (scope.vm.isEdit || typeof scope.vm.isEdit =="undefined" ) {
$anchorScroll(location);
} else {
$anchorScroll(location+'1');
}
});
}
};
}
But only problem is i am not sure how to apply active class to current affix li. This DEMO way i found to apply class active to current li and remove from other. It was working without Controller as but once i added controller as it stopped working and give some error of scope.
var app = angular.module('app', ['directives']);
app.controller('firstController',[function(){
var vm = this;
vm.model = { value: 'dsf'};
}]);
angular.module('directives', []).directive('toggleClass', function () {
var directiveDefinitionObject = {
restrict: 'A',
template: '<span ng-click="localFunction()" ng-class="selected" ng-transclude></span>',
replace: true,
bindToController: true,
scope: {
model: '='
},
transclude: true,
link: function (scope, element, attrs) {
scope.localFunction = function () {
scope.model.value = scope.$id;
};
scope.$watch('model.value', function () {
if (scope.model.value === scope.$id) {
scope.selected = "active";
} else {
scope.selected = '';
}
});
}
};
return directiveDefinitionObject;
});
Can you please add this in your directive.
element.parent().parent().children().each(function() {
$(this).find('a').removeClass('active');
});
element.addClass('active');
http://jsfiddle.net/hngzxmda/1/
I suggest using controllerAs in your directive too
angular.module('directives', []).directive('toggleClass', function () {
var directiveDefinitionObject = {
restrict: 'A',
template: '<span ng-click="vmd.localFunction()" ng-class="selected" ng-transclude></span>',
replace: true,
bindToController: {
model: '=',
$id: '='
},
scope: {},
transclude: true,
controller: function() {
var _this = this;
this.localFunction = function () {
_this.model.value = _this.$id;
};
},
controllerAs: 'vmd'
};
return directiveDefinitionObject;
});
my directive:
angular.module('matrixarMatrice', []).directive('mtxMatriceForm', function () {
return {
restrict: 'E',
templateUrl: 'views/matrice/matrice.html',
scope: {
matrix: '=',
isclicked: '=',
selectedprice: '&'
},
link: function (scope, element, attrs) {
...
scope.selected = function (prices) {
scope.selected.id = prices.id;
scope.selectedprice(prices);
};
}
};
});
my controller:
$scope.selectedprice = function (prices) {
console.log(prices);
};
my html:
<mtx-matrice-form matrix="matrix " isclicked="isclicked" selectedprice="selectedprice(prices)"></mtx-matrice-form>
In my directive when i select item i call my controller.
I want to exploit my object prices, but the problem i have at the moment is i have an undefined in my controller.
Does anyone know the correct way of doing this?
This is the one option that you can use to include controller inside a directive! There are other options as well. Hope it helps!
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'Lorem';
});
app.directive('directives', function() {
return {
restrict: 'E',
controller: function($scope, $element){
$scope.name = $scope.name + "impsum";
},
link: function(scope, el, attr) {
scope.name = scope.name + "Ipsum";
}
}
})
i have found this solution:
in my directive:
...
scope.selected = function (prices) {
scope.selected.id = prices.id;
scope.selectedprice({prices: prices});
};
...
I cannot get the parent function call from the isolated scope..The purpose of this code is to create a widget directive which can be used multiple times on the same page... I tried some other option, but doesn't work either. It works using the parent scope.
What am I missing here.
var app = angular.module("winApp", []);
app.controller("winCtrl", function($scope, dataFactory) {
$scope.getData = function() {
dataFactory.get('accounts.json').then(
function(data) {
$scope.items = data;
});
};
});
app.directive("windowSmall", function() {
return {
restrict : 'EA',
replace : 'true',
scope : {
type : '&'
},
transclude: 'true',
templateUrl : 'windowtemplate.html',
link : function(scope, element, attrs) {
element.bind("load", function(){
console.log(attrs.type);
if (angular.equals(attrs.type, 'getData()')) {
scope.active = 'accounts';
console.log(attrs.type);
// scope.getData();
scope.$apply(function() {
scope.$eval(attrs.type);
});
}
});
}
};
});
app.factory('dataFactory', function($http) {
return {
get : function(url) {
return $http.get(url).then(function(resp) {
return resp.data;
});
}
};
});
HTML:
<div ng-app="winApp" ng-controller="winCtrl">
<window-small type = "getData()"> </window-small>
<br> <br>
<!--
<window-small type = "bulletin"> </window-small> -->
You can also use $rootScope for a full proof solution. Due to the fact that an application can have multiple parents but only one $rootScope.
https://docs.angularjs.org/api/ng/service/$rootScope
Replace your link function with :
link : function(scope, element, attrs) {
element.bind("load", function(){
console.log(attrs.type);
if (angular.equals(attrs.type, 'getData()')) {
scope.active = 'accounts';
console.log(attrs.type);
scope.type();
}
});
}
Fiddle : http://jsfiddle.net/X7Fjm/3/