Inject $log into every controller and service - angularjs

Is there any way to inject AngularJS's $log into every service and controller? It just feels a little redundant specifying it for every one.

Another way you could do it is to add a method to the rootScope, and then access it through $scope.$root in your controllers, thus avoiding another injection. I don't know if it is as bad as globals.
testapp.js
(function(){
'use strict';
angular.module('app', [])
.run(function($rootScope, $log) {
$rootScope.log = function(msg){
$log.info(msg);
}
})
.controller('LogCtrl', ['$scope', function LogCtrl($scope) {
$scope.logThis = function(msg){
$scope.$root.log(msg);
};
}]);
})();
test.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.5/angular.min.js"></script>
<script src="testapp.js"></script>
</head>
<body ng-app="app">
<div ng-controller="LogCtrl">
<p>Enter text and press the log button.</p>
Message:
<input type="text" ng-model="message"/>
<button ng-click="logThis(message)">log</button>
</div>
</body>
</html>

Injecting it seems impossible to me without defining it in the function parameters. But you can make it available:
var $log;
app.run(['$log',function(logService) {
$log = logService;
}]);
app.controller('MainCtrl', function($scope, myService) {
$log.warn('Controlling');
});
app.service('myService', function() {
$log.warn('Ha!');
return {};
});
http://plnkr.co/edit/Zwnay7dcMairPGT0btmC?p=preview
Another way would be to set it as a global variable (window.$log), but I wouldn't do that.

Here's a solution for those who think that using the $rootscope requires too much fuss: add the $log to the angular object.
angular.module('myModule')
.run(['$log', function($log) {
angular.log = $log;
}]);
Then when you create your controllers, no $log is required.
angular.module('myModule')
.controller('MyController', MyController);
MyController.$inject = []; // <-- see, no $log required!
function MyController() {
angular.log.info("Hello world");
}
You could even take it a step further and add angular.info = $log.info if you wish to shorten it a bit more.

Related

Executing any one function in controller executes the entire controller function

I am a newbie to Angular. I am using a controller and I am initially loading the page using the init function. I have an element on html that activates the incrementPage function. When I activate the function, the init function executes again and I get the same result instead of the next page. How do I solve this issue?
myApp.controller('MusicController', ['$scope', '$resource', function($scope, $resource){
var vm = $scope;
init();
function init(){
vm.pgno = 1;
music = $resource('http://104.197.128.152:8000/v1/tracks/', {"page": vm.pgno}).get({"page": vm.pgno});
vm.tracks = music;
}
vm.incrementPage = function(){
vm.pgno = vm.pgno + 1;
console.log(vm.pgno);
music = $resource('http://104.197.128.152:8000/v1/tracks/', {"page": vm.pgno}).get({"page": vm.pgno});
vm.tracks = music;
console.log(vm.pgno);
};
}]);
Also, I am using ngRoute and two different controllers.
myApp.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: "views/listMusic.html",
controller:'MusicController',
})
.when('/genres', {
templateUrl: "views/genres.html",
controller:'MusicGenreController',
})
}]);
myApp.controller('MusicGenreController', ['$scope', 'tracklister', function($scope, tracklister) {
var vm = $scope;
var gpgno = 1;
var incrementGPage = function(){
gpgno += 1;
gen = tracklister.genreList.get({'page': gpgno});
vm.genres = gen;
}
(function(){
gen = tracklister.genreList.get({'page': gpgno});
vm.genres = gen;
})();
}]);
When I click the Genres instead of taking me to the genres view it is getting me back to the same listMusic view inside the first MusicController controller. What to do here?
<!DOCTYPE html>
<html ng-app='ListTracksApp'>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular-route.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular-resource.js"></script>
<script src="appl.js"></script>
<meta charset="utf-8">
<link rel="stylesheet" href="styles.css">
<title>Music</title>
</head>
<body>
<h1>Music Tracks</h1>
Genres
<div ng-view>
</div>
</body>
</html>
In your controller, change it to this:
myApp.controller('MusicController', ['$scope', '$resource', function($scope, $resource) {
var vm = $scope;
function $onInit() {
// the rest of your code
That'll get called once, when the controller initializes. Also I think your link is incorrect, as georgeawg pointed out but I'm not too familiar with ngRoute, I've used uiRouter for years, it should be #!/genres
One other thing although this isn't related to your question, in your init() function you have a call to your db, which I suspect is going to be async, you should probably use resolve in the ngRoute and inject it into the controller so it's initially resolved:
resolve: {
data: function ($resource) {
var url = 'http://104.197.128.152:8000/v1/tracks/';
return $resource(url, {"page": 1}).get({"page": 1}).$promise;
}
}
Then your controller can use 'data' as the result of the call:
myApp.controller('MusicController', ['$scope', '$resource', 'data', function($scope, $resource, data)

How to declare and use modules, controllers, services and bootstrap manually in Angular?

i'm trying to build an AngularJS app that has one Controller, one Service and that Bootstraps manually (no ng-app). The problem is that I keep having an error :
Argument 'AppController' is not a function, got string
HTML
<!DOCTYPE HTML>
<html xmlns:ng="http://angularjs.org">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-rc.0/angular.min.js" type="text/javascript"></script>
<script src="inc/bootstrap.js" type="text/javascript"></script>
<script src="inc/controllers.js" type="text/javascript"></script>
<script src="inc/services.js" type="text/javascript"></script>
</head>
<body ng-controller="AppController">
[...]
</body>
</html>
bootstrap.js
angular.element(document).ready(function() {
angular.bootstrap(document, ['htmlControllerApp']);
});
controllers.js
angular.module('htmlControllerApp', [])
.controller('AppController', 'ConnectionService', ['$scope', function ($scope, ConnectionService) {
// Code
}]);
services.js
angular.module('htmlControllerApp')
.factory('ConnectionService', ['$rootScope', function ($rootScope) {
// Code
}]);
Thanks
EDIT - SOLUTION
In controllers.js, use instead :
angular.module('htmlControllerApp')
.controller('AppController', ['$scope', 'ConnectionService', function ($scope, ConnectionService) {
// Code
}]);
In bootstrap.js, as a "good practice" :
angular.module('htmlControllerApp', []);
angular.element(document).ready(function() {
angular.bootstrap(document, ['htmlControllerApp']);
});
This will create the module just once in bootstrap.js and AngularJS will try to retrieve it in controllers.js and services.js.
This is the page you're looking for.
https://docs.angularjs.org/api/ng/function/angular.bootstrap
and change this
angular.module('htmlControllerApp', [])
.controller('AppController', 'ConnectionService', ['$scope', function ($scope, ConnectionService) {
// Code
}]);
to this ->
angular.module('htmlControllerApp', [])
.controller('AppController', ['$scope', 'ConnectionService', function ($scope, ConnectionService) {
// Code
}]);

access angular $cookies from non-angular code

I have a test module that set cookie isTesting to be true
app.controller('test_page',
['$scope', '$window', 'userService', 'flash', '$cookies',
function($scope, $window, userService, flash, $cookies) {
helper.initCommonScope($scope, $window, userService, flash)
$scope.refreshShownHidden = function() {
$scope.showTurnOffTest = $cookies.get('isTesting')
$scope.showTurnOnTest = ! $cookies.get('isTesting')
}
$scope.turnOnTest = function() {
$cookies.put('isTesting', true)
$scope.refreshShownHidden()
helper.turnOnTest()
}
$scope.turnOffTest = function() {
$cookies.put('isTesting', false)
$scope.refreshShownHidden()
helper.turnOffTest()
}
$scope.refreshShownHidden()
}])
And in helper.js, I have
exports.havePermission = function(access, resource, userService, entity) {
//Note: In debugging, we can grant client helper all access, and test robustness of server
if (angular.$cookies.isTesting)
return true
return permission.havePermission(access, resource, userService.isAuthenticated(), entity, userService.user)
}
But $cookies is not available since helper.js is not part of any angular module, thus no DI is available. How can I access the isTesting value?
I have tried using window.isTesting instead but it's not persisted when I refresh the page or go to other pages. So cookie is a better choice
You can use Angular's injector to access Angular modules and services outside of your Angular application.
AngularJS Code
angular.module('app', ['ngCookies']).
controller('ctrl', ['$cookies', function($cookies) {
$cookies.put('isTesting', true);
}]);
Non-Angular Code
helper = {
getCookies: function() {
// Create new injector for ngCookies module
var $injector = angular.injector(['ngCookies']);
// Inject $cookies to some function and invoke it
$injector.invoke(['$cookies', function($cookies) {
alert($cookies.get('isTesting'));
}]);
}
}
HTML
<html ng-app='app'>
<head>
<script data-require="angular.js#1.4.3" data-semver="1.4.3" src="https://code.angularjs.org/1.4.3/angular.js"></script>
<script data-require="angular-cookies.js#1.4.3" data-semver="1.4.3" src="https://code.angularjs.org/1.4.3/angular-cookies.js"></script>
<script src="script.js"></script>
<script src="helper.js"></script>
</head>
<body ng-controller="ctrl">
<button onclick="helper.getCookies()">Click Me</button>
</body>
</html>
Plunker: http://plnkr.co/edit/jur9A6d69ViiJqiFgopD?p=preview
var cookies = angular.injector(['ngCookies']).get('$cookies');
It creates a new instance of $cookies service, so if you're using it across the app, it is better to export it to global.
It's not the AngularJS purpose. You should try to keep all your stuff in your AngularJS code. However you can set any global variable in AngularJS:
app.controller('test_page',
['$scope', '$window', 'userService', 'flash', '$cookies',
function($scope, $window, userService, flash, $cookies) {
angular.$cookies = $cookies;
// or window.$cookies = $cookies;
helper.initCommonScope($scope, $window, userService, flash)
Then you can access $cookies anytime anywhere. It make certain things easier but less safe (any other script can access it too, it can create conflict, etc.)

Injecting $scope in manually instantiated controller

I'm trying to inject $scope in a controller created using the $controller service.
I'm getting the following error:
Unknown provider: $scopeProvider <- $scope <- TestController
It's important to mention that the creation is happening inside a directive's link function.
I've written a simple example to show the error.
app.js:
(function() {
angular.module('app', [])
.controller('TestController', [
'$scope',
function($scope) {
// I want to be able to use 'message' from the directive's template
// as if the controller was loaded directly using ng-controller
$scope.message = 'Hello World!';
}
])
.directive('directive', [
'$controller',
function($controller) {
return {
restrict: 'A',
template: '<div>{{ message }}</div>',
link: function(scope) {
// In the actual app the controller is dynamically selected
// I'm registering a $watch here that provides me the
// name of the controller
scope.myController = $controller('TestController');
}
};
}
]);
})();
index.html:
<!DOCTYPE html>
<html ng-app="app">
<head>
<title>Testing injection</title>
</head>
<body>
<div directive></div>
<script src="angular.js"></script>
<script src="app.js"></script>
</body>
</html>
Question: Why is this happening? Can you explain me the logic behind this behaviour? Any workaround?
Thank you.
Following Digix's answer, I was able to make it work:
var locals = {};
locals.$scope = scope;
$controller('TestController', locals);
My assumption is that in this way, instead of creating a new scope, the controller shares the one of the directive.
var locals = {};
locals.$scope = scope.$new();
$controller('testCtrl', locals);

How to access $rootScope value defined in one module into another module

I need to understand "How can I access the value of $rootScope value defined in one module into other module?"
Below is my code :
Index.html
<!DOCTYPE html>
<html ng-app="myapp">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"> </script>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
<script src="test.js"></script>
</head>
<div ng-controller="serviceDIController">
Service Values is : <b> {{sdiParam}} </b> <br/>
Factory Values is : <b> {{fdiParam}} </b> <br/>
Root Scope Values is : <b> {{rootParam}} </b>
</div>
</html>
script.js
var app = angular.module("myapp", ['testModule']);
app.controller('serviceDIController',['$scope','$rootScope',
'testService','testFactory',function($scope, $rootScope,testService, testFactory)
{
$scope.sdiParam = testService.param;
$scope.fdiParam = testFactory.fparam;
// $scope.rootParam = $rootScope.root; // How to access "$rootScope.root" value defined in test.js in current module inside a controller?
}
]);
test.js
var testapp = angular.module("testModule", []);
testapp.service('testService', function() {
this.param = "Service Param1 DI";
});
testapp.factory('testFactory', function() {
var fact = {};
fact.fparam = "Fact Param1 DI";
return fact;
});
testapp.controller('testCtrl', ['$scope',
function($rootScope) {
$rootScope.root = "Root Scope Param1";
}
]);
Live demo : http://plnkr.co/edit/X0aamCi9ULcaB63VpVs6?p=preview
Checked below example but did not work:
AngularJS $rootScope variable exists, but not accessible
Explicitly inject '$scope', not '$rootScope' in testCtrl, so a new scope is created just for that controller and passed as the first argument regardless of the name used for that argument.
Incorrect:
testapp.controller('testCtrl', ['$scope',
function($rootScope) {
$rootScope.root = "Root Scope Param1";
}
]);
Correct:
testapp.controller('testCtrl', ['$rootScope',
function($rootScope) {
$rootScope.root = "Root Scope Param1";
}
]);
Here is your updated working Plunkr
Basically I prefer to use $scope.$root to prevent the injection of the $rootScope.
You have also set the testCtlr on the <head> tag, don't know if it was on purpose or not.

Resources