using $scope with controller as syntax - angularjs

UPDATE
here's the article where I saw the examples below: https://github.com/johnpapa/angular-styleguide
after re-reading the example I realized that a specific and unique scenario was being explained, thus this question may not be fully valid. I will not delete it, however, so that if anyone has any further knowledge, they can contribute and help the community.
I've been reading about angular best practices and I'm convinced after reading a few articles that the best approach is to use the controller as syntax:
angular.module('example', [])
.controller('somectr', somectr);
somectr.$inject =['$http'];
function somectr($http) {
var vm = this;
this.x;
}
however I saw an article that shows this syntax, but it also injects a scope:
somectr.$inject = ['$scope', '$http'];
function somectr($scope, $http) {
var vm = this;
this.x;
this.y;
$scope.someFunc = function() {}
}
I thought that using the controller as syntax means no need to use a scope object. What user case would require the controller as syntax but still make use of a scope object?

An example of injecting $scope even if you are using controllerAs is when you want to pub/sub events.
If you want to Publish some events, you would use:
$scope.$broadcast('eventName', value)
$scope.$emit('eventName', value)
For Subscribing:
$scope.$on('eventName', function)
Take a further look at: https://docs.angularjs.org/api/ng/type/$rootScope.Scope
Another example would be if you are using $scope.$watch
There's a good article on controllerAs by ToddMotto: http://toddmotto.com/digging-into-angulars-controller-as-syntax/

Related

What does 'var vm = this;' mean in angular controllers?

I was browsing some stuff on github and I saw inside controller.js, someone had put the following:
function ImageController ($scope, $timeout) {
var vm = this;
}
What is this used for?
The vm in this case means viewmodel.
It is a shortcut, so instead of writing this.someMethod() you can use vm.someMethod().
Very common when you use Controller As syntax, so you donĀ“t use the $scope by "accident".
Also, the this keyword can be messy to use, since it may reference different things depending on where it is used.
Why?: Helps avoid the temptation of using $scope methods inside a
controller when it may otherwise be better to avoid them or move the
method to a factory, and reference them from the controller.
you can check full John Papa Angular Style to learn deeper...

how to duplicate and make tiny changes to existing angularjs controller

what I am trying to do here is to create a similar controller but not exactly the same, a few aspects of the controller need to be override. if it is the case in java then I probably just subclass and override the method I needed. but here in AngularJs not sure what is the best way to achieve this.
I really don't want to duplicate the code. refactoring the existing code is preferred but due to timeline issue have to delay that a bit.
so what is the correspondence of subclass and override in AngularJS
When you really need controller inheritance (including $scope), I think your question is best answered here: What's the recommended way to extend AngularJS controllers?
You can create a service and inherit its behaviour in any controller just by injecting it.
app.service("reusableCode", function() {
var reusableCode = {};
reusableCode.commonMethod = function() {
alert('Hello, World!');
};
return reusableCode;
});
Then in your controller that you want to extend from the above reusableCode service:
app.controller('MainCtrl', function($scope, reusableCode) {
angular.extend($scope, reusableCode);
// now you can access all the properties of reusableCode in this $scope
$scope.commonMethod()
});
DEMO PLUNKER: http://plnkr.co/edit/EQtj6I0X08xprE8D0n5b?p=preview

AngularJS controller $scope reserved keyword?

I am a newbie to Angular, I came across this fiddle which explains how nested controller works. When I rename $scope to something else say $abc and it doesn't work, does it mean that $scope is a reserved keyword in angularJS?
function CarController($scope) {
$scope.name = 'Car';
$scope.type = 'Car';
}
function BMWController($scope) {
$scope.name = 'BMW';
}
function BMWMotorcycleController($scope) {
$scope.name = 'BMWMotorade';
$scope.type = 'Motorcycle';
}
Effectively, yes. It's not a reserved word in the sense that e.g. if and while are but AngularJS gives it meaning. In your example Angular parses the string representation of the function and uses the named parameters to determine what to "inject" into the function when it calls it.
In this case you're injecting the $scope service.
It's not a reserved keyword, it's a specific dependency. You can ask all sorts of dependencies. For example, you can define a service and call it "$abc", and then inject that service into your controller. For more info:
https://docs.angularjs.org/guide/di
Your concept will be more clear by watching following video -
http://www.youtube.com/watch?v=NnB2NBtoeAY&list=PLP6DbQBkn9ymGQh2qpk9ImLHdSH5T7yw7&index=26
Hope this will help
I saw this on a AngularJS tut on their website:
This scope is a prototypical descendant of the root scope that was
created when the application was defined.

angular js how can I use a collection in all of my scopes

I have a collection that I need to access in all of my nested scopes. Inside my directive templates, inside my directives in ng-repeat... n levels deep. I don't want to have to say $scope.$parent.$parent.$parent....$parent.MyList.
I've tried using $rootScope, but clearly I lack the understanding of how this works. I pass it into my directive during the declaration like so:
$rootScope.MyList = ["list": 1];
...
...
MyApp.directive('mydirective', ['$rootScope', function ($rootScope) {
return {
restrict: 'A',
replace: false,
link: function (scope, rootScope) {
}
}
}])
The rootScope does not contain MyList. Is there something I'm doing wrong, or a better way to do it? I've thought of using a Factory or Service, but I don't know how to set that up and we all know how crappy the documentation is for Angular, so searching is very frustrating.
Can you provide a plnkr or jsfiddle reproducing this behavior? I can get the controller to communicate with service using $rootScope.
http://plnkr.co/edit/IEhOde
However, you'd probably want to create a service which would cache the value that you want and inject it in your directive and retrieve the value.
First of all $rootScope.MyList = ["list": 1] has syntax error, should be $rootScope.MyList = ["list", 1] or $rootScope.MyList = [{"list": 1}].
Anything you assign to $rootScope is accessible within child $scopes (except isolate scopes) due to prototype inheritance.
Generally if you want to share something within whole app, you can assign it to $rootScope as you did or you can create top level AppCtrl which will have something like $scope.MyList=... and all nested scopes will have access to it. Second option is bit better when it comes to testability as you can inject service to AppCtrl which provides MyList data. You can see this pattern in action here AngularJS GlobalCtrl vs $rootScope vs Service.
A service/provider is the recommended approach.
For just a list of data you can use the value provider:
app.value('listService', {
MyList : {"list": 1}
});
Inject it where you need it, and you can include it in the relevant scopes as such:
app.controller('Ctrl', function($scope,listService) {
$scope.list = listService.MyList;
});
A fiddle of that: http://jsfiddle.net/qKcQL/
Injecting it where you need is good for documentation and maintenance. But if you really need this on the global $rootScope then this will accomplish that:
app.controller('Ctrl', function($scope,listService,$rootScope) {
$rootScope.list = listService.MyList;
});
$rootScope fiddle: http://jsfiddle.net/qKcQL/1/

Angular.js - share the same model between multiple views by $rootScope [duplicate]

I have a problem where i'm initialising a variable on the scope in a controller. Then it gets changed in another controller when a user logs in. This variable is used to control things such as the navigation bar and restricts access to parts of the site depending on the type of user, so its important that it holds its value. The problem with it is that the controller that initialises it, gets called again by angular some how and then resets the variable back to its initial value.
I assume this is not the correct way of declaring and initialising global variables, well its not really global, so my question is what is the correct way and is there any good examples around that work with the current version of angular?
You've got basically 2 options for "global" variables:
use a $rootScope http://docs.angularjs.org/api/ng.$rootScope
use a service http://docs.angularjs.org/guide/services
$rootScope is a parent of all scopes so values exposed there will be visible in all templates and controllers. Using the $rootScope is very easy as you can simply inject it into any controller and change values in this scope. It might be convenient but has all the problems of global variables.
Services are singletons that you can inject to any controller and expose their values in a controller's scope. Services, being singletons are still 'global' but you've got far better control over where those are used and exposed.
Using services is a bit more complex, but not that much, here is an example:
var myApp = angular.module('myApp',[]);
myApp.factory('UserService', function() {
return {
name : 'anonymous'
};
});
and then in a controller:
function MyCtrl($scope, UserService) {
$scope.name = UserService.name;
}
Here is the working jsFiddle: http://jsfiddle.net/pkozlowski_opensource/BRWPM/2/
If you just want to store a value, according to the Angular documentation on Providers, you should use the Value recipe:
var myApp = angular.module('myApp', []);
myApp.value('clientId', 'a12345654321x');
Then use it in a controller like this:
myApp.controller('DemoController', ['clientId', function DemoController(clientId) {
this.clientId = clientId;
}]);
The same thing can be achieved using a Provider, Factory, or Service since they are "just syntactic sugar on top of a provider recipe" but using Value will achieve what you want with minimal syntax.
The other option is to use $rootScope, but it's not really an option because you shouldn't use it for the same reasons you shouldn't use global variables in other languages. It's advised to be used sparingly.
Since all scopes inherit from $rootScope, if you have a variable $rootScope.data and someone forgets that data is already defined and creates $scope.data in a local scope you will run into problems.
If you want to modify this value and have it persist across all your controllers, use an object and modify the properties keeping in mind Javascript is pass by "copy of a reference":
myApp.value('clientId', { value: 'a12345654321x' });
myApp.controller('DemoController', ['clientId', function DemoController(clientId) {
this.clientId = clientId;
this.change = function(value) {
clientId.value = 'something else';
}
}];
JSFiddle example
Example of AngularJS "global variables" using $rootScope:
Controller 1 sets the global variable:
function MyCtrl1($scope, $rootScope) {
$rootScope.name = 'anonymous';
}
Controller 2 reads the global variable:
function MyCtrl2($scope, $rootScope) {
$scope.name2 = $rootScope.name;
}
Here is a working jsFiddle: http://jsfiddle.net/natefriedman/3XT3F/1/
In the interest of adding another idea to the wiki pool, but what about AngularJS' value and constant modules? I'm only just starting to use them myself, but it sounds to me like these are probably the best options here.
Note: as of the time of writing, Angular 1.3.7 is the latest stable, I believe these were added in 1.2.0, haven't confirmed this with the changelog though.
Depending on how many you need to define, you might want to create a separate file for them. But I generally define these just before my app's .config() block for easy access. Because these are still effectively modules, you'll need to rely on dependency injection to use them, but they are considered "global" to your app module.
For example:
angular.module('myApp', [])
.value('debug', true)
.constant('ENVIRONMENT', 'development')
.config({...})
Then inside any controller:
angular.module('myApp')
.controller('MainCtrl', function(debug, ENVIRONMENT), {
// here you can access `debug` and `ENVIRONMENT` as straight variables
})
From the initial question is actually sounds like static properties are required here anyway, either as mutable (value) or final (constant). It's more my personal opinion than anything else, but I find placing runtime configuration items on the $rootScope gets too messy, too quickly.
// app.js or break it up into seperate files
// whatever structure is your flavor
angular.module('myApp', [])
.constant('CONFIG', {
'APP_NAME' : 'My Awesome App',
'APP_VERSION' : '0.0.0',
'GOOGLE_ANALYTICS_ID' : '',
'BASE_URL' : '',
'SYSTEM_LANGUAGE' : ''
})
.controller('GlobalVarController', ['$scope', 'CONFIG', function($scope, CONFIG) {
// If you wish to show the CONFIG vars in the console:
console.log(CONFIG);
// And your CONFIG vars in .constant will be passed to the HTML doc with this:
$scope.config = CONFIG;
}]);
In your HTML:
<span ng-controller="GlobalVarController">{{config.APP_NAME}} | v{{config.APP_VERSION}}</span>
localStorage.username = 'blah'
If you're guaranteed to be on a modern browser. Though know your values will all be turned into strings.
Also has the handy benefit of being cached between reloads.
Please correct me if I'm wrong, but when Angular 2.0 is released I do not believe$rootScope will be around. My conjecture is based on the fact that $scope is being removed as well. Obviously controllers, will still exist, just not in the ng-controller fashion.Think of injecting controllers into directives instead. As the release comes imminent, it will be best to use services as global variables if you want an easier time to switch from verison 1.X to 2.0.
You can also use the environment variable $window so that a global variable declare outside a controller can be checked inside a $watch
var initWatch = function($scope,$window){
$scope.$watch(function(scope) { return $window.globalVar },
function(newValue) {
$scope.updateDisplayedVar(newValue);
});
}
Becareful, the digest cycle is longer with these global values, so it is not always real-timed updated. I need to investigate on that digest time with this configuration.
I just found another method by mistake :
What I did was to declare a var db = null above app declaration and then modified it in the app.js then when I accessed it in the controller.js
I was able to access it without any problem.There might be some issues with this method which I'm not aware of but It's a good solution I guess.
Try this, you will not force to inject $rootScope in controller.
app.run(function($rootScope) {
$rootScope.Currency = 'USD';
});
You can only use it in run block because config block will not provide you to use service of $rootScope.
It's actually pretty easy. (If you're using Angular 2+ anyway.)
Simply add
declare var myGlobalVarName;
Somewhere in the top of your component file (such as after the "import" statements), and you'll be able to access "myGlobalVarName" anywhere inside your component.
You can also do something like this ..
function MyCtrl1($scope) {
$rootScope.$root.name = 'anonymous';
}
function MyCtrl2($scope) {
var name = $rootScope.$root.name;
}

Resources