Can AngularJS apps / modules contain controllers from other apps / modules? - angularjs

Can I create a module for authentication and then bind to its controllers from a view in another app / module? For example, creating a common LoginController and then have login pages in my other apps that would use this controller? If so, how? I cannot find any examples but the docs make me think this is possible.

Yeah so long as you have a script/module loaded up and set as the dependency of your app used for the ng-app or for manually bootstrapping the app then you can use any of the controllers/providers defined in those modules.
angular.module('A',['B']);
angular.module('B', []).controller('MyController',function($scope){ $scope.doSomething = function(){alert('did something')}});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="A">
<div ng-controller="MyController">
<button ng-click="doSomething()">Do Something</button>
</div>
</div>

You could have multiple modules by that you can separate out your code.
Basically you can create a separate module for your LoginController, like
angular.module('authentication',[])
.controller('LoginController', function($scope){
//code here
});
then you main app module you should add this module
angular.module('app',['authentication']
Then you can use this app module as ng-app or you could bootsrap the same module.

Related

Can't run AngularJS inside Angular 8 using ngUpgrade

I'm trying to run Hybrid Angular application using ngUpgrade from documentation. The problem is that no matter what I'll do AngularJS is just not raising.
When I put Angular and AngularJS together then both application runs.
<body>
<app-root><app-root>
<div ng-app="app"></div>
</body>
but of course this is wrong, Angular should bootstrap AngularJS, so I changed it to:
<body>
<app-root>
<div id="ng-app"></div>
<app-root>
</body>
And in Angular Module I added:
export class AppModule {
constructor(private upgrade: UpgradeModule) { }
ngDoBootstrap() {
this.upgrade.bootstrap(document.getElementById('ng-app'), ['app']);
}
}
But still nothing, I have no idea even how I can investiage it and where the problem may be.
Ok I found issue, I had declared bootstrap inside #NgModule({...})

Module Directive vs. Module Service Injection

I'm looking to sure up my understanding of dependency injection and make sure my understanding is correct. I'm following a course at the moment that takes 2 modules as examples, ngMessage vs. ngResource. Within my app module injection I include ['ngResource', 'ngMessage'].
Within the controller I inject the service $resource (for ngResource).
Then in my view html I can make use of the ngMessages directive $error.
My question is why doesn't ngMessage require any insertion in to the controller? Is it the difference between a service ($resource) vs directive ($error)?
I just want to make sure I'm clear on why ngMessage didn't require any form of injection in to the controller. If my thinking is right, all modules that are injected in to your app will have all directives immediately available in the view, but any services will need to be injected in to the controller.
app.js
var myApp = angular.module('myApp', ['ngResource']);
myApp.controller('mainController', function('$resource') {
console.log($resource)
});
<form name="myForm">
<input type = "text" ng-model="field" name="myField" required minlength="5"/>
<div ng-messages="myForm.myField.$error">
<div ng-message="required">You did not enter a field</div>
<div ng-message ="minlength">The value entered is too short</div>
</div>
</form>
Directive are available at the module level and can be used in any template in the module or module that import the module that declares it.
Services are injected as objects into your controllers for accessing data from them and sharing data between controllers.

Adding dependencies to an AngularJS controller

I have inherited some AngularJS code. It has this
function MainCtrl($scope)
{
// code goes here
};
angular
.module('inspinia')
.controller('MainCtrl', MainCtrl)
Now I want to add a custom controller which combines a datepicker and timepicker into one control. The GitHub project is here and there is a demo Plunk here.
The demo Punk declares its controller as
var app = angular.module('app', ['ui.bootstrap', 'ui.bootstrap.datetimepicker']);
app.controller('MyController', ['$scope', function($scope) {
How do I add that into my existing controller? What is the combined declaration? Preferably one that I can use it with ng-stricti-di on my ng-app.
[Update] here's my best guess, which I can't test until I get home in 10 hours or so. How does it look?
var myApp=angular.module('myApp', ['$scope','ui.bootstrap','ui.bootstrap.datetimepicker']);
myApp.controller('MainCtrl', function($scope)
{
// code goes here, and can use ui.bootstrap and ui.bootstrap.datetimepicker
// which were injected into the app's module
}]);
[Update 2[ When I change it to
angular
.module('inspinia' ['ui.bootstrap', 'ui.bootstrap.datetimepicker'])
.controller('MainCtrl', MainCtrl)
I get
Error: [$injector:nomod] http://errors.angularjs.org/1.5.0/$injector/nomod?p0=undefinedError: [$injector:nomod] http://errors.angularjs.org/1.5.0/$injector/nomod?p0=undefined
Despue index.html having
<script src="js/bootstrap/bootstrap.min.js"></script>
How do I get this project to use ui boostrap and its datepicker?
Please review these steps:
You don't need to inject your $scope in your app declaration just
inject external modules you want to use, for this case:
'ui.bootstrap' and 'ui.bootstrap.datetimepicker'.
angular.module('myApp', ['ui.bootstrap','ui.bootstrap.datetimepicker'])
What is the combined declaration?
Because 'ui.bootstrap.datetimepicker' depends only on 'ui.bootstrap.dateparser' and 'ui.bootstrap.position' but you need also the bootstrap templates and functionality that are included into the ui.bootstrap-tpls.js.
Make sure to include the above files required in you index.html
<link rel="stylesheet" ref="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.1.0/ui-bootstrap-tpls.js"></script>
<!-- make sure you download this file from the github project -->
<script src="datetime-picker.js"></script>
How do I add that into my existing controller?
When you declare your controller this inherit all module dependencies you had declared (injected) for the app, so you don't need to do this again. In your controller you should create an object literal to store the date-time selected for the user and a variable to control when the date-picker is open, like this:
angular.module('myApp').controller('MainCtrl', ['$scope', function($scope) {
$scope.myDatetime = {
dateSelected: new Date(),
isOpen: false
}
}]);
Call the date-time picker directive in your html:
<html ng-app-="myApp">
<head> .... </head>
<body ng-controller="MainCtrl">
<div class="input-group">
<input type="text" class="form-control" datetime-picker="MM/dd/yyyy HH:mm" ng-model="myDatetime.dateSelected" is-open="myDatetime.isOpen" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="myDatetime.isOpen = !myDatetime.isOpen"><i class="fa fa-calendar"></i></button>
</span>
</div>
</body>
</html>
I hope this help you.
Based on your comment under the question, your confusion is with the way the two pieces of code handle their dependency injection. So before I go further, if you haven't read the documentation on dependency injection, then stop right here and go read it. It will have all of your answers and more and it's something you need to know if handling Angular for longer than five minutes.
To answer the specific case you have, the top code you listed uses implicit injection for the controller which works but is not safe for minification nor is it recommended. The code sample you found uses array dependency inject for the controller which is better and safe for minification. The app declaration in the second sample is just standard module dependency injection and shouldn't look any different than what you already have in your application.
So to use the code you found all you have to do is add the correct module dependencies to your app something like:
angular.module('inspinia', ['ui.bootstrap', 'ui.bootstrap.datetimepicker']);
angular.module('inspinia').controller('MainCtrl',MainCtrl);
function MainCtrl($scope) { }
Your controller appears to already have the correct dependencies so it doesn't need to be changed (which is say it doesn't need anything outside of $scope). I used the code from your first example to show how your current code would be updated but ideally you would use the second version of dependency inject for your controller.
The update you have with the error is because the ui.bootstrap module is not part of bootstrap but part of the angular-bootstrap project. You need to include those js in your page.
It would be remiss of me if I didn't go ahead and mention there is a third way to do dependency injection using the $inject service. It is preferred in a number of popular style guides because it is easy to use a task runner to automate. This is arguably the best option to use for this reason.
Here is minimal app, that you will need to use this datepicker
Html:
<body ng-app="inspinia">
<div ng-controller="MainCtrl as ctrl">
<h1>Datepicker Demo</h1>
<div class="row">
<div class="col-md-6">
<p class="input-group">
<input type="text" class="form-control" uib-datepicker-popup ng-model="ctrl.dt" is-open="ctrl.opened" close-text="Close" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="ctrl.open()"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
</div>
</div>
</body>
JavaScript:
(function() {
'use strict';
angular.module('inspinia', ['ui.bootstrap']);
angular.module('inspinia').controller('MainCtrl', MainCtrl);
function MainCtrl() {
this.open = function() {
this.opened = true;
};
this.opened = false;
}
})();
Here I created a plunker for you, so you can try:
http://plnkr.co/edit/jEwT39sKcKtr8jbQa0uc?p=preview

Angular binding for dynamically added html div

Sorry, this seems a duplicated questions, but I tried all answered questions close to my question, with no success.
I am trying to introduce angular.js into a legacy system.
the system is using the .load jquery function to dynamically load div content with a page from an ASP.NET MVC page.
my brief html will look like this
<body ng-app="myApp">
<div ng-controller="myCtrl">
any content...
<div id="dyncontent"> </div>
</div>
and my javascript legacy code looks like
$('#dyncontent').load('/showviewcontent');
I added in the dynamic content, some angular directive and binding instruction
my angular code is like this
var myApp = angular.module('myApp', []);
myApp.controller('myCtrl', function ($scope) {
.....
});
How to make the binding / angular directive works on the newly added content?
You need to manually start the angular module using angular.bootstrap
$('#dyncontent').load('/showviewcontent', function() {
angular.bootstrap(document.getElementById('dyncontent'), ['myApp']);
});

Using a child controller from another module

I've defined a module and made it the main module for my app using the ng-app directive. I added two controllers to the main app using angular.module('myApp').controller(). One of those controllers has page wide scope whereas the other controller is a child controller.
What I'm now trying to do is include a controller that belongs to another module (not the main myApp module), but I can't figure it out. I do not want to globally namespace controllers.
Anyone know how to do this?
Here is what I have so far:
<!doctype html>
<html lang="en" data-ng-app='myApp' data-ng-controller='myApp.mainController'>
<head>
<meta charset="utf-8">
<title>Untitled</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$(function() {
var app, module;
//create two modules, one of which will be used for the app base
app = angular.module('myApp', []);
module = angular.module('otherModule', []);
//create main controller for main app
app.controller('myApp.mainController', function($scope) {
$scope.content = 'App main controller content';
});
//create child controller for main app
app.controller('myApp.subController', function($scope) {
$scope.content = 'App sub controller content';
});
//create a controller for the other module
module.controller('othermodule.controller', function($scope) {
$scope.content = 'Other module controller content';
});
});
</script>
</head>
<body>
<!-- output content from main controller from main module: myApp -->
{{content}}
<!-- specify use of main module's child controller and output its content -->
<div data-ng-controller='myApp.subController'>
{{content}}
</div>
<!-- NOT WORKING - ideally should output content from the other module's controller -->
<div data-ng-controller='othermodule.controller'>
{{content}}
</div>
<!-- load angular library -->
<script src="lib/angular/angular.js"></script>
</body>
</html>
This code outputs the following with a JavaScript error essentially saying that the othermodule.controller controller was not found.
App main controller content
App sub controller content
{{content}}
Exact Error:
> Error: Argument 'othermodule.controller' is not a function, got
> undefined
> assertArg#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:1005
> assertArgFn#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:1016
> #http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:4740
> applyDirectivesToNode/nodeLinkFn/<#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:4322
> forEach#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:140
> nodeLinkFn#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:4307
> compositeLinkFn#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:3953
> compositeLinkFn#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:3956
> nodeLinkFn#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:4338
> compositeLinkFn#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:3953
> publicLinkFn#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:3858
> bootstrap/</<#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:964
> Scope.prototype.$eval#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:7993
> Scope.prototype.$apply#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:8073
> bootstrap/<#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:962
> invoke#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:2843
> bootstrap#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:961
> angularInit#http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:936
> #http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js:14729
> b.Callbacks/c#http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js:3
> b.Callbacks/p.fireWith#http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js:3
> .ready#http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js:3
> H#http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js:3
>
> http://localhost/sandbox/angular/apptemplate/lib/angular/angular.js
> Line 5687
What you have done currently is "declared" two modules app and module.
When angular bootstraps, you have asked it to bootstrap with app. So now your application bootstraps with app but the app has no reference to your other module ( which is module! ).
So, you will have to either bootstrap your application with app and specify a dependency on module or bootstrap your application with a totally new module and specify a dependency on app and module.
This is how you define a dependency
angular.module('app',['module']);
If you want to create a totally new module and specify both as dependencies
angular.module('myApp',['app','module'])
Note : if you create a totally new module, you will have to bootstrap your angular application with this new module..
<html ng-app="myApp"...

Resources