Angular controller is not a function, got undefined - javascript

I've been learning Angular recently and in the process of creating a new website referenced I created with a tutorial. Following all the steps I was told, for some reason I am getting this error. And strangely, it is showing up as some sort of url. Here's the "error":
http://errors.angularjs.org/1.4.9/ng/areq?p0=PostCtrl&p1=not%20a%20function%2C%20got%20undefined
Removing all the url gibberish leaves PostCtrl not a function got undefined.
I don't understand why, I've looked all over Stack Overflow and all the common errors such as using global scope, not registering the controller, and other common errors don't seem to be the cause. Here is the controller and jade file.
Controller:
var app = angular.module("app", []);
(function() {
var PostCtrl = function ($scope, $log, $location) {
$scope.posts = [];
$scope.post = function (title, content) {
$scope.title = title;
$scope.content = content;
$log.info("Posting article: " + title + "\n" + content);
$scope.posts.push([title, content]);
};
};
app.controller("PostCtrl", ["$scope", "$log", PostCtrl]);
})();
Jade file: (ng-app="app") is inside the layout file, along with all other scripts involving angular.
extends partials/layout
block scripts
script(src="app/controllers/PostCtrl.js")
block content
.body(ng-controller="PostCtrl")
.row
.col-xs-12
form(class="form-horizontal" ng-submit="post(title, content)")
.form-group
label(for="inputTitle" class="col-sm-2 control-label") Title
.col-sm-10
input(type="text" class="form-control" id="inputTitle" placeholder="Title" ng-model="title")
.form-group
label(for="inputContent" class="col-sm-2 control-label") Content
.col-sm-10
textarea(class="form-control" id="inputContent" placeholder="Content" ng-model="content")
.form-group
.col-sm-offset-2.col-sm-10
button(type="submit" class="btn btn-default") Post
hr
.row
.col-xs-12

#FlorianTopf saved the day. I was not including $location as a dependency. New PostCtrl controller:
(function() {
var PostCtrl = function ($scope, $log, $location) {
$scope.posts = [];
$scope.post = function (title, content) {
$scope.title = title;
$scope.content = content;
$log.info("Posting article: " + title + "\n" + content);
$scope.posts.push([title, content]);
};
};
app.controller("PostCtrl", ["$scope", "$log", "$location", PostCtrl]);
})();

You are initiating twice the controller. Remove it from the html .body(ng-controller="PostCtrl")

Related

Unable to update Child controllers scope valriable

Im new to angular js and im not able to figure out how to change the child controller scope variable from parent controller. Here is the code snippet for that:
var mainApp = angular.module("mainApp", []);
var parentCtrl = function($rootScope, $scope, shareService, $log){
shareService.setDetails($scope.pdetails);
}
var mainCtrl1 = function($rootScope, $scope, shareService, $log){
$scope.msg = "Controller 1";
$scope.details = shareService.details;//shareService.details;
}
var mainCtrl2 = function($rootScope, $scope, shareService){
$scope.msg = "Controller 2";
$scope.details = shareService.details;//shareService.details;
}
parentCtrl.$inject = ["$rootScope", "$scope", "shareService", "$log"];
mainCtrl1.$inject = ["$rootScope", "$scope", "shareService", "$log"];
mainCtrl2.$inject = ["$rootScope", "$scope", "shareService", "$log"];
mainApp.controller("parentController", parentCtrl)
.controller("mainController1", mainCtrl1)
.controller("mainController2", mainCtrl2)
.factory("shareService", function(){
var shareData = {
details : "sadfgs detaisdfadsfasdf..",
setDetails: function(value){
this.details = value;
}
};
return shareData;
});
<html>
<head>
<title>Angular JS Views</title>
<script src='lib/angular.js'></script>
<script src='js/mainApp.js'></script>
<script src='js/studentController.js'></script>
</head>
<body ng-app = 'mainApp' ng-controller='parentController' ng-strict-di>
<div ng-controller='mainController1'>
1. Msg : {{msg}}<br/>
Share Details: {{details}}<br/><br/>
</div>
<div ng-controller='mainController2'>
2. Msg : {{msg}}<br/>
Share Details: {{details}}<br/><br/>
</div>
<input type='text' ng-model='pdetails'/>
</body>
</html>
Here is the Plunker link:
https://plnkr.co/edit/hJypukqMmdHSEZMVnkDO?p=preview
In order to change value of child controller from parent controller you can use $broadcast on $scope.
syntax
$scope.$broadcast(event,data);
$broadcast is used to trigger an event(with data) to the child scope from current scope.
In child controller use $on to receive the event(with data).
Here id the code snippet:
app.controller("parentCtrl",function($scope){
$scope.OnClick=function()
{
$scope.$broadcast("senddownward",$scope.messege);
}
});
app.controller("childCtrl",function($scope){
$scope.$on("senddownward",function(event,data)
{
$scope.messege=data;
});
});
In this example I am broadcasting the event on ng-click,you can use some other custom event.like $watch on $scope.
See this example
https://plnkr.co/edit/efZ9wYS2pukE0v4JsNCC?p=preview
P.S. you can change the name of event from senddownward to whatever you want
You can access the parent's scope properties directly due to the scope inheritance:
<div ng-controller='mainController1'>
Share Details: {{pdetails}}
</div>
Your example does not work because the controllers get executed only once before the view is rendered, pdetails is empty at that moment.
To monitor the changes to pdetails, you can use $watch in the child controller:
$scope.$watch('pdetails', function(newVal) {
$scope.details = newVal;
});

AngularJS Error: $interpolate:interr Interpolation Error with $routeParams

I am trying to load dynamic links from the json to into my iframe template. When I load the iframe page, this error pops up. I don't really know why. This is the first time I've seen this error. Here is the code below.
Controller
app.controller('apps', [
'$scope',
'$http',
'contentService',
'gotoService',
'getIndex',
'$routeParams', function($scope, $http, contentService, gotoService, getIndex, $routeParams){
contentService.then(function(data){
$scope.data = data; // access all data
$scope.appsList = $scope.data.appsList; // list of shortcuts
// change url to links
$scope.goTo= function(url){
gotoService.getLink(url);
}
// get index
$scope.getIndex = function(index){
getIndex.current(index);
}
// embed in iframe
$scope.link = function(){
$scope.indexRoute = $routeParams.index;
return $scope.appsList[$scope.indexRoute].url;
}
});
}]);
iframe template
<iframe ng-controller="apps" ng-src="{{link()}}" width="800" height="600">
</iframe>
apps icon template
<div class="apps-background" ng-click="goTo(a.link+'/'+$index); getIndex($index);" ng-style="{'background-image':'url({{a.image}})', 'background-repeat': 'no-repeat', 'background-size': 'cover'}">
You can't have interpolation directive inside a ng-style directive expression, you need to correct it like below.
<div class="apps-background"
ng-click="goTo(a.link+'/'+$index); getIndex($index);"
ng-style="{'background-image': 'url('+ a.image + ')', 'background-repeat': 'no-repeat', 'background-size': 'cover'}">
Similar answer
I fixed the problem. I changed the code in my controller to this and it worked perfectly.
app.controller('apps', [
'$scope',
'$http',
'contentService',
'gotoService',
'getIndex',
'$routeParams',
'$sce', function($scope, $http, contentService, gotoService, getIndex, $routeParams, $sce){
contentService.then(function(data){
$scope.data = data; // access all data
$scope.data = data; // access all data
$scope.appsList = $scope.data.appsList; // list of shortcuts
// change url to links
$scope.goTo= function(url){
gotoService.getLink(url);
}
// get index
$scope.getIndex = function(index){
getIndex.current(index);
}
// embed in iframe
$scope.link = function(){
$scope.indexRoute = $routeParams.index;
return $sce.trustAsResourceUrl($scope.appsList[$scope.indexRoute].url);
}
});
}]);

AngularJS: help registering custom service the right way

Newbie Question
Have been watching this great Angular Beginners course but got stuck in the register process.
Code project (plnkr.co)
index.html
<!DOCTYPE html>
<html ng-app="githubViewer">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
<script src="github.js"></script>
</head>
<body ng-controller="MainController">
<h1>{{message}}</h1>
{{ countdown }}
<form name="searchUser" ng-submit="search(username)">
<input type="search" required placeholder="Username to find" ng-model="username"/>
<input type="submit" value="Search">
</form>
<div ng-include="'userdetails.html'" ng-show="user"> </div>
</body>
</html>
github.js
(function() {
var github = function($http) { // requires the service $http
// Private implementation details //
var gettingUser = function(username) {
return $http.get("https://api.github.com/users/" + username)
.then(function(response) {
return response.data;
});
/* returning the promise that already comes with
the function to perform the data extration
*/
};
var gettingRepos = function(user) {
return $http.get(user.repos_url)
.then(function(response) {
return response.data;
});
/* returning a promise that it will return the data
- so the controller doesn't have to. */
};
// Public API //
return {
gettingUser: gettingUser,
gettingRepos: gettingRepos
};
// returns an object (github service)
};
var module = angular.module("githubViewer");
/* Not creating a module, just getting the reference
to the one created in script.js So no need to list
the dependencies in a list after githubViewer*/
// Register the Service
module.factory("$github", github);
}());
script.js
(function() {
var app = angular.module("githubViewer", []);
var MainController = function(
$scope, $github, $interval, $log,
$anchorScroll, $location) {
var onUserComplete = function(data) {
$scope.user = data;
$github.gettingRepos($scope.user)
.then(onRepos, onError);
};
var onRepos = function(data){
$scope.repos = data;
$anchorScroll( $location.hash("userDetails") );
}
var onError = function(reason) {
$scope.error = "Could not fetch data";
};
var decrementCountdown = function(){
$scope.countdown -= 1;
if($scope.countdown < 1){
$scope.search($scope.username);
}
}
$scope.search = function(username) {
$log.info("Searching for "+ username);
$github.gettingUser(username).then(onUserComplete, onError);
if(countdownIntervalObj){
$interval.cancel(countdownIntervalObj);
$scope.countdown = null;
}
};
var countdownInterval = null;
var startCountdown = function(){
countdownIntervalObj = $interval(decrementCountdown, 1000, $scope.countdown);
}
$scope.username = "angular";
$scope.message = "GitHub Viewer";
$scope.repoSortOrder = "-stargazers_count";
$scope.countdown = 5;
startCountdown();
};
app.controller("MainController",
["$scope", "$http", "$interval", "$log", "$anchorScroll", "$location", "$github", MainController]);
}());
The console keeps saying that the $github.gettingUser is not a function. What am I doing wrong?
Watch out for the order when you inject your dependencies as you are injecting seven but just passing six to the controller in the wrong order. You need to pass $http and put $github at the end.
var MainController = function($scope, $http, $interval, $log, $anchorScroll, $location, $github)
app.controller("MainController", ["$scope", "$http", "$interval", "$log", "$anchorScroll", "$location", "$github", MainController]);
When you inject resources into your controller
app.controller("MainController", ["$scope", "$http", "$interval", "$log", "$anchorScroll", "$location", "$github", MainController]);
order et type must match your controller function declaration
var MainController = function(
$scope, $github, $interval, $log,
$anchorScroll, $location) {
So here what $github contains is the $http module :)
Here is a corrected version of your plunkr
http://plnkr.co/edit/9UyNHDKiXDZAZt8PPEPy?p=preview
However I prefer this syntax, I find it more clear: http://plnkr.co/edit/byhQ7ST8AZlQ6oMYIMeV?p=preview
You should take a look to https://github.com/johnpapa/angular-styleguide
A styleguide were using at work, filled with best practices.
Have fun with angular
because the order of providers are not the same in the array ["scope", "github", etc] with the controller's. your service corresponds to another provider which is minified, even if it is not, it does not matter. you have to pass the injectors in the same order you define in the provider array

AngularJS not displaying scope data

I'm having issues with a dynamically placed template.
My HTML for index.html looks something like this:
<body data-ng-controller="MainController">
<data-ng-include id="outside" src="dynamicTemplate()"></data-ng-include>
</body>
The index.html page displays a template based on a certain condition.
Here is the code for my home.html, which is the default template for index.html.
<span data-ng-bind="message" data-ng-style="messageStyle"></span>
<form data-ng-controller="FormController" data-ng-submit="processForm()">
other form stuff goes here
</form>
My FormController looks something like this:
app.controller("FormController", ['$scope', '$http', '$window', function($scope, $http, $window) {
$scope.message = "";
$scope.processForm = function() {
$scope.message = "Processing form";
$scope.messageStyle = {
"color": "green"
};
// Ajax Logic to process form
.success(function(data) {
$scope.message = data.msg; /* Message never gets updated in the view */
});
};
}]);
The issue here is that the $scope.message never displays any data in the data-ng-bind="message" after the FormController gets called. I think the issue lies with the scope not knowing which controller it belongs to. How can I fix this?

AngularJS: Working directive not called when split to new file

Question: Why isn't my (previously working) AngularJS directive being called after splitting a module into separate files?
Background: I had my postcards module contained in a single file. I am trying, unsuccessfully, to split it. The postcards.factories and postcards.controllers file are working fine. I cannot get the single directive in postcards.directives to function. I have been successful at doing exactly this with a different, far more complex module.
Research: I have read through a couple SO posts, like this one and this one without much luck. Those posts seems to focus on the initial declaration of the module without the required [].
Main Module - postcards
var postcardsApp = angular.module('postcards', ['postcards.directives', 'postcards.factories', 'postcards.controllers']);
postcards.directives
var postcardAppDirectives = angular.module('postcards.directives', ['postcards.controllers']);
postcardAppDirectives.directive('numPostcards', function () {
return {
restrict: "AE",
template: '{{ ctrl.numPostcards }}',
controller: 'postcardDirectiveController as ctrl'
}
});
postcards.controllers
var PostcardsControllers = angular.module('postcards.controllers', ['postcards.factories']);
PostcardsControllers.controller("postcardDirectiveController", ['PostcardFactory',
function (PostcardFactory) {
var _this = this;
PostcardFactory.getNumPostcards().$promise.then(function (data) {
console.log(data);
_this.numPostcards = data['numPostcards'];
});
}]);
// This controller works fine.
PostcardsControllers.controller('PostcardMainController', ['PostcardFactory', function (PostcardFactory) {...}
postcards.factories
// These are retrieving data fine.
var POSTCARD_URL = 'http://' + BASEURL + '/api/v1/postcards/';
var PostcardsFactories = angular.module('postcards.factories', []);
PostcardsFactories.factory('Inbox', ['$resource', function ($resource) {
return $resource(POSTCARD_URL);
}
]);
// More factories pulling data from my API here...
PostcardsFactories.factory('PostcardFactory', ['$http', 'Inbox', 'Sent', 'PostcardDetail', 'NewPostcard', 'UnreadCount', '$q',
function ($http, Inbox, Sent, PostcardDetail, NewPostcard, UnreadCount, $q) {
var PostcardFactory = {}
// Get count of all unread messages sent TO a member
PostcardFactory.getNumPostcards = function () {
return UnreadCount.query()
};
... // Tons of stuff in here
return PostcardFactory
}
Main App var - To show that postcards is included as a dependency
var app = angular.module('mainApp', ['ngResource', 'boat', 'members', 'location', 'trips',
'angular-jwt', 'tools', 'carousel', 'navbar', 'dashboard', 'postcards', 'widgets', 'ui.bootstrap', 'ui.router']);
HTML calling the directive
<li ng-if="navCtrl.isLoggedIn()">
<a ui-sref="dashboard.postcards">
<span class="glyphicon glyphicon-envelope" style="color: dodgerblue"></span>
<span style="margin-left: -3px; margin-top: -15px; background-color: red; opacity: .75;" class="badge">
<num-messages></num-messages>
</span>
</a>
</li>
Included in HTML file
<script src="./static/app/postcards/postcards.js"></script>
<script src="./static/app/postcards/postcards_factories.js"></script>
<script src="./static/app/postcards/postcards_controllers.js"></script>
<script src="./static/app/postcards/postcards_directives.js"></script>
Question Restatement: Why isn't my directive being called?
Additional Question: I don't really grok when I need to include other modules as part of the .module('myModule', [...]) declaration.
Question answered - in the stupidest way possible.
<num-messages></num-messages> was not refactored by a colleague to reflect the directive's name change to numPostcards. I did not check it.
Now being called successfully with <num-postcards></num-postcards>.
Sorry, #Phil.

Categories

Resources