How to add a particular function from service to directive in AngularJS - angularjs

This is a function I have added in localcacheService.
I want to add this function in directive.
LocalCacheServiceClear.prototype.isAvailable = function() {
this.cache.clear();
}
My directive is this:
(function() {
var MainApp = angular.module('MainApp');
MainApp.directive('Logout', function () {
return {
'restrict': 'E',
'templateUrl': 'directives/panels/Logout.html',
'controller': ["$scope","LocalCacheService", function($scope,LocalCacheService) {
console.log("Logout Controller called....");
$scope.Logout = function() {
window.sessionStorage.clear();
console.log('Log out');
}
}]
};
});
}());
How to add this function to this directive?

via Angular Service:
MainAppUserConvMod.service('LocalCacheServiceClear', LocalCacheServiceClear);
and then inject into your directive:
MainAppUserConvMod.directive('Logout', function (LocalCacheServiceClear) {
and use it
LocalCacheServiceClear.isAvailable()

Related

Call angularjs directive function from controller

I've got a directive that needs to do something every now and then, let's say it has to count something.
If I use the basic syntax with $scope to bind the count function, it works just fine. but when we switch to the controller as syntax it doesn't bind the function.
Here is a working plunker: https://plnkr.co/edit/C2wVaeOm63SLnXBG?open=lib%2Fscript.js&deferRun=1&preview
JS
angular
.module('plunker', [])
.controller('MainCtrl', function ($scope) {
var vm = this;
vm.name = 'Plunker';
setInterval(function () {
$scope.count();
}, 1000);
setInterval(function () {
$scope.count2();
}, 1000);
setInterval(function () {
$scope.count3();
}, 1000);
})
.directive('test', function () {
return {
scope: {
count: '=',
},
controller: function ($scope) {
$scope.i = 0;
$scope.count = function () {
$scope.i++;
console.log($scope.i);
};
},
};
})
//with bindToController
.directive('test2', function () {
return {
scope: {
count: '=',
},
bindToController: true,
controller: function ($scope) {
var vm = this;
vm.i = 0;
vm.count = function () {
vm.i++;
console.log(vm.i);
};
},
};
})
//with bindToController - the new way
.directive('test3', function () {
return {
scope: true,
bindToController: {
count: '=',
},
controller: function ($scope) {
var vm = this;
vm.i = 0;
vm.count = function () {
vm.i++;
console.log(vm.i);
};
},
};
});
HTML
<body ng-app="plunker" ng-cloak>
<div ng-controller="MainCtrl as vm">
<h1>Hello {{vm.name}}</h1>
<test count="count"></test>
<test2 count="count2"></test>
<test3 count="count3"></test>
</div>
</body>
If you are using bindToController syntax, then you should declare your directive count function in directive link function, because binding is happening after directive controller initialisation.
Your modified example here:
//with bindToController
.directive('test2', function () {
return {
scope: {
count: '=',
},
bindToController: true,
controller: function ($scope) {
var vm = this;
vm.i = 0;
},
link:function($scope,$element,$attr,ctrl){
ctrl.count = function () {
ctrl.i++;
console.log('test2',ctrl.i);
};
}
};
})
Or you can check my modified plunker here:
https://plnkr.co/edit/TKTtObbDTcFFC9SS?open=lib%2Fscript.js&deferRun=1
angular
.module('plunker', [])
.controller('MainCtrl', function ($scope, $interval) {
var vm = this;
vm.name = 'Plunker';
̶s̶e̶t̶I̶n̶t̶e̶r̶v̶a̶l̶(̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶(̶)̶ ̶{̶
$interval(function () {
$scope.count();
}, 1000);
Use the $interval service.
AngularJS modifies the normal JavaScript flow by providing its own event processing loop. This splits the JavaScript into classical and AngularJS execution context. Only operations which are applied in the AngularJS execution context will benefit from AngularJS data-binding, exception handling, property watching, etc.
For more information, see
AngularJS $interval Service API Reference

angularjs 1.7.2 - How to call a directive function from a controller?

How do you call a directive's function from within a controller?
I have seen a number of answers to this question, with the solution similar to the following:
https://lennilobel.wordpress.com/tag/calling-directive-from-controller/
I have implemented it as follows:
Directive
angular.module('myApp').directive('myDirective', ['$log',
function ($log) {
function link(scope, element, attributes) {
//function that a controller can call
scope.myFunc = function () {
//Do Something
};
//if the user has provided an accessor, attach the function
if (scope.accessor) {
scope.accessor.myFunc = scope.myFunc;
}
}
return {
link: link,
restrict: 'E',
templateUrl: 'app/myTemplate.html',
scope: {
accessor: '=',
}
}
}
Controller
angular.module('myApp').controller('myCtrl', ['$log', '$q',
function ($log, $q) {
var vm = this;
// empty object that the directive will attach myFunc to
vm.accessor = {};
$q
.all([
//Service Call
])
.then(function (results) {
//manipulate the results of the service call using the
//directives function
vm.callDirective();
},
function (err) {
$log.debug('$q.all err:', err);
});
vm.callDirective = function () {
if (vm.accessor.myFunc) {
vm.accessor.myFunc();
} else {
$log.error('umm, I don\'t have a function to call');
}
};
}
HTML Template
<div ng-controller="myCtrl">
<myDirective accessor="vm.accessor"></myDirective>
</div>
When I run the code, the directive indicates that accessor is undefined. As a result, accessor, in the controller, doesn't have myFunc defined.
How do I get myFunc to execute?
I am using angular 1.7.2
The controller is compiled (an instance created with the resulting scope) before the directive.
In this scenario, it compiles faster than the directive can set the accessor function.
A quick workaround for this is to set a delay before checking if there is an accessor present using $timeout service.
The key is having a Promise object passed to $q.all. This will cause a small delay and allowing for the directive to be compiled.
For real, you'll be having promises that do some network call passed to $q.all instead of doing this workaround with the $timeout service.
Here is how this will go:
index.html
<div ng-controller="myCtrl as vm">
<my-directive accessor="vm.accessor"></my-directive>
</div>
script.js
const myApp = angular.module('myApp', []);
myApp.directive('myDirective', ['$log', myDirective]);
myApp.controller('myCtrl', ['$scope', '$timeout', '$log', '$q', myCtrl]);
function myCtrl($scope, $timeout, $log, $q) {
const vm = $scope.vm;
// empty object that the directive will attach myFunc to
vm.accessor = {};
vm.callDirective = () => {
if (vm.accessor.myFunc) {
vm.accessor.myFunc();
} else {
$log.error("umm, I don't have a function to call");
}
};
const handleSuccess = results => {
//manipulate the results of the service call using the
//directives function
vm.callDirective();
};
const handleError = err => {
$log.debug('$q.all err:', err);
};
$q.all([
//Service Call
$timeout()
])
.then(handleSuccess)
.catch(handleError);
}
function myDirective($log) {
//function that a controller can call
const myFunc = function() {
//Do Something
$log.info('Calling assessor myFunc');
};
const link = function(scope) {
//if the user has provided an accessor, attach the function
if (scope.accessor) {
scope.accessor.myFunc = myFunc;
}
};
return {
link: link,
restrict: 'E',
templateUrl: 'mydirective.html',
scope: {
accessor: '='
}
};
}

Error: [$controller:ctrlreg] Angular controller not registered

I tried many ways but i am not sure what i am missing I am getting controller name is not registered error in console.
I tried to even change name of controller but still no luck
Please suggest
AngularController.js
(function () {
'use strict';
angular
.module('mymod')
.controller('controller', controller);
controller.$inject = ['$location'];
(function ($) {
$.fn.menumaker = function (options) {
var cssmenu = $(this), settings = $.extend({
format: "dropdown",
sticky: false
}, options);
return this.each(function () {
$(this).find(".button").on('click', function () {
$(this).toggleClass('menu-opened');
var mainmenu = $(this).next('ul');
if (mainmenu.hasClass('open')) {
mainmenu.slideToggle().removeClass('open');
}
else {
mainmenu.slideToggle().addClass('open');
if (settings.format === "dropdown") {
mainmenu.find('ul').show();
}
}
});
cssmenu.find('li ul').parent().addClass('has-sub');
multiTg = function () {
cssmenu.find(".has-sub").prepend('<span class="submenu-button"></span>');
cssmenu.find('.submenu-button').on('click', function () {
$(this).toggleClass('submenu-opened');
if ($(this).siblings('ul').hasClass('open')) {
$(this).siblings('ul').removeClass('open').slideToggle();
}
else {
$(this).siblings('ul').addClass('open').slideToggle();
}
});
};
if (settings.format === 'multitoggle') multiTg();
else cssmenu.addClass('dropdown');
if (settings.sticky === true) cssmenu.css('position', 'fixed');
resizeFix = function () {
var mediasize = 1000;
if ($(window).width() > mediasize) {
cssmenu.find('ul').show();
}
if ($(window).width() <= mediasize) {
cssmenu.find('ul').hide().removeClass('open');
}
};
resizeFix();
return $(window).on('resize', resizeFix);
});
};
})(jQuery);
(function ($) {
$(document).ready(function () {
$("#cssmenu").menumaker({
format: "multitoggle"
});
});
})(jQuery);
})();
Directive.js
This is directive created to call on basepage
(function () {
'use strict';
angular.module('mymod')
.directive('myDirective', function () {
return {
restrict: 'E', //E = element, A = attribute, C = class, M = comment
scope: true,
//templateUrl: 'Views/Directives/Header/mytemplate.html',
templateUrl: '../Views/Directives/MainHeader/mytemplate.html',
//template: '<h1>Hello Directive: {{vm.title}}</h1>',
controller: 'controller',
controllerAs: 'vm'
}
});
})();
Below image shown is error message information
Update your code by having dependency array along with module initialization. Update your code to:
(function () {
'use strict';
angular
.module('mymod', [])
.controller('controller', controller);
controller.$inject = ['$scope', '$location'];
function controller($scope, $location) {
//Write controller code here
}
Then update your directive code to:
(function () {
'use strict';
angular.module('mymod')
.directive('myDirective', function () {
return {
restrict: 'E', //E = element, A = attribute, C = class, M = comment
scope: true,
//templateUrl: 'Views/Directives/Header/mytemplate.html',
templateUrl: '../Views/Directives/MainHeader/mytemplate.html',
//template: '<h1>Hello Directive: {{vm.title}}</h1>',
controller: controller,
controllerAs: 'vm'
}
});
})();
And if you want to use jquery in angularjs app make sure you inject it (script tag on index.html) before angularjs lib.
Demo Example

Using jasmine to test angular directive that uses a controller

I am trying to write a jasmine test that will test if an angular directive I've written is working.
Here is my spec file:
describe('blurb directive', function () {
var scope, httpMock, element, controller;
beforeEach(module('mdotTamcCouncil'));
beforeEach(module('mdotTamcCouncil.core'));
beforeEach(module('blurb'));
beforeEach(inject(function (_$httpBackend_, $rootScope, $compile) {
element = angular.element('<mcgi-blurb text-key="mainPageIntro"></mcgi-blurb>');
var httpResponse = '<textarea name="content" ng-model="content"></textarea>';
scope = $rootScope.$new();
httpMock = _$httpBackend_;
httpMock.whenGET('components/blurb/blurb.html').respond(httpResponse);
element = $compile(element)(scope);
scope.$digest();
}));
it('should have some content', function () {
expect(scope.content).toBeDefined();
});
});
The value "scope.content" is always undefined and when I look at the scope object it seems to be a generic scope object that doesn't have my custom attributes on it.
Here are the other related files:
blurb-directive.js
(function () {
'use strict';
angular.module('blurb')
.directive('mcgiBlurb', blurb);
function blurb() {
return {
restrict: 'E',
replace: true,
templateUrl: jsGlobals.componentsFolder + '/blurb/blurb.html',
controller: 'BlurbController',
controllerAs: 'blurb',
bindToController: false,
scope: {
textKey: "#"
}
};
};
})();
blurb-controller.js
(function () {
angular.module('blurb')
.controller('BlurbController', ['$scope', 'blurbsFactory', 'userFactory', function ($scope, blurbsFactory, userFactory) {
$scope.content = "";
$scope.blurbs = {};
$scope.currentUser = {};
this.editMode = false;
userFactory().success(function (data) {
$scope.currentUser = data;
});
blurbsFactory().success(function (data) {
$scope.blurbs = data;
$scope.content = $scope.blurbs[$scope.textKey];
});
this.enterEditMode = function () {
this.editMode = true;
};
this.saveEdits = function () {
this.editMode = false;
$scope.blurbs[$scope.textKey] = $scope.content;
};
}]);
})();
What am I doing wrong?
The directive has isolated scope, so the scope passed to its controller and link function (if there was one), is the isolated one, different than your scope.
You may have luck getting the scope of the directive using element.isolateScope(); you may not, because of the replace: true - try to make sure. You may also access the controller instance using element.controller('mcgiBlurb').

calling a directive method from controller

I am creating a directive with angular and in that i am using kendo-window control. Now i want to open that kendo window on demand from controller. In simple words i want to call a method of directive from controller on button click.
Here is my code sample
sample.directive('workorderwindow', [initworkorderwindow]);
function initworkorderwindow() {
return {
link: function (scope, elements, attrs) {
},
restrict: 'E',
template: "<div data-kendo-window='window.control' data-k-options='window.config'> HELLOW RORLD </div>",
scope: {
},
controller: function ($scope) {
$scope.window =
{
control: null,
config: { title: 'HELLO WORLD', visible: false }
}
$scope.open = function () {
$scope.window.control.center().open();
}
}
}
}
HTML
<workorderwindow></workorderwindow>
Now i want to call that directive open method from my controller.
sample.controller('datacontroller', ['$scope', 'datafac', initcontroller]);
function initcontroller($scope, datafac) {
$scope.onsampleclick = function () {
//FROM HERE
}
It's probably a bad practice to directly call a function of your directive from a controller. What you can do is create a Service, call it from your controller and injecting this service in your directive. With a $watch you will be able to trigger your directive function.
The service between Controller and Directive
app.factory('myWindowService', function () {
return {
windowIsOpen : null,
openWindow: function () {
this.windowIsOpen = true;
},
closeWindow: function () {
this.windowIsOpen = false;
}
};
Your directive :
app.directive('workorderwindow', function () {
return {
restrict: 'E',
template: "<div>test</div>",
controller: function ($scope, myWindowService) {
$scope.windowService = myWindowService;
$scope.$watch("windowService.windowIsOpen", function (display) {
if (display) {
console.log("in directive");
//$scope.window.control.center().open();
}
// You can close it here too
});
}
};
})
And to call it from your controller
app.controller('datacontroller', function ($scope, myWindowService) {
$scope.open = function () {
myWindowService.openWindow();
}
// $scope.close = ...
});
Here a working Fiddle http://jsfiddle.net/maxdow/ZgpqY/4/

Resources