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>
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 have read this post. However, in that example he calls the controller function after listening on a click event of the element.
How can I achieve calling a controller function when clicking children of the directive element?
<div ng-controller="MyCtrl">
<abc method1="outerMethod('c')" method2="outerMethod2('g')"></abc>
</div>
Directive:
var myApp = angular.module('myApp',[]);
myApp.directive('abc', function() {
return {
restrict: "EA",
replace: true,
template: "<div><p ng-click='clickedP()'>p</p><div ng-click='clickedDiv()'>div</div></div>",
controller: function($scope) {
// how can I call outerMethod if clickedP is executed???
// how can I call outerMethod2 if clickedDiv is executed???
},
controllerAs: "vm",
link: function(scope, element, attrs, vm) {
}
}
});
function MyCtrl($scope) {
$scope.outerMethod = function( a ) {
alert( "you did it" );
}
$scope.outerMethod2 = function( a ) {
alert( "you did it again" );
}
}
Fiddle: http://jsfiddle.net/j93ba7a2/5/
The scope can be used directly without passing attributes. Also, using "controllerAs" on a directive with the same value as the parent controller is a bad idea, since it will overwrite it.
Solution:
var myApp = angular.module('myApp', []);
myApp.directive('abc', function () {
return {
restrict: "EA",
replace: true,
template: "<div><p ng-click='clickedP()'>p</p><div ng-click='clickedDiv()'>div</div></div>",
controller: function ($scope) {
// how can I call outerMethod if clickedP is executed???
$scope.clickedP = function () {
$scope.outerMethod(); // you just call it!
}
// how can I call outerMethod2 if clickedDiv is executed???
$scope.clickedDiv = function () {
$scope.outerMethod2(); //Same way!
}
},
controllerAs: "vm",
link: function (scope, element, attrs, vm) {
/* It would have been better to handle clickedP and
clickedDiv here instead of in the controller, but I'm
trying to avoid confusion by changing as little as
possible of your code. */
}
}
});
function MyCtrl($scope) {
$scope.outerMethod = function (a) {
alert("you did it");
}
$scope.outerMethod2 = function (a) {
alert("you did it again");
}
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();
}
};
});
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});
};
...
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;
});
}