I am following a video tutorial video for Angular JS and started the topic of using a controller as syntax. The example I am working on yields a different result from the one in the tutorial, however. My code (below) outputs the following error:
angular.js:13550 Error: [ng:areq] Argument 'ParentController' is not a function, got undefined
I am confused as to why this is happening since I copied the code verbatim from the tutorial and still get the error while the tutorial's code output seems fine.
HTML
<body>
<div ng-controller="ParentController">
<p>This is the parent: {{ parentMessage }}</p>
<div ng-controller="FirstChild">
<p>My parent is: {{ parentMessage }}</p>
<p>The first child is: {{ firstMessage }}</p>
</div>
<div ng-controller="SecondChild">
<p>My parent is: {{ parentMessage }}</p>
<p>The second child is: {{ secondMessage }}</p>
</div>
</div>
</body>
JS
angular.model('myApp').controller('ParentController', ['$scope', function($scope) {
$scope.parentMessage = 'What she said.';}]);
angular.model('myApp').controller('FirstChild', ['$scope', function($scope) {
$scope.firstMessage = 'I want my mother.';}]);
angular.model('myApp').controller('SecondChild', ['$scope', function($scope) {
$scope.secondMessage = 'I want my father.';}]);
The reason the error is appearing is because the HTML code isn't able to find the ParentController, FirstChild and SecondChild functions as functions in the JS code. The reason this is bothering me is because when I attempt a similar parent/child JS/HTML code pair then the error doesn't appear.
HTML
<body>
<div ng-controller="First">
<input type="text" ng-model="model.name">
<p>This is the first controller: {{model.name}}</p>
</div>
<div ng-controller="Second">
<input type="text" ng-model="model.name">
<p>This is the second controller: {{model.name}}</p>
</div>
</body>
JS
angular.module('myApp').service('SharedService',function(){
return {name: 'Uncle Alvin'};});
angular.module('myApp').controller('First',['$scope', 'SharedService', function($scope, SharedService){
$scope.model = SharedService;}]);
angular.module('myApp').controller('Second',['$scope', 'SharedService', function($scope, SharedService){
$scope.model = SharedService;}]);
I am not convinced that using shared services is the reason the latter pair of code works while the former doesn't. I want to know what is causing the HTML to not recognize the ng-controllers in the first instance and how I should go about modifying the pair to make them recognizable.
I apologize if this post is redundant to another topic that I couldn't find on my own. If it is, feel free to link the most original/helpful posting of this issue.
The reason for controllers not working in the first module is,
(i) Not model it is module
angular.module('myApp')
and it is easy if you dont declare it thrice, declare once and add the controllers.
var myApp= angular.module('myApp', []);
myApp.controller('ParentController', ['$scope', function($scope) {
$scope.parentMessage = 'What she said.';}]);
myApp.controller('FirstChild', ['$scope', function($scope) {
$scope.firstMessage = 'I want my mother.';}]);
myApp.controller('SecondChild', ['$scope', function($scope) {
$scope.secondMessage = 'I want my father.';}]);
Here is a simple example on how to do it.
Took this example from w3schools
First Name:
Last Name:
Full Name: {{firstName + " " + lastName}}
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.firstName = "John";
$scope.lastName = "Doe";
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
First Name: <input type="text" ng-model="firstName"><br>
Last Name: <input type="text" ng-model="lastName"><br>
<br>
Full Name: {{firstName + " " + lastName}}
</div>
Related
I see almost tutorial use anonymous function in AngularJS, instead of normal function, like function name(para1) {}. Please see this link: http://www.w3schools.com/angular/tryit.asp?filename=try_ng_controller_property
I change to normal function, but it cannot work, Please advise. Thanks.
<div ng-app="myApp" ng-controller="personCtrl as main">
First Name: <input type="text" ng-model="firstName"><br>
Last Name: <input type="text" ng-model="lastName"><br>
<br>
Full Name: {{main.fullName()}}
</div>
<script>
var app = angular.module('myApp', []);
app.controller('personCtrl', function($scope) {
$scope.firstName = "John";
$scope.lastName = "Doe";
function fullName() {
return $scope.firstName + " " + $scope.lastName;
};
});
</script>
The idea of $scope is to have an object where all fields and functions are defined on, so that you are able to reference the fields and functions from your template.
When you don't attach the function to $scope it will not be visible for angular to be called. So the contract is that in your controller function, you add everything you need to the $scope object passed by the framework and by doing so, you can later access the fields or call the functions from your template. Everything you reference in directives like ng-model or put into {{ }} will be evaluated by angular, but angular doesn't know what you mean with the expression fullName() as written in your snippet link or fails finding it in the controller when written as main.fullName().
For details on the concept of $scope have a look at the angular docs on scopes.
What you can do (and it is also a good practice) is to declare your function and then (maybe in tha init of the controlelr) assign them to the $scope ..so is more clear when you'll re read it something like:
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="personCtrl">
First Name: <input type="text" ng-model="firstName"><br>
Last Name: <input type="text" ng-model="lastName"><br>
<br>
Full Name: {{fullName()}}
</div>
<script>
var app = angular.module('myApp', []);
app.controller('personCtrl', function($scope) {
$scope.firstName = "John";
$scope.lastName = "Doe";
$scope.fullName = fullName; //<-- here you assign it
function fullName() {
return $scope.firstName + " " + $scope.lastName;
};
});
</script>
</body>
</html>
I have a requirement wherein a single page contains lot of data. All these data are though different but needs to be displayed in one page only (with vertical scroll).
I have made various collapsible divs on my page and they are controlled usig ng-if for avoiding too much of DOM.
Initially for prototype, I had JS logics for all these divs in one controller. However, now I am following a different approach wherein I want one controller for the page and various child controller for the collapsible divs.
I kept one object each for a div in page controller and made several other controller on my main module (app.js). I expect each of them to be child of pageCtrl and as such I should be accessing data for each div in 'pageCtrl`.
However, this is not working. No errors though on consoles, but no divs are visible.
My structure is as:
<body ng-app ="mainModule">
<div ng-controller ="pageCtrl">
<div ng-controller = "collapse1Ctrl" ng-include="collapse1.tpl" ng-if="collapse1reqd">
<div ng-controller = "collapse2Ctrl" ng-include="collapse2.tpl" ng-if="collapse2reqd">
<div ng-controller = "collapse3Ctrl" ng-include="collapse3.tpl" ng-if="collapse3reqd">
<div ng-controller = "collapse4Ctrl" ng-include="collapse4.tpl" ng-if="collapse4reqd">
<div ng-controller = "collapse5Ctrl" ng-include="collapse5.tpl" ng-if="collapse5reqd">
</div>
JS is like:
angular.module("mainModule", []);
angular.module("mainModule").controller("pageCtrl", pageCtrlFn);
angular.module("mainModule").controller("collaspse1Ctrl", collaspse1CtrlFn);
angular.module("mainModule").controller("collaspse2Ctrl", collaspse2CtrlFn);
angular.module("mainModule").controller("collaspse3Ctrl", collaspse3CtrlFn);
angular.module("mainModule").controller("collaspse4Ctrl", collaspse4CtrlFn);
angular.module("mainModule").controller("collaspse5Ctrl", collaspse5CtrlFn);
Rest assured, all templates and conditions are at correct places.
Since my code as such is too large, I am avoiding to post it currently. May be I will post a similar fiddle soon.
But currently I wonder if is there any problem with having such a structure at all ??
Based on the OP's question and the problem's faced here's an example demo on how nested controllers work and how the scope behaves.
HTML looks like
<body ng-app="scopeInheritance">
<div class="spicy">
<div ng-controller="MainController">
<p>Good {{timeOfDay}}, {{name}}!</p>
<p>{{display.showName}} - {{age}} --> New Age - {{display.age}}</p>
<input type="text" ng-model="name">
<button ng-click="resetTime()">CHANGE</button>
<div ng-controller="ChildController">
<p>Good {{timeOfDay}}, {{name}}!</p>
<button ng-click="setTime()">SET</button>
<input type="text" ng-model="display.showName"> Age - {{age}}
<input type="text" ng-model="age">
<button ng-click="setAge()">Change Age</button>
<div ng-controller="GrandChildController">
<p>Good {{timeOfDay}}, {{name}}!</p>
</div>
</div>
</div>
</div>
JS looks like below
(function(angular) {
'use strict';
var myApp = angular.module('scopeInheritance', []);
myApp.controller('MainController', ['$scope', function($scope) {
$scope.timeOfDay = 'morning';
$scope.files ='';
$scope.name = 'Nikki';
$scope.display={};
$scope.display.showName ='Vikram';
$scope.age ='20';
// $scope.display.age ='20';
$scope.resetTime = function(){
$scope.timeOfDay = 'chaged day';
};
}]);
myApp.controller('ChildController', ['$scope', function($scope) {
$scope.name = 'Mattie';
$scope.$parent.timeOfDay ='';
$scope.setTime = function(){
$scope.timeOfDay = 'new day';
};
$scope.setAge = function(){
$scope.display.age ='25';
};
}]);
myApp.controller('GrandChildController', ['$scope', function($scope) {
$scope.timeOfDay = 'evening';
$scope.name = 'Gingerbread Baby';
}]);
})(window.angular);
This example is an extension of Angular Js org nested controllers doc's based example.
Better to wrap all your templates and controllers into components and hide them from outside controller
<component1 ng-if="req1"></component1>
<component2 ng-if="req2"></component2>
<component3 ng-if="req3"></component3>
and use ControllerAs of course.
I can't seem to get the following code to work:
<script>alert(topic);</script> <!-- Outputs: "dynamics" -->
<div ng-include="'content/' + topic + '.html'"></div> <!-- Does not work. -->
I have deduced the variable is the problem as the following code does work:
<div ng-include="'content/' + 'dynamics' + '.html'"></div> <!-- Works. -->
Does anybody know how I can do this?
Update:
Following Steffen's link, I have written the following code, but still no luck:
<script>
alert(topic); // Outputs "dynamics"
var app = angular.module('myapp', []);
app.controller('MainCtrl', ['$scope', '$window', function ($scope, $window) {
$scope.topic = $window.topic;
}]);
</script>
<div ng-app="myapp" ng-controller="MainCtrl" ng-include="'content/' +
topic + '.html'"></div> <!-- Does not work. -->
Thanks.
Based on Steffen's jsfiddle, here is how I passed a JavaScript variable to AngularJS and used it in defining a directory:
<script>
// Create module.
var app = angular.module('app', []);
// Add controller to module.
app.controller('MainCtrl', ['$scope', '$window', function ($scope, $window) {
$scope.topic = $window.topic;
console.log($scope.topic);
}]);
</script>
<div ng-app="app" ng-controller="MainCtrl" ng-include="'content/' +
topic + '.html'"></div> <!-- Works! -->
Many thanks to all for their answers. :)
try this :
<div ng-include="'content/{{topic}}.html'"></div>
In angularjs , scope variable are access in HTML using The double curly brace notation {{ }} .
Try as follows:
<ng-include src="topic"> </ng-include>
Make sure you have define $scope.topic = "whateveryouwant";
-----------OR-----------
You could do it like:
<ng-include src="getTopic()"></ng-include>
Controller:
function AppCtrl ($scope) {
$scope.getTopic= function () {
return 'partials/whatever.html';
}
}
I'm using AngularJS for binding JS variables to my HTML content, and it works fine.
JS
var app = angular.module("Tabs", [])
.controller("TabsController", ['$scope', function($scope){
$scope.events = my_JS_object;
})
HTML
<div>{{events.test}}</div>
It works as long as my_JS_object.test is a simple string, like "Hello World", but once I try to put HTML tag in there, such as Hello <b>World</b> It doesn't use the tags as HTML elements, but as simple text. Which makes sense, only I have no idea how to make the HTML tags work.
As stated by Angular documentation, you can use inbuilt ng-bind-html directive to evaluate model string and insert resulting HTML into element.
Example:
If you have model value like:
$scope.myHTML =
'I am an <code>HTML</code>string with ' +
'links! and other <em>stuff</em>';
Use ng-bind-html like:
<p ng-bind-html="myHTML"></p>
For detailed information go through: https://docs.angularjs.org/api/ng/directive/ngBindHtml
Note: Don't forget to inject ngSanitize service in your app.
You need to use the ngBindHtml directive that properly evaluates the expression and inserts the resulting HTML into the element in a secure way. To do this, you must include a reference to angular-sanitize.js in your HTML and then in your angular module, inject ngSanitize.
Like so
var app = angular.module("Tabs", ['ngSanitize'])
.controller("TabsController", ['$scope', function($scope){
$scope.events = my_JS_object;
})
<div ng-controller="TabsController">
<div ng-bind-html="events.test"></div>
</div>
Here is a full working example:
(function(angular) {
'use strict';
angular.module('bindHtmlExample', ['ngSanitize'])
.controller('ExampleController', ['$scope', function($scope) {
$scope.myHTML = 'Hello This is <b>BOLD<b/>';
}]);
})(window.angular);
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.1/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.1/angular-sanitize.js"></script>
</head>
<body ng-app="bindHtmlExample">
<div ng-controller="ExampleController">
<p ng-bind-html="myHTML"></p>
</div>
</body>
Refer to the official angular documentation for details:
https://docs.angularjs.org/api/ng/directive/ngBindHtml
If you want to insert HTML into page you shouldn't do it this way.
There is sanitize for this task.
For example in your controller:
$scope.trustedHtml = "<b>Hello World</b>"
And in your html:
<div ng-bind-html="trustedHtml "></div>
Always check html if using a user given text before inserting.
Also don't forget to add ngSanitize as dependency while creating controller
It's easier to use transclusion if you want to embed custom HTML into your DOM tree.
angular.module('myApp', [])
.controller('MainCtrl', function ($scope) {
$scope.overwrite = false;
$scope.origin = 'parent controller';
})
.directive('myDirective', function() {
return {
restrict: 'E',
templateUrl: 'my-directive.html',
scope: {},
transclude: true,
link: function (scope) {
scope.overwrite = !!scope.origin;
scope.origin = 'link function';
}
};
});
<script src="https://code.angularjs.org/1.3.2/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MainCtrl">
<my-directive>
<p>HTML template</p>
<p>Scope from {{origin}}</p>
<p>Overwritten? {{overwrite}}</p>
</my-directive>
</div>
<script type="text/ng-template" id="my-directive.html">
<ng-transclude></ng-transclude>
<hr />
<p>Directive template</p>
<p>Scope from {{origin}}</p>
<p>Overwritten? {{overwrite}}</p>
</script>
</div>
I've been reading the angularjs tutorials on tutorialspoint.com and I've been testing things that I learn on jsfiddle. The first few things I tried worked, like ng-model and ng-bind. But this was all with an empty ng-app (ng-app="").
However, now I'm trying to make an app and a controller, but its not working. Heres the fiddle
How do I fix this code? I've done exactly as the tutorial says. I just noticed when inspecting the page I get the following error:
Error: [$injector:modulerr] Failed to instantiate module myapp due to:
[$injector:nomod] Module 'myapp' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
<div ng-app="myapp" ng-controller="appController">
<div>
<span>First</span>
<input type='text' ng-model="person.firstname"/>
<span ng-bind="person.firstname"></span>
</div>
<div>
<span>Last</span>
<input type='text' ng-model="person.lastname"/>
<span ng-bind="person.lastname"></span>
</div>
<div> {{ person.fullname() }} </div>
</div>
var myapp = angular.module("myapp", []);
myapp.controller('appController', function($scope) {
$scope.person = {
firstname: "one",
lastname: "two",
fullname: function() {
var personobject;
personobject = $scope.person;
return personobject.firstname + " " + personobject.lastname;
}
};
});
Under the Frameworks and Settings change the thing that says onLoad to no wrap - in <head> or no wrap - in <body>