How do I make a directive's functions globally available? - angularjs

Imagine I have a singleton user-interface element that I want to provide services to the entire application.
The following "works", in that setMessage() is available anywhere in the application, via $rootScope:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.17/angular.js"></script>
<body ng-app="myApp">
<script>
angular.module('myApp', [])
.directive('myDirective', function($rootScope) {
return {
scope : {},
template: '<div>Status: {{contents}}</div>',
controller: function($scope) {
$rootScope.setMessage = function(contents) {
$scope.contents = contents;
};
}
};
});
</script>
<div my-directive=""></div>
<button ng-click="setMessage('clicked')">Click Me</button>
</body> </html>
It works, but I don't like it. It just doesn't feel anglish to me. I have been toying with the idea of create a service that exports a function to set the value and another function to get it, but that doesn't smell much better.
Any suggestions?

Related

Can I create global function with $window and call it in controllers in angularJS? [duplicate]

If I have a utility function foo that I want to be able to call from anywhere inside of my ng-app declaration. Is there someway I can make it globally accessible in my module setup or do I need to add it to the scope in every controller?
You basically have two options, either define it as a service, or place it on your root scope. I would suggest that you make a service out of it to avoid polluting the root scope. You create a service and make it available in your controller like this:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.factory('myService', function() {
return {
foo: function() {
alert("I'm foo!");
}
};
});
myApp.controller('MainCtrl', ['$scope', 'myService', function($scope, myService) {
$scope.callFoo = function() {
myService.foo();
}
}]);
</script>
</head>
<body ng-controller="MainCtrl">
<button ng-click="callFoo()">Call foo</button>
</body>
</html>
If that's not an option for you, you can add it to the root scope like this:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.run(function($rootScope) {
$rootScope.globalFoo = function() {
alert("I'm global foo!");
};
});
myApp.controller('MainCtrl', ['$scope', function($scope){
}]);
</script>
</head>
<body ng-controller="MainCtrl">
<button ng-click="globalFoo()">Call global foo</button>
</body>
</html>
That way, all of your templates can call globalFoo() without having to pass it to the template from the controller.
You can also combine them I guess:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.factory('myService', function() {
return {
foo: function() {
alert("I'm foo!");
}
};
});
myApp.run(function($rootScope, myService) {
$rootScope.appData = myService;
});
myApp.controller('MainCtrl', ['$scope', function($scope){
}]);
</script>
</head>
<body ng-controller="MainCtrl">
<button ng-click="appData.foo()">Call foo</button>
</body>
</html>
Though the first approach is advocated as 'the angular like' approach, I feel this adds overheads.
Consider if I want to use this myservice.foo function in 10 different controllers. I will have to specify this 'myService' dependency and then $scope.callFoo scope property in all ten of them. This is simply a repetition and somehow violates the DRY principle.
Whereas, if I use the $rootScope approach, I specify this global function gobalFoo only once and it will be available in all my future controllers, no matter how many.
AngularJs has "Services" and "Factories" just for problems like yours.These are used to have something global between Controllers, Directives, Other Services or any other angularjs components..You can defined functions, store data, make calculate functions or whatever you want inside Services and use them in AngularJs Components as Global.like
angular.module('MyModule', [...])
.service('MyService', ['$http', function($http){
return {
users: [...],
getUserFriends: function(userId){
return $http({
method: 'GET',
url: '/api/user/friends/' + userId
});
}
....
}
}])
if you need more
Find More About Why We Need AngularJs Services and Factories
I'm a bit newer to Angular but what I found useful to do (and pretty simple) is I made a global script that I load onto my page before the local script with global variables that I need to access on all pages anyway. In that script, I created an object called "globalFunctions" and added the functions that I need to access globally as properties. e.g. globalFunctions.foo = myFunc();. Then, in each local script, I wrote $scope.globalFunctions = globalFunctions; and I instantly have access to any function I added to the globalFunctions object in the global script.
This is a bit of a workaround and I'm not sure it helps you but it definitely helped me as I had many functions and it was a pain adding all of them to each page.

AngularJS - $templateCache is not defined

I am trying to load a template file in an AngularStrap popover, however I am having trouble using $templateCache. I seem to be a step further back than the other SO questions, hence this seemingly double one.
Following the API docs I added a <script type="text/ng-template" id="popoverTemplate.html"></script> right before the closing </body> tag. When I use <div ng-include="'popoverTemplate.html'"></div> on my page, I get nothing. If I try using console.log($templateCache.get("popoverTemplate.html")) I get "$templateCache is not defined", which leads me to assume I am missing a crucial step. However, I can't find how to do it in the docs or other SO questions.
EDIT:
Injecting the service was the missing link. However, when I inject the service, the controller's other function no longer works, but if you inject al the function's parameters the working code becomes:
(function() {
"use strict";
angular.module("app").controller("managerController", ["$scope", "imageHierarchyRepository", "$templateCache", function ($scope, imageHierarchyRepository, $templateCache) {
imageHierarchyRepository.query(function(data) {
$scope.hierarchies = data;
});
var template = $templateCache.get("popoverTemplate.html");
console.log(template);
}]);
})();
To use the template script tag . You have to insert it inside the angular application. That is inside the element with the ng-app attribute or the element used to bootstrap the app if you don't use the ng-app tag.
<body ng-app="myapp">
<div ng-template="'myTemplate.html'"></div>
<script type="text/ng-template" id="myTemplate.html">
// whate ever
</script>
</body>
If you want to retrieve the template on a component of the application then you need to inject the service where you want to consume it:
controller('FooCtrl', ['$templateCache', function ($templateCache) {
var template = $templateCache.get('myTemplate.html');
}]);
Or
controller('FooCtlr', FooCtrl);
FooCtrl ($templateCache) {};
FooCtrl.$inject = ['$templateCache'];
EDIT
Do not register two controllers with the same name because then you override the first one with the last one.
(function() {
"use strict";
angular.module("app").controller("managerController",["$scope", "imageHierarchyRepository", "$templateCache", function ($scope, imageHierarchyRepository, $templateCache) {
var template = $templateCache.get("popoverTemplate.html");
console.log(template);
imageHierarchyRepository.query(function(data) {
$scope.hierarchies = data;
});
}]);
})();
Small addition: Although there are few ways to achieve your goals, like wrapping your whole HTML in <script> tags and all that, the best approach for me was to add the $templateCache logic into each Angular directive. This way, I could avoid using any external packages like grunt angular-templates (which is excellent but overkill for my app).
angular.module('MyApp')
.directive('MyDirective', ['$templateCache', function($templateCache) {
return {
restrict: 'E',
template: $templateCache.get('MyTemplate').data,
controller: 'MyController',
controllerAs: 'MyController'
};
}]).run(function($templateCache, $http) {
$http.get('templates/MyTemplate.html').then(function(response) {
$templateCache.put('MyTemplate', response);
})
});
Hope this helps!

Make a default function for all controllers Angular JS [duplicate]

If I have a utility function foo that I want to be able to call from anywhere inside of my ng-app declaration. Is there someway I can make it globally accessible in my module setup or do I need to add it to the scope in every controller?
You basically have two options, either define it as a service, or place it on your root scope. I would suggest that you make a service out of it to avoid polluting the root scope. You create a service and make it available in your controller like this:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.factory('myService', function() {
return {
foo: function() {
alert("I'm foo!");
}
};
});
myApp.controller('MainCtrl', ['$scope', 'myService', function($scope, myService) {
$scope.callFoo = function() {
myService.foo();
}
}]);
</script>
</head>
<body ng-controller="MainCtrl">
<button ng-click="callFoo()">Call foo</button>
</body>
</html>
If that's not an option for you, you can add it to the root scope like this:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.run(function($rootScope) {
$rootScope.globalFoo = function() {
alert("I'm global foo!");
};
});
myApp.controller('MainCtrl', ['$scope', function($scope){
}]);
</script>
</head>
<body ng-controller="MainCtrl">
<button ng-click="globalFoo()">Call global foo</button>
</body>
</html>
That way, all of your templates can call globalFoo() without having to pass it to the template from the controller.
You can also combine them I guess:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.factory('myService', function() {
return {
foo: function() {
alert("I'm foo!");
}
};
});
myApp.run(function($rootScope, myService) {
$rootScope.appData = myService;
});
myApp.controller('MainCtrl', ['$scope', function($scope){
}]);
</script>
</head>
<body ng-controller="MainCtrl">
<button ng-click="appData.foo()">Call foo</button>
</body>
</html>
Though the first approach is advocated as 'the angular like' approach, I feel this adds overheads.
Consider if I want to use this myservice.foo function in 10 different controllers. I will have to specify this 'myService' dependency and then $scope.callFoo scope property in all ten of them. This is simply a repetition and somehow violates the DRY principle.
Whereas, if I use the $rootScope approach, I specify this global function gobalFoo only once and it will be available in all my future controllers, no matter how many.
AngularJs has "Services" and "Factories" just for problems like yours.These are used to have something global between Controllers, Directives, Other Services or any other angularjs components..You can defined functions, store data, make calculate functions or whatever you want inside Services and use them in AngularJs Components as Global.like
angular.module('MyModule', [...])
.service('MyService', ['$http', function($http){
return {
users: [...],
getUserFriends: function(userId){
return $http({
method: 'GET',
url: '/api/user/friends/' + userId
});
}
....
}
}])
if you need more
Find More About Why We Need AngularJs Services and Factories
I'm a bit newer to Angular but what I found useful to do (and pretty simple) is I made a global script that I load onto my page before the local script with global variables that I need to access on all pages anyway. In that script, I created an object called "globalFunctions" and added the functions that I need to access globally as properties. e.g. globalFunctions.foo = myFunc();. Then, in each local script, I wrote $scope.globalFunctions = globalFunctions; and I instantly have access to any function I added to the globalFunctions object in the global script.
This is a bit of a workaround and I'm not sure it helps you but it definitely helped me as I had many functions and it was a pain adding all of them to each page.

Angular Scope Directives

Angular Structural Question
I am new to angular.js and am just wondering how to go about performing a certain situation.
So basically, what I have got is a container:
<div ng-controller="ContainerController">
<container></container>
</div>
And the container controller and directives.
<script type="text/javascript" src="ContainerController.js"></script>
<script type="text/javascript" src="ContainerDirectives.js"></script>
Now the directives replaces the <container> tag with an example html: <example>{{ data }}</example>
Now within the scope of the ContainerController I have defined data as a string. (This is all example purposes). However when the directive accesses replaces it, it is unable to find the variable, due to scope.
The reason that this happens is because the ContainerDirective script's scope is not within the ContainerController scope. Meaning it is unable to access the variable.
Im just not sure on structure practices for these kinds of situations. Where do I put everything so the ContainerDirective can access the ContainerController scope.
I hope i have explained everything good enough
EDIT:
Test.js
(function(){
angular.module('test', []);
})();
TestController.js
(function(){
angular
.module('test')
.controller('TestController', [
'$scope',
TestController
]);
function TestController($scope) {
$scope.test = 'test';
}
})();
TestDirective.js
(function(){
angular.module('test').directive('test', function () {
return {
replace: true,
templateUrl: 'src/test/view/test.html',
link: function (scope, element, attrs) {
}
};
});
})();
test.html
<example>ClickMe</example>
index.html - body
<body ng-app="App" layout="row" ng-controller="TestController as page">
<test></test>
<script src="src/test/Test.js"></script>
<script src="src/test/TestController.js"></script>
<script src="src/test/TestDirective.js"></script>
<script type="text/javascript">
angular
.module('App', ['test']);
</script>
</body>
For reasons I have renamed certain variables and deleted a lot of data, but this is the core, and I am struggling to see anything wrong with this.
Error: [$interpolate:noconcat] Error while interpolating: abc/{{test}}
Strict Contextual Escaping disallows interpolations that concatenate multiple expressions when a trusted value is required.
So I figured out what was wrong in the end. Basically angular wont allow iframe of another location to be printed unless you first:
Give them the full url.
Then allow external url as a trusted website.
TO do this I had to basically add:
in the Test.js
angular.module('test', []).config(function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist($sceDelegateProvider.resourceUrlWhitelist().concat([
'http://www.test.com/**'
]));
});
This basically took my whitelist and concatinated the new url to it.
Then inside test.html:
<example><iframe ng-src={{src}}></iframe></example>

Can I make a function available in every controller in angular?

If I have a utility function foo that I want to be able to call from anywhere inside of my ng-app declaration. Is there someway I can make it globally accessible in my module setup or do I need to add it to the scope in every controller?
You basically have two options, either define it as a service, or place it on your root scope. I would suggest that you make a service out of it to avoid polluting the root scope. You create a service and make it available in your controller like this:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.factory('myService', function() {
return {
foo: function() {
alert("I'm foo!");
}
};
});
myApp.controller('MainCtrl', ['$scope', 'myService', function($scope, myService) {
$scope.callFoo = function() {
myService.foo();
}
}]);
</script>
</head>
<body ng-controller="MainCtrl">
<button ng-click="callFoo()">Call foo</button>
</body>
</html>
If that's not an option for you, you can add it to the root scope like this:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.run(function($rootScope) {
$rootScope.globalFoo = function() {
alert("I'm global foo!");
};
});
myApp.controller('MainCtrl', ['$scope', function($scope){
}]);
</script>
</head>
<body ng-controller="MainCtrl">
<button ng-click="globalFoo()">Call global foo</button>
</body>
</html>
That way, all of your templates can call globalFoo() without having to pass it to the template from the controller.
You can also combine them I guess:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.factory('myService', function() {
return {
foo: function() {
alert("I'm foo!");
}
};
});
myApp.run(function($rootScope, myService) {
$rootScope.appData = myService;
});
myApp.controller('MainCtrl', ['$scope', function($scope){
}]);
</script>
</head>
<body ng-controller="MainCtrl">
<button ng-click="appData.foo()">Call foo</button>
</body>
</html>
Though the first approach is advocated as 'the angular like' approach, I feel this adds overheads.
Consider if I want to use this myservice.foo function in 10 different controllers. I will have to specify this 'myService' dependency and then $scope.callFoo scope property in all ten of them. This is simply a repetition and somehow violates the DRY principle.
Whereas, if I use the $rootScope approach, I specify this global function gobalFoo only once and it will be available in all my future controllers, no matter how many.
AngularJs has "Services" and "Factories" just for problems like yours.These are used to have something global between Controllers, Directives, Other Services or any other angularjs components..You can defined functions, store data, make calculate functions or whatever you want inside Services and use them in AngularJs Components as Global.like
angular.module('MyModule', [...])
.service('MyService', ['$http', function($http){
return {
users: [...],
getUserFriends: function(userId){
return $http({
method: 'GET',
url: '/api/user/friends/' + userId
});
}
....
}
}])
if you need more
Find More About Why We Need AngularJs Services and Factories
I'm a bit newer to Angular but what I found useful to do (and pretty simple) is I made a global script that I load onto my page before the local script with global variables that I need to access on all pages anyway. In that script, I created an object called "globalFunctions" and added the functions that I need to access globally as properties. e.g. globalFunctions.foo = myFunc();. Then, in each local script, I wrote $scope.globalFunctions = globalFunctions; and I instantly have access to any function I added to the globalFunctions object in the global script.
This is a bit of a workaround and I'm not sure it helps you but it definitely helped me as I had many functions and it was a pain adding all of them to each page.

Resources