Access require controller in a directive controller - angularjs

app.directive('mainCtrl', function () {
return {
controller: function () {
this.funcA = function(){}
}
};
});
app.directive('addProduct', function () {
return {
restrict: 'E',
require: '^mainCtrl',
link: function (scope, lElement, attrs, mainCtrl) {
mainCtrl.funcA()
}
};
});
I don't want to use the link method but the controller method.
Is there a way to get the mainCtrl in the controller method of the directive addProduct.
something like:
app.directive('addProduct', function () {
return {
restrict: 'E',
require: '^mainCtrl',
controller: function (scope, mainCtrl) {
mainCtrl.funcA()
}
};
});

You'd still need to use the link function because the controllers are injected there. What you could, however, is request your directive's own controller and then set the other required controller as its property:
app.directive('addProduct', function () {
return {
restrict: 'E',
require: ['addProduct','^mainCtrl'],
controller: function ($scope) {
// this.mainCtrl is still not set here
// this.mainCtrl.funcA(); // this will cause an error
// but typically it is invoked in response to some event or function call
$scope.doFuncA = function(){
this.mainCtrl.funcA();
}
},
link: function(scope, element, attrs, ctrls){
var me = ctrls[0], mainCtrl = ctrls[1];
me.mainCtrl = mainCtrl;
}
};
});

Since AngularJS 1.5, you can use the $onInit lifecycle hook of the controller. As written in the documentation of require, when defining require as an object and setting bindToController to true, the required controllers are added to the controller as properties after the controller has been constructed, but before the $onInit method is run. So the code would look like this:
app.directive('mainCtrl', function () {
return {
controller: function () {
this.funcA = function(){}
}
};
});
app.directive('addProduct', function () {
return {
restrict: 'E',
require: {
myParentController: '^mainCtrl'
},
bindToController: true,
controller: function ($scope) {
this.$onInit = function() {
this.myParentController.funcA();
};
}
};
});

Here is my solution:
app.directive('mainCtrl', function () {
return {
controllerAs: 'main',
controller: function () {
this.funcA = function(){}
}
};
});
app.directive('addProduct', function () {
return {
restrict: 'E',
require: '^mainCtrl',
controller: function ($scope) {
$scope.main.funcA();
}
};
});

Pass the controller to the scope on the link function then accessing the scope on controller. Like this:
app.directive('mainCtrl', function () {
return {
controller: function () {
this.funcA = function(){}
}
};
});
app.directive('addProduct', function () {
return {
restrict: 'E',
require: '^mainCtrl',
link: function (scope, lElement, attrs, mainCtrl) {
scope.ctrl=mainCtrl;
},controller:function($scope){
$scope.ctrl.funcA();
}
};
});

Related

How to share scope between parent and child directives

I am creating a directive where two other child directives use it is functionalities but I need a help to know how to make the scope shared between the parent and the child directive
Parent directive
MetronicApp.directive('atmSearchComponent', function () {
function AtmSearchComponentController(scope) {
// initialize scope
}
AtmSearchComponentController.prototype.search = function () {
scope.mainGridOptions.dataSource.page(1);
reset();
}
AtmSearchComponentController.prototype.clearSearch = function () {
scope.data.basicSearch = {};
scope.data.advancedSearch = {};
}
AtmSearchComponentController.prototype.keyPressSearch = function (keyEvent) {
if (keyEvent.which === 13) {
keyEvent.preventDefault()
scope.search();
}
};
return {
restrict: 'E',
controller: ['$scope', AtmSearchComponentController],
scope: {}
};
});
Child directive
MetronicApp.directive('atmsQuerySelector', function ($log, $parse, $timeout, $http, $uibModal) {
return {
restrict: "E",
replace: false,
scope: {},
require: ['^atmSearchComponent', 'ngModel'],
templateUrl: "/apps/framework/templates/atmsSelector.view",
link: function (scope, element, attrs, controllersArray) {
scope.search = controllersArray[0].search;
clearSearch = controllersArray[0].clearSearch;
scope.keyPressSearch = controllersArray[0].keyPressSearch;
},
}
});
but when I call the search method I get the following error
ReferenceError: scope is not defined
at n.AtmSearchComponentController.search (directives.js:8)

Best practice to share variables between methods within a directive

Let's say i have a simple directive with two methods. In terms of readability i want to have all shared variables on top of the link function.
what's the best way to do this?
angular.module('myApp', [])
.directive('myCustomer', function() {
return {
restrict: 'E',
templateUrl: 'my-customer.html'
link: link
};
function link(scope,element,attrs){
var myCustomer = { // same name as directive so it's clear it's a global object
myCompany: "stackoverflow",
myCar: "tesla"
};
function funcA(){
config.myCar = "ferrari";
}
function funkB(){
alert(config.myCar);
}
funcA();
funcB();
}
});
would that be good practice? I'm asking for more complicated cases like async initializing of "myCustomer" keys as well.
Just use the directive scope:
angular.module('myApp', []).directive('myCustomer', function() {
return {
restrict: 'E',
templateUrl: 'my-customer.html',
link: function(scope, element, attrs) {
scope.myCustomer = {
myCompany: "stackoverflow",
myCar: "tesla"
}
function funcA() {
scope.myCustomer.myCar = "ferrari";
}
function funcB() {
// should be 'ferrari'
alert(scope.myCustomer.myCar);
}
funcA();
funcB();
}
};
});
angular.module('myApp', [])
.constant('BASE_API_URL', 'http://api.example.com')
.service('customerService', function customerService ($http, BASE_API_URL) {
return {
getCustomer: getCustomer
};
function getCustomer() {
// Returns a promise
$http.get(BASE_API_URL + '/customer');
}
})
.controller('mycontroller', function ($scope, customerService) {
$scope.customer = null;
customerService.getCustomer().success(function (customer) {
$scope.customer = customer;
});
})
.directive('myCustomer', function() {
return {
restrict: 'E',
templateUrl: 'my-customer.html',
scope: {
customer: '=',
},
link: link
};
function link(scope, element, attrs) {
// $scope.customer is the customer object
function funcA() {
config.myCar = "ferrari";
}
function funkB() {
alert(config.myCar);
}
funcA();
funcB();
}
});
<my-customer ng-if="customer" customer="customer"></my-customer>

AngularJS directive with require and 2 controllers

Is it possible to have a parent directive and a child directive, both with their own controller?
Something like:
.controller('ParentController', function () {
var self = this;
self.action = function () {
console.log('parent action');
}
})
.controller('TestSomethingController', function () {
var self = this;
self.something = function () {
console.log('something');
}
})
.directive('parent', function () {
return {
restrict: 'A',
controller: 'ParentController',
link: function (scope, element, attrs, controller) {
controller.action();
}
}
})
.directive('test', function () {
return {
restrict: 'A',
require: 'parent',
controller: 'TestSomethingController',
link: function (scope, element, attrs, controller) {
controller.something();
}
};
});
I tried to do this one codepen like this:
http://codepen.io/r3plica/pen/bdygeP?editors=101
If I remove the require, it obviously works, but I would like to keep the require.
Does anyone know if that is possible?
You can require multiple directives. Have it require itself as well as parent. With this syntax, the last parameter of link will be an array of the controllers of the given directives.
.directive('test', function () {
return {
restrict: 'A',
require: ['parent', 'test'],
controller: 'TestSomethingController',
link: function (scope, element, attrs, controllers) {
controllers[0].action(); // parent
controllers[1].something(); // self
}
};
});
Here is a forked, working version of your CodePen.

function binding not working between 2 directives

I'm trying to bind a function to a directive. Here is my fiddle code:
var myApp = angular.module('myApp', []);
myApp.directive("myFoo", function () {
return {
restrict: "E",
scope: {
callback: '&'
},
template: '<span ng-click="callback()">MyFoo</span>'
};
});
myApp.directive("myBar", function () {
return {
restrict: "E",
template: '<div>MyBar > <my-foo test="cb"></my-foo></div>',
link: function (scope) {
scope.cb = function (x) {console.log('click');}
}
};
});
DEMO
I must be doing something stupid because the callback is not working when I click the my-foo element. Any suggestions why this example doesn't work ?
You need to pass it into the attribute you're using which is callback, also associate it directly with an '=':
var myApp = angular.module('myApp', []);
myApp.directive("myFoo", function () {
return {
restrict: "E",
scope: {
callback: '='
},
template: '<span ng-click="callback()">MyFoo</span>'
};
});
myApp.directive("myBar", function () {
return {
restrict: "E",
template: '<div>MyBar > <my-foo callback="cb"></my-foo></div>',
link: function (scope) {
scope.cb = function (x) {console.log('click');}
}
};
});
jsFiddle: http://jsfiddle.net/xohv1syq/
jsFiddle using &: http://jsfiddle.net/hzxcptzv/

Angular JS passing parameter to scope function from directive

Assume that I have a directive like this
<div my-directive callback='doSomething(myArg)'></div>
angular.module('directives').directive('myDirective', function() {
return {
restrict: 'A',
scope: {
callback: '&'
},
link: function(scope, element, attrs) {
element.bind('someEvent', function() {
scope.callback({myArg: 'bla'});
});
}
}
});
If I want to pass a parameter to my scope's function, I have to do scope.callback({myArg: 'bla'}). I wonder if there's a way pass the argument without having to specify its name?
Use can use shared service in this case and inject it to directive:
angular.module("yourAppName", []).factory("mySharedService", function($rootScope){
var mySharedService = {};
mySharedService.values = {};
mySharedService.setValues = function(params){
mySharedService.values = params;
$rootScope.$broadcast('dataPassed');
}
return mySharedService;
});
And after inject it to directive. For example:
app.directive('myDirective', ['mySharedService', function(mySharedService){
return {
restrict: 'C',
link: function (scope, element, attrs) {
mySharedService.setValues(//some value//);
}
}
}]);
Then, you can get necessary value in controller.
function MyCtrl($scope, mySharedService) {
$scope.$on('dataPassed', function () {
$scope.newItems = mySharedService.values;
});
}

Resources