Access angular controller from directive using require - angularjs

In a directive i want to require a controller but i get the error that the controller can't be found. I am sure it is a small thing or maybe it is not possible the way i want to do it.
angular.module('myApp', []);
angular.module('myApp').controller('GreetingController', ['$scope', function($scope) {
$scope.greeting = 'Hola!';
//some function here returning data
}]);
angular.module('myApp').directive('yoloswag', function() {
return {
require: ['^?ngModel', '^GreetingController'],
restrict: 'A',
scope: {
},
link: function(scope, element, attrs, controllers) {
var modelCtrl = controllers[0],
greetingsCtrl = controllers[1];
console.log(controllers)
}
};
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="GreetingController">
{{ greeting }}
<div yoloswag>test</div>
</div>
</div>
What am i doing wrong?
Thank you so much!

Your code does not having and dependency with your main module, that's why you are getting that error.
Your code should be the following
angular.module('myApp', [])
.controller('GreetingController', ['$scope', function($scope) {
$scope.greeting = 'Hola!';
//some function here returning data
}])
.directive('yoloswag', function() {
return {
require: ['^?ngModel', '^GreetingController'],
restrict: 'A',
scope: {
},
link: function(scope, element, attrs, controllers) {
var modelCtrl = controllers[0],
greetingsCtrl = controllers[1];
console.log(controllers)
}
};
});
or set a variable for main module then you can add controller and directive with the main module like,
var MainModule = angular.module('myApp', []);
MainModule.controller('GreetingController', ['$scope', function($scope) {
$scope.greeting = 'Hola!';
//some function here returning data
}]);
MainModule.directive('yoloswag', function() {
return {
require: ['^?ngModel', '^GreetingController'],
restrict: 'A',
scope: {
},
link: function(scope, element, attrs, controllers) {
var modelCtrl = controllers[0],
greetingsCtrl = controllers[1];
console.log(controllers)
}
};
});

You can use controller property of directive :
make sure don't update property in link function.
return {
restrict: 'A',
scope: {
},
controller : 'GreetingController',
link: function(scope, element, attrs) {
var modelCtrl = controllers[0],
greetingsCtrl = controllers[1];
console.log(controllers)
}
};

Related

Send data from controller to directive

I want to send that to my directive but I want that data to stay updated if the data in the controller changes.
// Controller
angular
.module('app')
.controller('IndexController', IndexController)
IndexController.$inject = [];
function IndexController() {
var vm = this;
vm.name = 'John';
newName = function() {
vm.name = 'Brian';
}
newName();
}
// Directive
angular
.module('app')
.directive('userName', userName);
userName.$inject = ['$document'];
function userName($document) {
var directive = {
restrict: 'EA',
template: '<div id="user"></div>',
replace: true,
scope: {
name: '='
},
link: function(scope, elem, attrs) {
console.log(scope.data);
}
}
return directive;
}
this is how I use the directive. the problem is that it always returns the first name and not the new name after the change in the controller.
<div ng-controller="indexController">
<user-name name="indexController.name">
</div>
thank you.
Try this, you just have to inject $scope into your Indexcontroller
angular
.module('app', [])
.controller('IndexController', function($scope) {
var vm = this;
vm.name = 'John';
vm.newName = function() {
vm.name = 'Brian';
console.log(vm.name);
}
//vm.newName();
})
.directive('userName', ['$document', function() {
var directive = {
restrict: 'E',
template: '<div id="user"></div>',
replace: true,
scope: {
name: '='
},
link: function(scope, elem, attrs) {
console.log(scope.name);
}
}
return directive;
}])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="IndexController as vm">
<user-name name="vm.name"></user-name>
<button ng-click="vm.newName()">Click</button>
</div>
Without using as in controller, you cannot use controller.prop inside the scope.
Inside the controlleryou need to call the method using its $scope or this.
Check the below code.
angular
.module('app', [])
.controller('IndexController', function($scope) {
$scope.name = 'John';
$scope.newName = function() {
$scope.name = 'Brian';
}
$scope.newName();
})
.directive('userName', ['$document', function() {
var directive = {
restrict: 'E',
template: '<div id="user"></div>',
replace: true,
scope: {
name: '='
},
link: function(scope, elem, attrs) {
console.log(scope.name);
}
}
return directive;
}])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="IndexController">
<user-name name="name"></user-name>
</div>

How can I pass variables from an isolated scope directive to a child?

I have two isolated scope directives. Ideally I like both to work independently and not require any custom templates. The first directive is going to be page scroll watcher, when it hits a certain point I want it to trigger an update in the other directive. Is it possible for a child directive to watch a variable in the parent directive?
I've created a simple plunkr to illustrate the issue, http://plnkr.co/edit/wwfBzmemyrj1r1R54riM?p=preview
/*
<div ng-outer>Outer directive {{myvar}}
<div ng-inner="myvar">Inner directive</div>
</div>
*/
app.directive('ngOuter', [ '$timeout', function ($timeout) {
var directive = {
restrict: 'A'
,scope:{}
}
directive.link = function (scope, element, attrs) {
$timeout(function(){
scope.myvar = "test 001"
},1000)
}
return directive;
}]);
app.directive('ngInner', [ function () {
var directive = {
restrict: 'A'
,scope:{ data: '=ngInner', myvar: '=myvar' }
}
directive.link = function (scope, element, attrs) {
scope.$watch('data', function(newVal, oldVal){
if(newVal)
element.text("new inner val", newVal);
});
scope.$watch('myvar', function(newVal, oldVal){
if(newVal)
element.text("new myvar", newVal);
});
}
return directive;
}]);
Solved this issue by using
angular.element(element.parent()).isolateScope();
The child directive can access the scope of the parent directive and watch variables etc.
http://plnkr.co/edit/RAO6q81ZE4tClMDMiLFb?p=preview
First approach of passing variable from parent directive to the child is by using an 'attr' in child scope with '#' and initialize it in parent controller as following:
var app = angular.module('app', []);
app.directive('ngOuter', [ '$timeout', function ($timeout) {
return{
restrict: 'E',
scope:{},
template: '<ng-inner attr="{{myvar}}">Inner directive {{myvar}}</ng-inner>',
controller: ['$scope', function($scope) {
$scope.myvar = "test 001";
}],
link: function (scope, elem, attrs) {
}
}
}]);
app.directive('ngInner', [ function () {
return{
restrict: 'E',
scope:{'attr' : "#"},
link: function (scope, element, attrs) {
console.log(scope.attr);
}
}
}]);
html:
<ng-outer></ng-outer>
2nd approach is utilizing a function in a parent controller which returns the "myvar" value and call that function in child directive:
app.directive('ngOuter', [ '$timeout', function ($timeout) {
return{
restrict: 'E',
scope:{},
template: '<ng-inner attr="{{myvar}}">Inner directive {{myvar}}</ng-inner>',
controller: ['$scope', function($scope) {
$scope.myvar = "test 001";
this.getMyvar = function() {
return $scope.myvar;
};
}],
link: function (scope, elem, attrs) {
}
}
}]);
app.directive('ngInner', [ function () {
return{
restrict: 'E',
require: '^ngOuter',
scope:{'attr' : "#"},
link: function (scope, element, attrs, parentDirCtrl) {
console.log(parentDirCtrl.getMyvar());
}
}
}]);
3rd Approach: you can inject a service to both inner and outer directives.Then use the service.
var app = angular.module('app', []);
app.service('myService', [
function() {
var service = {
myvar: 'test001',
setMyVar: function(value) {
this.myvar = value;
},
getMyVar: function() {
return this.myvar;
}
}
return service;
}
]);
app.directive('ngOuter', ['$timeout', 'myService',
function($timeout, myService) {
var directive = {
restrict: 'A',
scope: {}
}
directive.link = function(scope, element, attrs) {
$timeout(function() {
scope.myvar = myService.getMyVar();
}, 1000)
}
return directive;
}
]);
app.directive('ngInner', ['myService',
function(myService) {
var directive = {
restrict: 'A',
scope: {}
}
directive.link = function(scope, element, attrs) {
var variable = myService.getMyVar();
console.log("myvar", variable);
}
return directive;
}
]);

Using Controllers In Directives In AngularJS

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});
};
...

How would I go about adding directives to an existing directive programmatically whilst ensuring that they have access to the same model?

I have attempted the following which seems to generate the correct html, but doesn't perform the data binding i.e. the new directives that I add do not have access to the $modelValue in ngController:
.controller('MyController', ['$scope', function($scope) {
$scope.aModel = {"key": "value"}
function init() {
$scope.aModel = {"key": "value"}
}
}])
.directive('innerDirective', [function (){
return {
restrict: 'AE',
require: 'ngModel',
template: '<ul></ul>',
link: function(scope, elem, attr, ngModelController) {
console.log(ngModelController.$modelValue) // Doesnt work
}
}
}])
.directive('outerDirective', ["$log", "$compile", function($log, $compile) {
return {
restrict: 'AE',
require: 'ngModel',
scope: {},
template: '<div></div>',
link: function(scope, elem, attrs, ngModelController) {
ngModelController.$render = function() {
var aModel = ngModelController.$modelValue; // Works
var modelName = attrs['ngModel']; // aModel
var html = '<inner-directive ng-model="' + modelName + '"></inner-directive>';
var angularElement = angular.element(html);
elem.append(angularElement);
$compile(angularElement)(scope);
}
}
};
}])
HTML looks like:
<div ng-controller="MyController">
<outer-directive ng-model="aModel"></outer-directive>
</div>
This is based on reccomendations from another question: Adding ngModel to input with a directive
What is it that I'm doing wrong here?
Cheers.
There is two issue:
1- outerDirective is using isolated scope. so aModel value is undefinded in the directive scope.
2-You can't access ngModelController.$modelValue in link function immediately. Look at outerDirective that you access it in the render function.
So you can change your directives as follows:
var app = angular.module('app', []);
app.controller('MyController', ['$scope', function ($scope) {
$scope.aModel = { "key": "value" }
function init() {
$scope.aModel = { "key": "value" }
}
}]);
app.directive('innerDirective', ['$timeout', function ($timeout) {
return {
restrict: 'AE',
require: 'ngModel',
template: '<ul></ul>',
link: function (scope, elem, attr, ngModelController) {
$timeout(function () {
console.log(ngModelController.$modelValue) // It works
});
}
}
}]);
app.directive('outerDirective', ["$log", "$compile", function ($log, $compile) {
return {
restrict: 'AE',
require: 'ngModel',
template: '<div></div>',
link: function (scope, elem, attrs, ngModelController) {
ngModelController.$render = function () {
var aModel = ngModelController.$modelValue; // Works
var modelName = attrs['ngModel']; // aModel
var html = '<inner-directive ng-model="' + modelName + '"></inner-directive>';
var angularElement = angular.element(html);
elem.append(angularElement);
$compile(angularElement)(scope);
}
}
};
}]);

AngularJs passing a value to a directive

I'm trying to pass a value to a directive. The directive is used to integrate a jquery plugin Knob
JSFIDDLE: http://jsfiddle.net/Tropicalista/TH87t/93/
I have this code:
var App = angular.module('Knob', []);
App.controller('myCtrl', function($scope) {
$scope.number = 24;
})
App.directive('knob', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
$(element).knob().val(scope.number);
console.log(attrs)
}
};
});
The problem is that knob() doesn't return the element. Use this instead:
link: function(scope, element, attrs) {
$(element).val(scope.number).knob();
}
Here's your fiddle: http://jsfiddle.net/TH87t/94/
I used your question as reference for a fully bi-direction binding. For a working version with angular 1.2.1 see http://jsfiddle.net/sander_van_dam/m5YJu/
App.directive('knob', function() {
return {
require: 'ngModel',
scope: { model: '=ngModel' },
controller: function($scope, $element, $timeout) {
var el = $($element);
$scope.$watch('model', function(v) {
var el = $($element);
el.val(v).trigger('change');
});
},
link: function($scope, $element, $attrs,$ngModel) {
var el = $($element);
el.val($scope.value).knob(
{
'change' : function (v) {
$scope.$apply(function () {
$ngModel.$setViewValue(v);
});
}
}
);
}
}
});

Resources