scope of 'angular' variable when several apps are declared? - angularjs

if you have the following:
<html ng-app="outerApp">
<head ng-app="innerApp"></head>
<script>
var outerApp = angular.module("outerApp", []);
var ACtrl = outerApp.controller("ACtrl", function($scope){console.log($scope.name);});
var BCtrl = outerApp.controller("BCtrl",function($scope){console.log($scope.name});
var CCtrl = innerApp.controller.("CCtrl", function($scope){ console.log($scope.name);});
var innerApp = angular.module("innerApp", []);
</scope>
Is this ok? is angular a global variable that will work for declaring modules out of both innerApp and outerApp? Also are there limits to number of ng-app's on a page? And do both ACtrl, and BCtrl have reference to the same $scope?
Thanks

This won't work because:
Only one AngularJS application can be auto-bootstrapped per HTML document. The first ngApp found in the document will be used to define the root element to auto-bootstrap as an application. To run multiple applications in an HTML document you must manually bootstrap them using angular.bootstrap instead. AngularJS applications cannot be nested within each other.
See documentation

$rootscope,$scope are conceptually global variables, whom you can implement to achieve as global variables for sharing data between the modules,directives,controllers,views.
you should read conceptually DI(Dependency Injection) and how the conceptual framework implements in angular. you can inject the dependencies.
angular.module('modulename',[]);
[] is an array in which you define that module is dependant on the other module. in Other words.
Angular framework concepts works the injectable way DI(Dependency Inject).
however i strongly suggest you, what you trying to achieve is the right path is, you should make a simple custom directive and inject it as a dependency in the angular app.

Related

Can I have 2 controllers in AngularJS app

I'm building a small search app using Elasticsearch and AngularJS (still learning how to use both). I know this may not be best practice, but for all the AngularJS code, trying to keep all my js code in 1 file.
I would like to use the AngularJS UI Bootstrap Typeahead for an autocomplete feature but a little confused on how I can have 2 controllers for the app OR if I can somehow include the Typeahead in my current controller?
Here is some of my code:
var searchApp = angular.module('searchApp', ['elasticsearch', 'ngSanitize', 'ui.bootstrap']);
searchApp.controller('SearchResultsList', ['$scope', 'searchService', 'filterService', '$sce', function($scope, searchService, filterService, $sce) {
I've included ui bootstrap as a dependency for the app, but since I already have SearchResultsList as my controller, not sure how to include TypeaheadCtrl to it...
Yes you can have as many controllers as you'd like in AngularJS. You need to be careful however (for example passing variables between controllers, $scope.$parent, if applicable)
As well, if you are using type-ahead (or any directive from Angular UI-Bootstrap such as tabset), you need to be careful of child-scopes and primitive scopes creating be Angular-UI-Bootstrap. Always declare scope variables using some holding object so it doesn't get overwritten in primitive scopes in a directive ($scope.data storing your data vs just storing it in $scope)
For including typeahead, this is a simple directive and you've already included its functionality when you included it as a dependency in the module. Just read the documentation and follow it:
https://angular-ui.github.io/bootstrap/

AngularJS module inside "root module"

Is there a way to define an angular module inside another module ? I have a template in my web application which is called for almost every page of the application. In the template definition I set the ng-app. So for this ng-app I can declare the modules I need in all pages of the application (or almost every page). Now there are some modules I want to add only on specific pages. The problem is that in those pages I already have the ng-app of the template.
So is there a way to keep the ng-app as some kind of root ng-app which declared the modules I need everywhere and then add specific modules inside specific pages too ?
That means is it possible to do something like this:
<div ng-app="rootApp">
<div ng-app="specificApp">
...
</div>
</div>
The rootApp contains the module that are declared in my template, that are use in all the pages, and the specifiApp contains the modules I need only in one specific page.
Thanks !
[EDIT] Bootstrap attempt:
var reportHolidaysByEmployeeApp = angular.module('reportHolidaysByEmployeeApp', ['fitnetApp', 'ui.bootstrap']);
angular.bootstrap(document.getElementById("reportHolidaysByEmployeeApp"), ['reportHolidaysByEmployeeApp']);
reportHolidaysByEmployeeApp.controller('ReportHolidaysByEmployeeCtrl', function($scope, $filter, $timeout) {
fitnetApp is the global Module I load on the html tag in every page
Only one AngularJS application can be auto-bootstrapped per HTML
document. The first ngApp found in the document will be used to define
the root element to auto-bootstrap as an application. To run multiple
applications in an HTML document you must manually bootstrap them
using angular.bootstrap instead. AngularJS applications cannot be
nested within each other. --
http://docs.angularjs.org/api/ng.directive:ngApp
See also
https://groups.google.com/d/msg/angular/lhbrIG5aBX4/4hYnzq2eGZwJ
http://docs.angularjs.org/api/angular.bootstrap
If you are having separate controllers for your pages[views] , add dependency in your controller module to [rootApp] or [spcificApp] as your page needs.
$routeProvider.when('/view1',{
template:
controller:view1controller
})
if u need rootApp as dependency in view1 page
in your controller module
angular.module('GlobalCtrl',['rootApp'])
.controller('view1controller')
'
You cannot have two ng-app in a single web page.
If you need to add dependency module on specific page use
angular.module('reportHolidaysByEmployeeApp').requires.push('thirdpartymodule');
This will dynamically inject dependency in your already running angular application.

Do native (non-$scope, etc) members of angularjs controller objects do anything?

Learning angularjs, the curve is steep but I can see that it's going somewhere.
Given the following:
var app = angular.module('theApp',[]);
app.controller('Controller1', function($scope) {
var self=this;
$scope.thing = "hi.";
this.thang = "yo.";
$scope.doIt=function(){
return self.thang;
};
});
thing and doIt() are exposed through $scope, but thang is not:
<body ng-app="theApp">
<div ng-controller="Controller1">
<div>{{thing}}</div>
<div>{{thang}}</div>
<div>{{doIt()}}</div>
</div>
</body>
Is there any way to bind or otherwise expose thang? Or is this. completely pointless inside an ngController?
No problem if it is, just trying to get it straight in my head. I'm getting the idea that and ngController only communicates through $scope (and other ng service objects), they aren't independently accessible to other code; and I see that as a basically good thing, within anjularjs.
But it means you have to go all-in with angularjs; legacy/external code has to be wrapped in angularjs services and stuff in order to communicate across an ngController, would that be a fair statement?
I'm using angularjs 1.2.13, does the behavior change across versions?
Is there any way to bind or otherwise expose thang?
It depends how you want it to be exposed. If you want it to be available in the view; you'll have to put it into the $scope.
If you want to share the value with other controllers, you'll probably want to use a service or to store the value.
Or is this. completely pointless inside an ngController?
I consider variables, or methods, not in the $scope to be similar to a protected variable [or method]. Depending what your building their can be uses for that. I would not consider it pointless.
But it means you have to go all-in with angularjs; legacy/external
code has to be wrapped in angularjs services and stuff in order to
communicate across an ngController, would that be a fair statement?
No, it doesn't mean that. For example, I once wrote an app with a login form, and needed to hash the password before calling a remote service. I just Googled and found a JAvaScript hash library; then imported it into the html page (AKA Used the script tag), and was able to access the hash function from within the controller without doing any other work. This is due to the nature of JavaScript and how browsers work.
However, by doing this I added an external dependency into my controller which would make it difficult to write tests against. If I had wrapped the library in an Angular service, then passed it into the controller I would have built a semi-self-documenting API for the controller that could be tested with known dependencies.
So, you don't have to wrap external services in AngularJS. But, you may want to. As long as you understand the trade offs your making, you can make good decisions for your use case. (Just like any 'best practice').
I'm using angularjs 1.2.13, does the behavior change across versions?
All versions of Angular I've used have the same "Controller / Scope / Dependency Injection" approach.
The ng-controller tag can put the controller on the scope. These are equivalent:
<body ng-app="theApp">
<div ng-controller="Controller1 as c">
<div>{{thing}}</div>
<div>{{c.thang}}</div>
<div>{{doIt()}}</div>
</div>
</body>
And:
app.controller('Controller1', function($scope) {
var self=this;
$scope.thing = "hi.";
$scope.c = this;
this.thang = "yo.";
$scope.doIt=function(){
return self.thang;
};
});
Personally I think putting the name in the tag usually makes more sense as the template reads better.
Remember you can also access controllers which aren't on $scope from the link function of a directive. When you do that you refer to the name you gave the controller when you registered it, Controller1 in this case. See the require attribute here: http://docs.angularjs.org/guide/directive

'Stand Alone' Controllers VS modular controllers in angularJS

I am new to angularJS. I have been reading many code examples and I often see controllers defined as:
function MyController($scope) {
//code here
};
I however am using the method below to define my controller, as I wasn't aware there was any other way to do it.
angular.module("csApp.controllers", [])
.controller("main", function ($scope) {
//code here
};
How does the first method work? Is there some sort of naming convention I am missing here?
Are people using the first method simply adding these functions as global variables by placing them in in script files after angular loads?
How would you connect a global variable to a route if the controller is not registered with angularJS?
Thanks!
The AngularJS Dependency Injection framework can always find controller constructor function in global scope as they are global by nature. Even the ng-controller directive has this in its documentation
Name of a globally accessible constructor function or an expression
that on the current scope evaluates to a constructor function.
When using $routeProvider you can provide the route definition a Controller class or a quoted controller name which has been registered using the module api. These two are valid
route :{controller:MainCtrl,...}
route :{controller:'main',...}
The module based approach is preferable because it stops one from polluting the JS global namespace.
You just need to initialize your module, then you can declare your controllers with the two methods.
The first method make it easier and more readable when you have for instance 5 controllers, or if you want to split them in differents files. But they do the same job. All you need to do is keeping track your controller name.
function MainCtrl($scope) {
// do your stuff
}
<!-- Using the function name here -->
<ANY ng-controller="MainCtrl">
<!-- your HTML data -->
</ANY>
More info in the API Doc.

How to run two separate Angular js apps in the same page

New to Angular. I feel like I'm missing something obvious: Shouldn't I easily be able to run to separate AngularJs apps (modules) in the same html page? Something like this:
<section ng-app="HelloWorldApp" ng-controller="HelloWorldController">
Hello {{name}}!
</section>
<br />
<section ng-app="MyNameIsApp" ng-controller="MyNameIsController">
My Name is {{FirstName}} {{LastName}}!
</section>
Javascript:
var HelloWorldApp = angular.module('HelloWorldApp', []);
HelloWorldApp.controller('HelloWorldController', function($scope) {
$scope.name = 'World';
});
var MyNameIsApp = angular.module('MyNameIsApp', []);
MyNameIsApp.controller('MyNameIsController', function($scope) {
$scope.FirstName = 'John';
$scope.LastName = 'Smith';
});
This only runs the first module, while the second doesn't appear to do anything. I want to do this so that I can build reusable, encapsulated directives for multiple pages that don't have to name their modules the same thing.
Live Example: http://plnkr.co/edit/cE6i3ouKz8SeQeA5h3VJ
We ended up building small hierarchy of modules, however my original question can done, with just a bit of work (see below).
It is possible, but it requires a little bit coding by hand. You need to bootstrap the angular apps on your own. Don't worry, it is not that complicated
Do not add ng-app attributes in your HTML
Make sure you can fetch the DOM elements holding the app
When DOM is loaded you need to start the apps on your own: angular.bootstrap( domElement, ['AppName']);
Fork of you plunker which works: http://plnkr.co/edit/c5zWOMoah2jHYhR5Cktp
According to the Angular docs for ngApp:
Use this directive to auto-bootstrap an application. Only one
directive can be used per HTML document. The directive designates the
root of the application and is typically placed at the root of the
page.
Seems it's by design.
You can specify any nested apps in the module def of the main one.
angular.module("myapp", ['statusapp', 'tickerapp']).controller(....
and in a separate file, you have the other apps defined. We're using a template engine which hides some of this, but you'll end up with HTML that contains nested ng-apps and javascript for each one that defines the module/controller. The code above is the trick to getting more than one bootstrapped.

Resources