So i still new to angular and java script but i read it was good practical to wrap the everything into functions.
This is what i have done.
in comment is the previous version
app.js
//var app = angular.module('app',['ngRoute','ngResource','routes']);
(function(angular) {
angular.module("app.directives", []);
angular.module("app.controllers", []);
angular.module("app", ['ngRoute','ngResource','routes','app.directives','app.controllers']);
}(angular));
directives.js
/*
app.directive('footer', function () {
return {
replace: true,
templateUrl: "/template/main_footer.html",
controller: ['$scope', '$filter', function ($scope, $filter) {
}]
}
});
*/
(function(angular) {
var footer = function () {
return {
replace: true,
templateUrl: "/template/main_footer.html",
controller: ['$scope', '$filter', function ($scope, $filter) {
}]
};
};
footer.$inject = [];
angular.module("app.directives").controller("footer", footer);
});
controller.js
/*app.controller('HeaderController',function($scope, $location) {
$scope.isActive = function (viewLocation) {
var active = (viewLocation === $location.path());
return active;
};
});*/
(function(angular) {
var HeaderController = function($scope,$location){
$scope.isActive = function(viewLocation){
var active = (viewLocation === $location.path());
return active;
};
}
HeaderController.$inject = ['$scope','$location'];
angular.module("app.controllers").controller("HeaderController", HeaderController);
})
and how should i proceed for routes.js
angular.module('routes', []).config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'pages/home.html'
})
.when('/second', {
templateUrl: 'pages/second.html'
})
.when('/third', {
templateUrl: 'pages/third.html'
})
.when('/123', {
templateUrl: 'pages/123.html'
})
.otherwise({
redirectTo: '/'
});
});
index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/custom.css">
<script type="text/javascript" src="https://code.angularjs.org/1.4.4/angular.js"></script>
<script type="text/javascript" src="https://code.angularjs.org/1.4.4/angular-resource.js"></script>
<script type="text/javascript" src="https://code.angularjs.org/1.4.4/angular-route.js"></script>
<script type="text/javascript" src="js/routes.js"></script>
<script type="text/javascript" src="js/app.js"></script>
<script type="text/javascript" src="js/controllers.js"></script>
<script type="text/javascript" src="js/directives.js"></script>
</head>
<body>
<div ng-view></div>
</body>
</html>
But it does not work. And i find it hard to find what went wrong because i don't get a error with the development tools on google chrome
Update
Now i do call the function at the end.
But i still can't see the footer. I also added the footer.html just in case there would something i forgot there.
directives.js
(function(angular) {
var footer = function () {
return {
replace: true,
templateUrl: "/template/main_footer.html",
controller: ['$scope', '$filter', function ($scope, $filter) {
}]
};
};
footer.$inject = [];
angular.module("app.directives").controller("footer", footer);
}(angular));
home.html
<div>
<div>
<h3>This is the homepage</h3>
</div>
<div footer></div>
</div>
In the 'directives.js' and 'controller.js' files, you forgot (angular) at the end, like in 'app.js'.
If you write a function like this:
function f() {
// do stuff...
}
it's never going to run unless you call it somewhere: f();. Now, if you want to wrap a bit of code in a function, you still want it to run immediately as if it had not been wrapped. So what you do is you call the wrapping function immediately like this:
(function f() {
// do stuff...
})();
or like this (same thing):
(function f() {
// do stuff...
}());
In that second way of writing things, the outermost parentheses are useless for the program but they help the reader see that the function will be immediately run (or "evaluated", or "called").
You can also pass anything that lives outside of the function into the function, for example angular:
(function f(angular) {
// do stuff...
}(angular));
That is because you're missing the function invocation in some of those wrappings. For example, controller.js needs to be:
(function(angular) {
var HeaderController = function($scope,$location){
$scope.isActive = function(viewLocation){
var active = (viewLocation === $location.path());
return active;
};
}
HeaderController.$inject = ['$scope','$location'];
angular.module("app.controllers").controller("HeaderController", HeaderController);
})(angular); // CALL FUNCTION
Note in the last line I added (angular); to actually call the function.
Related
I'm trying to inject my factory into a controller. If I list the factory as one of the controller's parameters, I get this error:
Error: [$injector:unpr] Unknown provider: wordRushFacProvider <- wordRushFac <- wordrushCtrl
http://errors.angularjs.org/1.6.1/$injector/unpr?p0=wordRushFacProvider%20%3C-%20wordRushFac%20%3C-%20wordrushCtrl
Here is the code for my factory:
(function() {
"use strict";
angular
.module("wordrush")
.factory("wordRushFac", function($http) {
function getValidWords() {
return $http.get('../data/valid-words.txt');
}
return {
getValidWords : getValidWords
}
})
})
And the code for my controller:
(function() {
'use strict'
angular
.module('wordrush')
.controller('wordrushCtrl', function($scope, $http, wordRushFac) {
wordRushFac.getValidWords().then(function(words) {
$scope.words = words.data;
});
$scope.words = 'Hello'
});
})();
And for my index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Word Rush</title>
<link rel="stylesheet" href="node_modules/angular-material/angular-material.css">
<link rel="stylesheet" type="text/css" href="css/style.css">
<script src="node_modules/angular/angular.js"></script>
<script src="scripts/app.js"></script>
<script src="components/wordrush.ctr.js"></script>
<script src="components/wordrush.fac.js"></script>
</head>
<body ng-app="wordrush" ng-controller="wordrushCtrl">
<h1> {{ words }} </h1>
</body>
</html>
And for my app.js:
angular
.module('wordrush', ['ngMaterial'])
.config(function($mdThemingProvider) {
$mdThemingProvider.theme('default')
.primaryPalette('blue')
.accentPalette('green');
})
I made a program with code identical to this except the names and variables were changed, and it worked fine. So what am I doing wrong here?
Here is a plunkr that says "Hello": https://plnkr.co/edit/MyxcXQ8YI4QYqeFsyVJz?p=preview
You have an extra set of open / close parenthesis in your controller definition, remove those:
angular
.module('wordrush')
.controller('wordrushCtrl', function($scope, $http, wordRushFac) {
wordRushFac.getValidWords().then(function(words) {
$scope.words = words.data;
});
$scope.words = 'Hello'
});
Also, are you sure you are including the ng-material JS file? I didn't see that listed in your HTML.
You're not injecting in the controller, should be:
.controller('wordrushCtrl', ['$scope', '$http', 'wordRushFac', function($scope, $http, wordRushFac) {
// Rest of controller code;
}]);
Switch your scripts. Factory script should be first then controller
Ther order should be,
<script src="scripts/app.js"></script>
<script src="components/wordrush.fac.js"></script>
<script src="components/wordrush.ctr.js"></script>
DEMO
I made the following changes and it worked fine.
(function() {
"use strict";
angular
.module("wordrush")
.factory("wordRushFac", function($http) {
function getValidWords() {
return $http.get('../data/valid-words.txt');
};
return {
getValidWords : getValidWords
};
});
}());
I am trying to use a resolve to front-load data from Rates Service in my Controller (rates controller) and get a blank screen. The api works but for some reason when I go step by step, in the execution, it skips over the $http.get method within the service :-/. Does anyone have any suggestions on how to fix this? Cheers!
rates.contoller.js
(function () {
'use strict';
angular.module('print.module').controller('ratesCtrl', ['ratesTest123', function (ratesTest123) {
console.log(ratesTest123);
}]
)})();
rates.service.js
(function () {
'use strict';
angular.module('print.module').service('ratesService', ['$http', function ($http) {
vm = this;
function getRatesDataService() {
console.log("test");
return this.$http.get("api/Rates/GetRates");
}
//}
}]
)
})();
print.module.js
(function () {
"use strict";
var module = angular.module('print.module', [
'ui.router',
]);
module.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
$urlRouterProvider.otherwise('/print');
$stateProvider
.state('print', {
url: '/print',
templateUrl: "Public/scripts/sharedViews/printNavbar.html"
})
.state('print.rates', {
url: "/rates",
controller: 'ratesCtrl',
templateUrl: "Public/scripts/rates/rates.view.html",
controllerAs: 'vm',
resolve: {
ratesTest123: ['ratesService', '$q', function (ratesService, $q) {
var deferred = $q.defer();
ratesService.getRatesDataService().then(function (response) {
deferred.resolve(response.data);
});
return deferred.promise;
}]
}
})
$locationProvider.html5Mode(true);
});
}());
view (scripts tags only for reference)
<body ng-app="print.module">
<div ui-view></div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.1/angular-ui-router.min.js"></script>
<script type="text/javascript" src="~/public/scripts/print.module.js"></script>
<script type="text/javascript" src="~/public/scripts/books/books.controller.js"></script>
<script type="text/javascript" src="~/public/scripts/terms/terms.controller.js"></script>
<script type="text/javascript" src="~/public/scripts/rates/rates.service.js"></script>
<script type="text/javascript" src="~/public/scripts/rates/rates.controller.js"></script>
<script type="text/javascript" src="~/public/scripts/services/modals.service.js"></script>
</body>
Assign the getRatesDataService function to your service
(function () {
'use strict';
angular.module('print.module').service('ratesService', ['$http', function ($http) {
this.getRatesDataService = function () {
console.log("test");
return $http.get("api/Rates/GetRates");
}
//}
}]
)
} )();
since it returns a promise, you can simply do the following
resolve: {
ratesTest123: ['ratesService', function (ratesService) {
return ratesService.getRatesDataService()
}]
}
var myApp = angular.module("MyApp", ['ngRoute']);
myApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'partials/cart.php',
controller: 'ctrl',
resolve: {
categories: function(cartService){
console.log('inside resolve categories')
return cartService.getCategories();
}
}
}).
otherwise({
redirectTo: '/'
});
}]);
myApp.controller('ctrl', function (categories, $scope) {
$scope.items = categories;
});
myApp.service("cartService", function ($http, $q) {
this.getCategories = function () {
var deferred = $q.defer();
$http.get('js/categories.js')
.then(function (response) {
deferred.resolve(response.data);
});
return deferred.promise;
}
});
myApp.run(['$rootScope',function($rootScope){
$rootScope.stateIsLoading = false;
$rootScope.$on('$routeChangeStart', function(e, current, pre) {
$rootScope.stateIsLoading = true;
var fullRoute = current.$$route.originalPath;
if(fullRoute == '/')
{
console.log('load categoreis and products')
}
});
$rootScope.$on('$routeChangeSuccess', function() {
$rootScope.stateIsLoading = false;
console.log('route changed');
});
$rootScope.$on('$routeChangeError', function() {
//catch error
});
}]);
I have placed the ng-app and ng-controller directives at the top of the HTML
<html lang="en" ng-app="MyApp" ng-controller="ctrl">
But when I run the HTML I get the following error
Error: [$injector:unpr] Unknown provider: categoriesProvider <-
categories <- ctrl
How can I fix this ?
Edit: If I remove ng-controller="ctrl" from the HTML, then no errors
You got that error just because, you are using the same controller for both index.php and 'partials/cart.php'
Create a separate controller for 'partials/cart.php' to resolve this
problem
Code Snippet:
// Code goes here
var app = angular.module('app', ['ngRoute']);
app.controller('indexCtrl', function($scope) {
$scope.title = 'Header';
});
app.config(function($routeProvider) {
$routeProvider.when('/', {
template: "<ul><li ng-repeat='item in items'>{{item}}</li></ul>",
controller: 'categoryCtrl',
resolve: {
categories: function(cartService){
return cartService.getCategories();
}
}
});
});
app.controller('categoryCtrl', function (categories, $scope) {
$scope.items = categories;
});
app.service("cartService", function() {
this.getCategories = function() {
return ['A', 'B', 'C'];
};
});
<html ng-app="app">
<head>
<script data-require="angular.js#1.4.9" data-semver="1.4.9" src="https://code.angularjs.org/1.4.9/angular.js"></script>
<script data-require="angular-route#1.4.2" data-semver="1.4.2" src="https://code.angularjs.org/1.4.2/angular-route.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="indexCtrl">
<h1>{{title}}</h1>
<div ng-view></div>
</body>
</html>
you have to define the categories service/factory which is injected in your controller 'ctrl'.
I have a loading div that I'd like to share across several controllers. Is there a way to accomplish this without placing this template in every other template?
For example:
<div ng-show="loading" class="loading">Loading</div>
Now in my controller I turn this off and on my using $scope.loading = true/false.
In my main page I use this:
<div class="container" ng-app="myApp">
<div ng-view>
</div>
</div>
I'm using routing so, right now I have to place the loading div in each template that is called by the router so it is inserted in ng-view. All I want is one location for the loading div. How do I accomplish this?
Set up the loading div as a custom directive, check out this example from the angularjs documentation:
angular.module('docsSimpleDirective', [])
.controller('Controller', ['$scope', function($scope) {
$scope.customer = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
}])
.directive('myCustomer', function() {
return {
template: 'Name: {{customer.name}} Address: {{customer.address}}'
};
});
http://plnkr.co/edit/?p=preview
There's quite a few ways to do this.
What I've come up with is to use a service to register an AppController callback. Then in each of my page's controllers I inject that service, and call the callback with true/false.
The full code is below, but the main lines to focus on is:
myApp.service('LoadingService', function() {
var controllerCallback = function() {};
this.setControllerCallback = function(callback) {
controllerCallback = callback;
};
this.setLoading = function(bool) {
controllerCallback(bool);
};
});
And in your AppController:
LoadingService.setControllerCallback(function(bool) {
$scope.loading = bool;
});
Then to show the loading div, just inject that service into a controller and call
LoadingService.setLoading(true) //or false
This allows for the service to be reused in any controller that needs to toggle the loading div.
// Code goes here
var myApp = angular.module('app', ['ngRoute']);
myApp.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/page1', {
templateUrl: 'page1.html',
controller: 'PageOneController'
})
.when('/page2', {
templateUrl: 'page2.html',
controller: 'PageTwoController'
})
});
myApp.controller('AppController', function($scope, LoadingService) {
$scope.loading = false;
LoadingService.setControllerCallback(function(bool) {
$scope.loading = bool;
});
});
myApp.controller('PageOneController', function($timeout, LoadingService) {
LoadingService.setLoading(true);
$timeout(function() {
LoadingService.setLoading(false);
}, 2000);
});
myApp.controller('PageTwoController', function($timeout, LoadingService) {
LoadingService.setLoading(true);
$timeout(function() {
LoadingService.setLoading(false);
}, 3000);
});
myApp.service('LoadingService', function() {
var controllerCallback = function() {};
this.setControllerCallback = function(callback) {
controllerCallback = callback;
};
this.setLoading = function(bool) {
controllerCallback(bool);
};
});
<!DOCTYPE html>
<html ng-app="app">
<head>
</head>
<body ng-controller="AppController">
<h1>Title</h1>
Page 1
Page 2
<div ng-if="loading">Loading...</div>
<div ng-view></div>
<script src="https://code.angularjs.org/1.4.3/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.3/angular-route.min.js"></script>
<script type="text/ng-template" id="page1.html">
<div>You're on page one</div>
</script>
<script type="text/ng-template" id="page2.html">
<div>You're on page two</div>
</script>
</body>
</html>
Here is the sample (from Angular official site):
angular.module('project', ['ngRoute', 'firebase']).
value('fbURL', 'https://angularjs-projects.firebaseio.com/').
factory('Projects', function(angularFireCollection, fbURL) {
return angularFireCollection(fbURL);
}).
config(function($routeProvider) {
$routeProvider.
when('/', {controller:ListCtrl, templateUrl:'list.html'}).
when('/edit/:projectId', {controller:EditCtrl, templateUrl:'detail.html'}).
when('/new', {controller:CreateCtrl, templateUrl:'detail.html'}).
otherwise({redirectTo:'/'});
});
function ListCtrl($scope, Projects) {
$scope.projects = Projects;
}
function CreateCtrl($scope, $location, $timeout, Projects) {
$scope.save = function() {
Projects.add($scope.project, function() {
$timeout(function() { $location.path('/'); });
});
}
}
function EditCtrl($scope, $location, $routeParams, angularFire, fbURL) {
angularFire(fbURL + $routeParams.projectId, $scope, 'remote', {}).
then(function() {
$scope.project = angular.copy($scope.remote);
$scope.project.$id = $routeParams.projectId;
$scope.isClean = function() {
return angular.equals($scope.remote, $scope.project);
}
$scope.destroy = function() {
$scope.remote = null;
$location.path('/');
};
$scope.save = function() {
$scope.remote = angular.copy($scope.project);
$location.path('/');
};
});
}
Link: http://jsfiddle.net/TE2WR/
Firefox console shows:
[01:45:20.760] Error: [$injector:modulerr] http://errors.angularjs.org/undefined/$injector/modulerr?p0=project&p1=%5B%24injector%[...]
What's going on?
Edit:
My HTML scripts:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular-resource.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular-route.min.js"></script>
<script src="https://cdn.firebase.com/v0/firebase.js"></script>
<script src="http://firebase.github.io/angularFire/angularFire.js"></script>
Be sure to include ngRoute and firebase scripts so that they are available to inject as dependencies.
For example, include ngRoute like this:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
<script src="http://code.angularjs.org/1.2.0-rc.2/angular-route.min.js"></script>
angular.module('project', ['ngRoute']).
config(function($routeProvider) {
});
You missed angular-route.js and firebase.js and angularfire.js in jsfiddle.
This would work
</style> <!-- Ugly Hack due to jsFiddle issue: http://goo.gl/BUfGZ -->
<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular-route.min.js"></script>
<script src="https://cdn.firebase.com/v0/firebase.js"></script>
<script src="https://rawgithub.com/firebase/angularFire/master/angularfire.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular-resource.min.js"></script>
<style>