Adding dependencies to an AngularJS controller - angularjs

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

Related

Why run method of this module isn't run? [duplicate]

I'm trying to add two angular apps / modules to one page.
In the fiddles below you can see that always only the first module, referenced in the html code, will work correctly, whereas the second is not recognized by angular.
In this fiddle we can only execute the doSearch2 method, whereas in this fiddle only the doSearch method works correctly.
I'm looking for the way how to correctly place two angular modules into one 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
I created an alternative directive that doesn't have ngApp's limitations. It's called ngModule. This is what you code would look like when you use it:
<!DOCTYPE html>
<html>
<head>
<script src="angular.js"></script>
<script src="angular.ng-modules.js"></script>
<script>
var moduleA = angular.module("MyModuleA", []);
moduleA.controller("MyControllerA", function($scope) {
$scope.name = "Bob A";
});
var moduleB = angular.module("MyModuleB", []);
moduleB.controller("MyControllerB", function($scope) {
$scope.name = "Steve B";
});
</script>
</head>
<body>
<div ng-modules="MyModuleA, MyModuleB">
<h1>Module A, B</h1>
<div ng-controller="MyControllerA">
{{name}}
</div>
<div ng-controller="MyControllerB">
{{name}}
</div>
</div>
<div ng-module="MyModuleB">
<h1>Just Module B</h1>
<div ng-controller="MyControllerB">
{{name}}
</div>
</div>
</body>
</html>
You can get the source code at:
http://www.simplygoodcode.com/2014/04/angularjs-getting-around-ngapp-limitations-with-ngmodule/
It's essentially the same code used internally by AngularJS without the limitations.
Why do you want to use multiple [ng-app] ? Since Angular is resumed by using modules, you can use an app that use multiple dependencies.
Javascript:
// setter syntax -> initializing other module for demonstration
angular.module('otherModule', []);
angular.module('app', ['otherModule'])
.controller('AppController', function () {
// ...do something
});
// getter syntax
angular.module('otherModule')
.controller('OtherController', function () {
// ...do something
});
HTML:
<div ng-app="app">
<div ng-controller="AppController">...</div>
<div ng-controller="OtherController">...</div>
</div>
EDIT
Keep in mind that if you want to use controller inside controller you have to use the controllerAs syntax, like so:
<div ng-app="app">
<div ng-controller="AppController as app">
<div ng-controller="OtherController as other">...</div>
</div>
</div>
You can bootstrap multiple angular applications, but:
1) You need to manually bootstrap them
2) You should not use "document" as the root, but the node where the angular interface is contained to:
var todoRootNode = jQuery('[ng-controller=TodoController]');
angular.bootstrap(todoRootNode, ['TodoApp']);
This would be safe.
Manual bootstrapping both the modules will work. Look at this
<!-- IN HTML -->
<div id="dvFirst">
<div ng-controller="FirstController">
<p>1: {{ desc }}</p>
</div>
</div>
<div id="dvSecond">
<div ng-controller="SecondController ">
<p>2: {{ desc }}</p>
</div>
</div>
// IN SCRIPT
var dvFirst = document.getElementById('dvFirst');
var dvSecond = document.getElementById('dvSecond');
angular.element(document).ready(function() {
angular.bootstrap(dvFirst, ['firstApp']);
angular.bootstrap(dvSecond, ['secondApp']);
});
Here is the link to the Plunker
http://plnkr.co/edit/1SdZ4QpPfuHtdBjTKJIu?p=preview
NOTE: In html, there is no ng-app. id has been used instead.
I made a POC for an Angular application using multiple modules and router-outlets to nest sub apps in a single page app.
You can get the source code at: https://github.com/AhmedBahet/ng-sub-apps
Hope this will help

How to include Angular ngMessage template

I have quite a big form and was looking at ngMessages. I wanted to implement this:
<script type="text/ng-template" id="error-messages">
<div ng-message="required">This field is required</div>
<div ng-message="minlength">This field is too short</div>
</script>
would I make a factory method? so I could use it across many different controllers? as the project will have many forms in it? I am not sure how to include this in a factory if that is the correct way. This is what I was thinking whether it is right or not.
(function() {
"use strict";
angular.module("minorApp")
.factory("errorMessage", []);
function errorMessage() {
return // some template
}
})();
You can add the template to angular's template cache:
var myApp = angular.module('myApp', []);
myApp.run(function($templateCache) {
$templateCache.put('error-messages.html', '<div ng-message="required">This field is required</div><div ng-message="minlength">This field is too short</div>');
});
Then, reference it in the html documents where you want to include it using ng-include.
<div ng-include src="'error-messages.html'"></div>
If you are using a build system like gulp, you can keep your html in .html files and using the https://www.npmjs.com/package/gulp-angular-templatecache plugin to automate the process of adding them to angular's template cache.

Unable do define a simple controller in AngularJS 1.3.0-rc.4

This works in angularJS 1.2.0. I want to be able to define a simple controller this way.
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
<div ng-app='' ng-controller='ctrl'>
<input type="text" ng-model="data.input"><br>
{{data.input}}
<script>
function ctrl($scope) {
$scope.data = {input:'hejsan'}
}
</script>
</div>
Demo
However, in 1.3.0-rc.4 it doesn't work. Why can't I define a controller this way?
Demo 1.3.0-rc.4
Since Angular v1.3.0-beta defining controller constructors in the global scope is no longer supported.

Multiple angularjs applications for one page [duplicate]

I'm trying to add two angular apps / modules to one page.
In the fiddles below you can see that always only the first module, referenced in the html code, will work correctly, whereas the second is not recognized by angular.
In this fiddle we can only execute the doSearch2 method, whereas in this fiddle only the doSearch method works correctly.
I'm looking for the way how to correctly place two angular modules into one 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
I created an alternative directive that doesn't have ngApp's limitations. It's called ngModule. This is what you code would look like when you use it:
<!DOCTYPE html>
<html>
<head>
<script src="angular.js"></script>
<script src="angular.ng-modules.js"></script>
<script>
var moduleA = angular.module("MyModuleA", []);
moduleA.controller("MyControllerA", function($scope) {
$scope.name = "Bob A";
});
var moduleB = angular.module("MyModuleB", []);
moduleB.controller("MyControllerB", function($scope) {
$scope.name = "Steve B";
});
</script>
</head>
<body>
<div ng-modules="MyModuleA, MyModuleB">
<h1>Module A, B</h1>
<div ng-controller="MyControllerA">
{{name}}
</div>
<div ng-controller="MyControllerB">
{{name}}
</div>
</div>
<div ng-module="MyModuleB">
<h1>Just Module B</h1>
<div ng-controller="MyControllerB">
{{name}}
</div>
</div>
</body>
</html>
You can get the source code at:
http://www.simplygoodcode.com/2014/04/angularjs-getting-around-ngapp-limitations-with-ngmodule/
It's essentially the same code used internally by AngularJS without the limitations.
Why do you want to use multiple [ng-app] ? Since Angular is resumed by using modules, you can use an app that use multiple dependencies.
Javascript:
// setter syntax -> initializing other module for demonstration
angular.module('otherModule', []);
angular.module('app', ['otherModule'])
.controller('AppController', function () {
// ...do something
});
// getter syntax
angular.module('otherModule')
.controller('OtherController', function () {
// ...do something
});
HTML:
<div ng-app="app">
<div ng-controller="AppController">...</div>
<div ng-controller="OtherController">...</div>
</div>
EDIT
Keep in mind that if you want to use controller inside controller you have to use the controllerAs syntax, like so:
<div ng-app="app">
<div ng-controller="AppController as app">
<div ng-controller="OtherController as other">...</div>
</div>
</div>
You can bootstrap multiple angular applications, but:
1) You need to manually bootstrap them
2) You should not use "document" as the root, but the node where the angular interface is contained to:
var todoRootNode = jQuery('[ng-controller=TodoController]');
angular.bootstrap(todoRootNode, ['TodoApp']);
This would be safe.
Manual bootstrapping both the modules will work. Look at this
<!-- IN HTML -->
<div id="dvFirst">
<div ng-controller="FirstController">
<p>1: {{ desc }}</p>
</div>
</div>
<div id="dvSecond">
<div ng-controller="SecondController ">
<p>2: {{ desc }}</p>
</div>
</div>
// IN SCRIPT
var dvFirst = document.getElementById('dvFirst');
var dvSecond = document.getElementById('dvSecond');
angular.element(document).ready(function() {
angular.bootstrap(dvFirst, ['firstApp']);
angular.bootstrap(dvSecond, ['secondApp']);
});
Here is the link to the Plunker
http://plnkr.co/edit/1SdZ4QpPfuHtdBjTKJIu?p=preview
NOTE: In html, there is no ng-app. id has been used instead.
I made a POC for an Angular application using multiple modules and router-outlets to nest sub apps in a single page app.
You can get the source code at: https://github.com/AhmedBahet/ng-sub-apps
Hope this will help

Simple AngularJS running on JSFiddle

How do I make a jsfiddle out of the following code:
<html>
<head>
</head>
<body>
<div ng-app ng-controller="MainCtrl">
<ul>
<li ng-repeat="num in nums">
{{num}}
</li>
</ul>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.js"></script>
<script type="text/javascript" charset="utf-8">
function MainCtrl($scope) {
$scope.nums = ["1","2"];
}
</script>
</body>
</html>
My non working attempt: http://jsfiddle.net/zhon/3DHjg/ shows nothing and has errors.
You need to set some things up in jsFiddle for this to work.
First, on the left panel, under "Frameworks & Extensions", select "No wrap - in <body>".
Now, under "Fiddle Options", change "Body tag" to <body ng-app='myApp'>
In the JS panel, initiate your module:
var app = angular.module('myApp', []);
Check it out: http://jsfiddle.net/VSph2/1/
#pkozlowski.opensource has a nice blog post about how to use jsFiddle to write AngularJS sample programs.
You've defined your controller in a function scope that is not accessible to angular (angular is not yet loaded). In other words you are trying to call angular library's functions and helpers like below example before getting angular library loaded.
function onload(){
function MainCtrl(){}
}
To resolve this, switch your angular load type to be No wrap - in <body> like shown in screenshot.
here is a working example in jsfiddle
Click JAVASCRIPT button, choose angular version and place where u want include loaded script:
Then click HTML button and add ng-app in body tag. Its all:)
I am writing my answer for those who land on this page , I was used to use ng-module directive but in jsfiddle after half an hour I realized that ng-module is not allowed and you see no error , and when changed that ng-module to ng-app fiddle worked very well .I just wanted to share this .And no wrap (body) is required too.
<div ng-app="appX" ng-controller="appCtrl">
<p>{{greeting}}
</p>
</div>
var app=angular.module("appX",[]);
console.log(app);
app.controller("appCtrl",function($scope){
$scope.greeting="Hello World";
});
https://jsfiddle.net/cloudnine/trgrjwf1/7/
Since Angular 1.4.8 has been chosen by JSFiddle as the top option for Angular V1 in its JAVASCRIPT setting panel, more restriction applies: both ng-app and ng-controller should be declared in HTML to make it work.
Sample HTML:
<div ng-app="myApp" ng-controller="myCtrl">
<input type="text" ng-model="sample" placeholder="type something here...">
<span>{{sample}}</span>
</div>
Sample JS:
angular.module('myApp', [])
.controller('myCtrl', function($scope) {});
https://jsfiddle.net/y170uj84/
Also tested with the latest Angular 1.6.4, by setting as External Resource.
For little experiments in angular 5, you can use https://stackblitz.com/.
This site is used in angular documentation to run live demo. For example, https://stackblitz.com/angular/eybymjopmav

Resources