AngularJS controller reference becomes undefined - angularjs

I've just started learning AngularJS and built a small yet simple application, which consists of multiple controllers as shown here:
I have a SiteMaster.html page, inside this page I use ng-view as shown here:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="Scripts/angular.min.js"></script>
<script src="Scripts/angular-route.min.js"></script>
<script src="Scripts/app.js"></script> <!-- Consists of Routing -->
<script src="Templates/Params/paramsController.js"></script>
<title>Angular Routing Tutorial</title>
</head>
<body ng-app="mainApp">
<h1>sitemaster Template</h1>
<div ng-view></div>
</body>
</html>
As you can see the last script tag is the controller for the params page, Ideally I don't want this script tag reference on the SiteMaster instead I would like to place it inside the params.HTML page that way it's only loaded when it's required, now I've moved this script tag from the SiteMaster.Html to the params.Html page as shown here:
<script src="paramsController.js"></script>
<div ng-controller="paramsCtrl">
<h1>
Passed a parameter via url
</h1>
</div>
Yet when I run the project I get the following error:
Error: [ng:areq] http://errors.angularjs.org/1.5.2/ng/areq?p0=paramsCtrl&p1=not%20a%20function%2C%20got%20undefined
So my question is, how do I get this paramsController.js reference to work within the params.html page? instead of having it on the SiteMaster.html page?
Please note, when the paramsController.js is placed inside the SiteMaster.Html page it works as expected.
Any help would be appreciated.
Update
After adding ocLazyLoad I have done the following:
Added the script reference to sitemaster.html
Inside my app.js I have done the following:
var app = angular.module('mainApp', ['ngRoute', "oc.lazyLoad"]);
Inside my paramsController.js I have the following:
angular.module("mainApp").controller('paramsCtrl', function ($scope, $routeParams, $ocLazyLoad) {
console.log($routeParams);
var param1 = $routeParams.page_number;
alert(param1);
});
And now I've hit a road block I'm unsure where or how I go about loading this controller via ocLazyLoad ? I following this documentation : https://oclazyload.readme.io/docs

First of all, your path is wrong. Change
<script src="paramsController.js"></script>
to
<script src="Templates/Params/paramsController.js"></script>
Also, include the following in your <head> section:
<base href="/">
And the second thing, I'm not sure, even that will not work as Angular has already been initialized. So you need to use a library like ocLazyLoaded to dynamically load resources.
Also, consider reading this post https://stackoverflow.com/a/17675432/2405040
Update:
In your params.html
<!-- Remove this line
<script src="paramsController.js"></script>
-->
<div ng-controller="paramsCtrl">
<h1>
Passed a parameter via url
</h1>
</div>
And now modify your $routeProvider configuration:
(From the docs https://oclazyload.readme.io/docs/with-your-router)
$routeProvider.
when('/foo', {
templateUrl: 'Templates/Params/params.html',
resolve: {
loadMyCtrl: ['$ocLazyLoad', function($ocLazyLoad) {
// you can lazy load files for an existing module
return $ocLazyLoad.load('Templates/Params/paramsController.js');
}]
}
})

Related

Controller is not registered error after adding ngRoute `.config`

Controller is not recognizing - AngularJS error
I've a controller defined in controllerPloyee.js called controllerPloyee which was working before i added the ngRoute and made to route. The error that shows is
angular.min.js:127 Error: [$controller:ctrlreg] http://errors.angularjs.org/1.7.8/$controller/ctrlreg?p0=controllerPloyee
I've checked the documentation and another questions with the same error, but doesn't help.
Index.html
<html ng-app="ployee">
<head>
<!--Angular-->
<script src="lib/angular.min.js"></script>
<script src="lib/angular-route.js"></script>
<!--JS-->
<script src="assets/js/moduloPloyee.js"></script>
<!--Controllers-->
<script src="assets/js/controllers/controllerPloyee.js"></script>
<!--Services-->
<script src="services/routeConfig.js"></script>
</head>
<body>
<div ng-view></div>
<div ng-include="'view/footer.html'"></div>
</body>
</html>
routeConfig.js
angular.module('ployee', ['ngRoute']).config(function($routeProvider){
$routeProvider.when('/login', {
templateUrl: "view/login.html",
controller: "controllerPloyee"
}).when('/',{
templateUrl: "view/login.html",
controller: "controllerPloyee"
}).otherwise({redirectTo: "/login"})
})
controllerPloyee.js
angular.module('ployee').controller('controllerPloyee', function($scope){
});
The script that creates the module needs to be placed before the others:
<!--Angular-->
<script src="lib/angular.min.js"></script>
<script src="lib/angular-route.js"></script>
<!-- IMPORTANT needs to be place here -->
<script src="services/routeConfig.js"></script>
<!--JS-->
<script src="assets/js/moduloPloyee.js"></script>
<!--Controllers-->
<script src="assets/js/controllers/controllerPloyee.js"></script>
<!--Services-->
̶<̶s̶c̶r̶i̶p̶t̶ ̶s̶r̶c̶=̶"̶s̶e̶r̶v̶i̶c̶e̶s̶/̶r̶o̶u̶t̶e̶C̶o̶n̶f̶i̶g̶.̶j̶s̶"̶>̶<̶/̶s̶c̶r̶i̶p̶t̶>̶
The statement angular.module('ployee', ['ngRoute']) creates a new module. The statement angular.module('ployee') retrieves the module for further configuration.
When the module is created after the controller script, the controller is lost. This is why the script that creates the module needs to be placed before other scripts which add controllers, services, filters, directives, constants, etc.
A module is a container for your app.
Passing one argument retrieves an existing angular.Module, whereas passing more than one argument creates a new angular.Module.
From the Docs:1
Creation versus Retrieval
Beware that using angular.module('myModule', []) will create the module myModule and overwrite any existing module named myModule. Use angular.module('myModule') to retrieve an existing module.
For more information, see
AngularJS angular.module Function API Reference
AngularJS angular.Module Type API Reference
AngularJS Developer Guide - modules

Issue with Routing and ng-view

I have a problem with my single Page Application. When I start my Project with the keyuser.html as first site(home page) the Table from the connected Database is shown with the Data. When I use the normal home.html as entry Point for my Program, I can click the Hyperlink to my keyuser.html file, the controller does the necessary routing and I am on my keyuser.html site. But here is just the update Button, but not my Table with my Data.
+++++++++ keyuser.html ++++++
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<button onclick="update()">Update</button>
<div id="flexGrid"></div>
</body>
</html>
<script>
var cv = new wijmo.collections.CollectionView();
var flexGrid = new wijmo.grid.FlexGrid('#flexGrid');
flexGrid.itemsSource = cv;
// Get Data
wijmo.httpRequest("/api/Colors", {
success: function (xhr) {
cv.sourceCollection = JSON.parse(xhr.response);
}
});
</script>
++++++++++++ control.js ++++++++++++++
var app = angular.module("myApp", ["ngRoute"]);
app.config(function ($routeProvider) {
$routeProvider
.when("/keyuser", {
templateUrl: "keyuser.html"
});
++++++++++++ home.html ++++++++++++++
<!DOCTYPE html>
<html>
<head>
<script src="http://cdn.wijmo.com/5.latest/controls/wijmo.min.js"></script>
<script src="http://cdn.wijmo.com/5.latest/controls/wijmo.grid.min.js"></script>
</head>
<body>
<div ng-app="myApp">
Stammdaten
<div ng-view></div>
</div>
There are multiple things wrong here.
First of when loading HTML templates with routing the entire template gets loaded into the ng-view element. Which means that in your case the doctype tag, html tag, body tag and all the other tags are loading twice which might break your page.
Secondly when using AngularJS do not write your javascript in script tags, instead start using controllers, directives, componentens and services.
And last, make sure to include the correct AngularJS scripts like angular.js and angular-route.js
In general i highly recommend just going through the basics of AngularJS before proceeding because i feel like you are missing those.

Why won't Angular-ui-router's <templateUrl> work when all my files are hosted in S3 bucket?

I'm building a sample AngularJS single-page application that uses Angular-UI-Router. But instead of the usual setup where the Angular application is served up through a web-server, I am running a server-side application that just serves up the index.html page in response to HTTP requests. All other resources needed are just pointers to my AWS S3 bucket or somewhere else.
I am doing this because I want to pre-populate the tags on the server-side with og:title from my database so that the Facebook scraper sees the proper values (as I discussed here). This can't be done purely on the user's client. That's why I have to jump through these hoops.
So when you curl my endpoint, it responds with the following HTML from my index page:
<!DOCTYPE html>
<html>
<head>
<base href="/">
<meta property="og:title" content="Saqib's Pre-filled OG Title!"/>
</head>
<body ng-app="pangolinApp">
<table>
<tr>
<td><a ui-sref="splash"><button>Splash</button></a></td>
<td><a ui-sref="blue"><button>Blue</button></a></td>
<td><a ui-sref="green"><button>Green</button></a></td>
<td><a ui-sref="red"><button>Red</button></a></td>
</tr>
</table>
<ui-view></ui-view>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/1.0.3/angular-ui-router.min.js"></script>
<script src="http://static.predictagram.com/js/app.js" type="text/javascript"></script>
<script src="http://static.predictagram.com/js/splashController.js" type="text/javascript"></script>
<script src="http://static.predictagram.com/js/blueController.js" type="text/javascript"></script>
<script src="http://static.predictagram.com/js/greenController.js" type="text/javascript"></script>
<script src="http://static.predictagram.com/js/redController.js" type="text/javascript"></script>
</body>
</html>
It renders onto the page as expected. Great:
Here are the ui-router states specified in http://static.predictagram.com/js/app.js:
var app = angular.module("pangolinApp", ["ui.router"]);
app.config(function($stateProvider, $urlRouterProvider, $locationProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('splash', {url:'/', templateUrl : "html/splash.html", controller : "SplashCtrl"})
.state('blue', {url:'/blue', template: '<p>Hello From Blue!!</p> <p>Color = {{color}}</p>', controller : "BlueCtrl"})
.state('green', {url:'/green', templateUrl: 'html/green.html', controller : "GreenCtrl"})
.state('red', {url:'/red', templateUrl: 'html/red.html', controller : "RedCtrl"});
$locationProvider.html5Mode(true);
});
However, the problem is that only the Blue button actually works. The other ones don't. I can see that when you press each button it enters the respective controller (because I have put a console.log line in each one). But only the template specified for the blue state is working.
Clearly this is because the blue state uses template and all the other states uses templateUrl. So I suspect it cannot find the files html/red, html/green. html/splash.html. Maybe they are not being served? I don't know. How can I ensure my AngularJS Single-Page-App can access those html templates??
EDIT:
Here is pic of the structure of my angular application. But it is stored in my S3 bucket. So replace angular_app/ with http://static.predictagram.com/:
When you set templateUrl as: templateUrl: 'html/green.html' you are telling angular, that your templates can be found at that local folder (html).
As you are trying to take the templates from a remote server, you have to get them with absolute routes. For example: templateUrl: 'http://yourserver/templates/green.html'
As it is not meant to work like that, you are going to have CORS errors, you can take a look to this question/answer and it may help you:
How get a template from a remote URL with AngularJS

Angularjs Controller is not working when I place it in a seperate file

I'm creating a sailsJS application and using AngularJS for the front-end.
This is my index.ejs file
<!DOCTYPE html ng-app="myApp">
<head>
<title>Title</title>
<!-- load socket.io, angularjs, filters, special fonts, jquery, bootstrap -->
<!-- Application JavaScript -->
<script src='/js/app.js'></script>
<script src='/js/controllers/indexCtrl.js'></script>
</head>
<body ng-controller="indexController">
<div ui-view></div>
</body>
</html>
and this is my app.js file
var myApp = angular.module('myApp', ['ui.router', 'angular.filter']);
console.log('this is executing');
and this is my indexCtrl.js file
angular.module('myApp').controller('indexController', ['$scope', '$http', function($scope, $http) {
console.log('check if its executing');
}]);
I'm not getting a console log from indexCtrl.js file but I am from the app.js file
This is my folder structure
- Api
- Assets
--> images
--> js
--> controllers
-->indexCtrl.js
--> dependencies
--> directives
--> services
--> app.js
--> styles
--> templates
--> views
- Config
- node_modules
- tasks
- views
-->index.ejs
Something about your opening html tag doesn't feel right. I've never seen the DOCTYPE tag and <html> tag fused together like that. Try something like this instead :
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title>Title</title>
...
...
</html>
A few other things you can check :
In your browser's developper console, check to make sure the request for /js/app.js and /js/controllers/indexCtrl.js went through and didn't return any 404 (Network tab in Chrome and Firefox)
Make sure there are no Javascript errors in the console
Note : the fact that you were seeing the console.log from App.js only means the Javascript file was being downloaded and interpreted, but not necessarily that your Angular app was starting correctly (because the console.log is placed outside of any Angular function).

AngularJS writing an app with no server

I'm trying to write an AngularJS client side only app.
I thought I might be able to load it from chrome by typing in the address bar:
file:///C:/path/to/project//index.html
I also tried to invoke chrome with the flag --allow-file-access-from-files
Unfortunatly nothing happened - just the busy sign on the tab name is working.
Why does is not loading my app?
I'm using the following code:
index.html:
<!doctype html>
<html ng-app="app">
<head>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-route.js"></script>
<script src="app.js"></script>
<title></title>
</head>
<body style="background-color: white;">
<h1>Index</h1>
<a id="link" href="/login">Go to login</a>
<ng-view></ng-view>
</body>
</html>
app.js:
angular.module('app', ['ngRoute']).
config(function($routeProvider) {
$routeProvider.
when('/', {controller: HomeCtrl, templateUrl: 'app.html'}).
when('/login', {controller: LoginCtrl, templateUrl: 'login.html', resolve: function() {}}).
otherwise({redirectTo:'/'});
});
function HomeCtrl($scope) {
$scope.numbers = [1,2,3,4,5];
}
function LoginCtrl($scope) {
}
app.html:
<div ng-controller="HomeCtrl">
<ul ng-repeat="number in numbers" >
<li>{{number}}</li>
</ul>
</div>
Edit:
2 possible solutions:
Close all chrome instances and run from command line: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --allow-file-access-from-files --allow-file-access
Run Firefox which does not have this restriction (Like #GeekBoy mentioned)
As far as I know google chrome does not allow javascripts to be run from file system. But I did a quick google search and found this. Might be useful
Link
On the flipside you can use firefox. Firefox doesn't have such restrictions as far as I know
Try changing the following lines:
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-route.js"></script>
to
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-route.js"></script>
I think since you're using a file-based way to get at index.html, it's assuming the // also points to a local system resource. By specifically indicating http://, it will look at the actual locations.
I know that this is an old question but for anyone that might still be interested, here is a small project that demonstrates how to write an angularjs client-side app. It is a complete AngularJS 1.63 single page application with routing that does not need a web server: https://github.com/jlinoff/aspa-nows.
There were two key challenges to getting it working: getting the the page href references right because of the newly introduced default hash prefix: ! (see aa077e8 for details), and embedding the template HTML code into index.html as ng-template scripts to avoid CORS errors. Once those fixes were made, it worked as expected.
The project README.md explains what needed to be done in detail and the full source code is available.

Resources