I have done this when the service and controller are in a single file (usually, app.js) and it works without any issues.
Now, I have the controllers and services organized in different files and the respective folders. I need to inject 1 particular service in a controller but I am running into an error.
This is a simple angular app that I am working on that has a way to manage your YouTube favorite videos. I am getting the error on the add page. Just click on add button to see the error.
Equivalent Plunker
Here is what I have so far:
index.html
<!doctype html>
<html ng-app="youtube-favorites">
<head>
<title>My YouTube Favorites</title>
<link rel="stylesheet" type="text/css" href="bower_components/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="css/custom.css" />
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-12" style="border: 1px solid red;">
<div ui-view></div>
</div>
</div>
</div>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
<script src="bower_components/angular-ui-router/release/angular-ui-router.min.js"></script>
<script src="app.js"></script>
<script src="services/add.js"></script>
<script src="controllers/home.js"></script>
<script src="controllers/add.js"></script>
</body>
</html>
app.js
angular.module('youtube-favorites', ['ui.bootstrap', 'ui.router'])
.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
// For any unmatched url, redirect to /home
$urlRouterProvider.otherwise('/home');
// Now set up the states
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'views/home.html',
controller: 'homeController'
})
.state('add', {
url: '/add',
templateUrl: 'views/add.html',
controller: 'addController'
});
}
]);
Controller - add.js
angular.module('youtube-favorites')
.controller('addController', ['$scope', '$log', 'addService',
function($scope, $log, addService) {
$log.info('add');
$scope.addFavorite = function() {
addService.addFavorite($scope.title, $scope.youtubeUrl)
$log.info('title', $scope.title);
$log.info('youtubeUrl', $scope.youtubeUrl);
};
}
]);
Service - add.js
angular.module('youtube-favorites', [])
.service('addService', ['$scope', '$log', '$q', '$window',
function($scope, $log, $q, $window) {
$log.info('add service called');
this.addFavorite = function(title, url) {
$log.info('title', title);
$log.info('url', url);
$window.localStorage.setItem('youtubeFavorites', angular.toJson({
title: title,
url: url
}));
return true;
};
}
]);
View - add.html
<form name="addForm" ng-submit='addFavorite()' novalidate>
<div class="form-group">
<label for="title">Title</label>
<input type="text" name="title" class="form-control" placeholder="Awesome video!" aria-describedby="title" ng-model="title" required />
<!-- <p ng-show="addForm.title.$error.required" class="help-block">Please enter the title.</p> -->
</div>
<div class="form-group">
<label for="youtubeUrl">YouTube <em>embed</em> URL</label>
<input type="text" name="youtubeUrl" class="form-control" placeholder="https://www.youtube.com/embed/someID" aria-describedby="youtubeUrl" ng-model="youtubeUrl" required />
<!-- <p ng-show="addForm.youtubeUrl.$error.required" class="help-block">Please enter the URL.</p> -->
</div>
<div class="form-group">
<button class="btn btn-default grey" type="submit">Submit</button>
</div>
</form>
Here is the error that I am getting:
Pretty sure that I am not injecting the service correctly.
I did try adding the service as a dependency to the app module as per below, but still giving an error.
angular.module('youtube-favorites', ['ui.bootstrap', 'ui.router', 'youtube-favorites.addService'])....
How do I fix this?
In your addService, change this:
angular.module('youtube-favorites', [])
to this:
angular.module('youtube-favorites')
You are effectively creating a new module with the same name when you include the empty [].
Also, you should be passing in $rootScope to your service because $scope is only available to controllers.
You can't inject $scope into a service. You can inject $rootScope, but $scope is a thing that gets injected at the controller level.
Take a look at this stack post for a little more detail.
Related
My dir's structure is like:
---/public
|
---index.html
---shop.html
|
---/js
|
---index.js
---index_controller.js
---/lib
---/css
---/plugins
|
---...
my index.html:
<!doctype html>
<html class="signin no-js" lang="">
<head>
<meta charset="utf-8">
<meta name="description" content="Flat, Clean, Responsive, application admin template built with bootstrap 3">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">
<title>Index</title>
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="css/font-awesome.css">
<link rel="stylesheet" href="css/themify-icons.css">
<link rel="stylesheet" href="css/animate.min.css">
<link rel="stylesheet" href="css/skins/palette.css">
<link rel="stylesheet" href="css/fonts/font.css">
<link rel="stylesheet" href="css/main.css">
<script src="js/lib/angular/angular.js"></script>
<script src="js/lib/angular/angular.min.js"></script>
<script src="js/lib/angular/angular-route.js"></script>
<script src="js/lib/angular/angular-route.min.js"></script>
<script src="js/index_controller.js"></script>
<script src="js/index.js"></script>
<script src="plugins/modernizr.js"></script>
</head>
<body class="bg-primary" ng-app="myApp.index">
<div class="cover" style="background-image: url(img/cover3.jpg)"></div>
<div class="overlay bg-primary"></div>
<div class="center-wrapper">
<div class="center-content">
<div class="row">
<div class="col-xs-10 col-xs-offset-1 col-sm-6 col-sm-offset-3 col-md-4 col-md-offset-4">
<section class="panel bg-white no-b">
<ul class="switcher-dash-action">
<li class="active">Index</li>
</ul>
<div class="p15" ng-controller="IndexCtrl">
<form role="form" >
<div >
<button class="btn btn-primary btn-lg btn-block" ng-click='testRoute()'>
TestRoute
</button>
</div>
</form>
</div>
</section>
<p class="text-center">
Copyright ©
<span id="year" class="mr5"></span>
</p>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var el = document.getElementById("year"),
year = (new Date().getFullYear());
el.innerHTML = year;
</script>
</body>
</html>
And shop.html renders the following: (only for test use):
SHOP
And index_controller.js is :
function IndexCtrl($scope, $http, $location, $route, $window) {
$scope.testRoute = function() {
console.log(">>>TestRoute>>>");
$location.url('/shop');
}
}
function ShopCtrl() {
console.log("ShopCtrl");
}
And index.js:
'use strict';
//Angular-js
var module = angular.module('myApp.index', ['ngRoute']);
module.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/shop', {templateUrl: 'shop.html', controller: ShopCtrl
});
}]);
/*My Controllers*/
module.
controller('IndexCtrl', ['$scope', '$http', '$location', '$route', '$window', IndexCtrl]);
module.
run([
'$rootScope', '$location',
function($rootScope, $location) {
$rootScope.$on('$routeChangeStart', function(event, next, current) {
var nextTemplate = next.templateUrl;
var nextController = next.controller;
console.log("location.path:" + $location.path());
console.log('Template Starting to leave %s to go to %s\n', "", nextTemplate);
console.log('Controller Starting to leave %s to go to %s\n', "", nextController);
});
}
]);
And when I type "http://localhost:6001/index.html" in Chrome's address bar, it renders:
After clicking Test Route button, it changes to:
Only the url address changes, and it seems strange:
"http://localhost:6001/index.html#/shop"
Whereas I need
"http://localhost:6001/shop"
Chrome's console shows:
My problem is: how to render shop.html and how to navigate to /guoguo path properly, using code like:
$routeProvider.when('/shop', {templateUrl: 'shop.html', controller: ShopCtrl
});
I am pretty new to Angular. Maybe I am not thinking in the angularjs approach. Thanks for your points.
It is a mix of issues for your .html# being shown. Try this.
1: Add in the first line of head tags
<head><base href="/">
...
</head>`
2: Use this $locationProvider.html5Mode(true);
app.config(function($routeProvider,$locationProvider){
$routeProvider
.when('/',{
templateUrl: 'views/home.html',
controller:'homeCtrl'
})
.when('/about',{
templateUrl: 'views/about.html',
controller:'aboutCtrl'
})
.otherwise({
redirectTo: '/home'
});
$locationProvider.html5Mode(true);
});
This should remove the # from the page. But in your server make index.html as the default file serving for the path http://localhost:6001/ then it will load http://localhost:6001/index.html as http://localhost:6001/
I finaly get to know that AngularJS is a SPA(Single Page App) based framwork. If I simply jump to another html, the page will load another ng-app, which has no relation to origin app(the bootstrap has been restarted).
What solution I take is to use ng-view inside the index html. It allows to load different ng-view(which is in '<div></div>' from other html file), and config the routeProvider by declaring template url and controller.
I will paste the complete code later, thanks for you all !!!
var routerApp = angular.module('routerApp', ['ui.router','ngResource']);
routerApp.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
// HOME STATES AND NESTED VIEWS
.state('partyDetail', {
url: '/party/:partyID',
templateUrl: 'hello.html',
controller: function($scope, $stateParams, UserFactory) {
$scope.id = $stateParams.partyID;
console.log($stateParams.partyID);
UserFactory.get({}, function (userFactory){
$scope.userdata = userFactory.user;
});
}
});
});
routerApp.controller('chappy',[function(){
var thisOne=this;
thisOne.note=[
{id:1,Name:'emp.json',Status:false},
{id:2,Name:'1',Status:true},
{id:3, Name:'2',Status:false}
];
console.log("I'm in controller");
}]);
routerApp.factory('UserFactory', function ($resource,$stateParams) {
console.log($stateParams.partyID);
return $resource(':Id',{Id: $stateParams.partyID }, {
query: {
method: 'GET',
params: {},
isArray: true
}
})
});
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<!-- CSS (load bootstrap) -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<!-- JS (load angular, ui-router, and our custom js file) -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.7/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.15/angular-ui-router.js" ></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.7/angular-resource.js"></script>
<script src="app.js"></script>
</head>
<!-- apply our angular app to our site -->
<body ng-app="routerApp">
<!-- NAVIGATION -->
<nav class="navbar navbar-inverse" role="navigation" ng-controller="chappy as chappu">
<ul class="nav navbar-nav" ng-repeat="result in chappu.note">
<li><a ui-sref="partyDetail({ partyID: result.Name })" ><span ng-bind="result.Name"></span></a></li>
</ul>
</nav>
<!-- MAIN CONTENT -->
<div class="container">
<!-- THIS IS WHERE WE WILL INJECT OUR CONTENT ============================== -->
<div ui-view></div>
</div>
</body>
</html>
<!--partial html which is needed to be included in the ui-view-->
<!--hello.html-->
<div>
<p > what were you saying <span ng-bind="id"></span></p>
<p ng-repeat="result in userdata">
<span ng-bind="result.subject"></span>
</p>
</div>
I have created Here a DemoApp in which I have dynamically Created The URi according to the data coming from the different Controller
The Programs seems to work fine at the first glance but it has a problem that the $stateparams even After changes but in the URi it remains the same
The issue here is that maybe my not services is getting called again
but I am not been able to encounter this bug
var routerApp = angular.module('routerApp', ['ui.router','ngResource']);
routerApp.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
// HOME STATES AND NESTED VIEWS
.state('partyDetail', {
url: '/party/:partyID',
The Console output clearly indicates that the Uri is same as it fetch the data for the first time
Clearly, either factory is not getting called again or $stateparams is not changing
help is appreciated
I had done some debugging of the code and I have find out since I was directly injecting the $stateparams in the factory that's why it is taking the first value it has attained
to sort it out I have included the id:$stateparams in the get request in the controller and it seemed to work
controller: function($scope, $stateParams, UserFactory) {
$scope.id = $stateParams.partyID;
UserFactory.get({'Id': $stateParams.partyID}, function (userFactory){
$scope.userdata = userFactory.user;
});
}
that's It , It will work like whammy
Im not sure where to place the partials folder holding the html views! I have placed it at the app root folder, in views and in public. Also tried removing the first trailing slash of the templateUrl but nothing. I also have tried(as view loading container):
<div ng-view></div>
<ng-view></ng-view>
<div data-ng-view></div>
<div ng-view=""></div>
<div ng-view="demoApp"></div>
This is just a learning example holding a module with 2 controllers and 2 views.
Here is the SPA(this page renders as rout '/' of a dancer(perl) project):
<!DOCTYPE html>
<html ng-app="demoApp">
<head>
<title><% title %></title>
<link rel="stylesheet" href="/customised_bootstrap/css/bootstrap.css">
<script src="/bower_components/underscore/underscore.js"></script>
<script src="/bower_components/backbone/backbone.js"></script>
<script src="/bower_components/angular/angular.js"></script>
<script src="/bower_components/angular-resource/angular-resource.js"></script>
<script src="/bower_components/angular-route/angular-route.js"></script>
<script src="/bower_components/ng-tasty/ng-tasty-tpls.js"></script>
<script>
//define a module
var demoApp = angular.module('demoApp', ['ngRoute']);
//define routes for our module(each route will have its set of views and controllers)
demoApp.config =(function ($routeProvider) {
$routeProvider
.when('/',
{
controller: 'simpleController1',
templateUrl: '/partials/testAlexView1.html'
})
.when('/testAlexView1',
{
controller: 'simpleController2',
templateUrl: '/partials/testAlexView1.html'
})
.when('/testAlexView2',
{
controller: 'simpleController2',
templateUrl: '/partials/testAlexView2.html'
})
.otherwise({redirectTo: '/partials/testAlexView1.html'});
});
//define a controller within our module 'demoApp'
demoApp.controller('simpleController1', function ($scope) {
$scope.customers = [
{name:'Boris', age:'18'},
{name:'Claudia', age:'28'},
{name:'Carlos', age:'39'},
{name:'Ben', age:'25'}
];
//var stuff ={};
});
demoApp.controller('simpleController2', function ($scope) {
$scope.customers = [
{name:'Alex', age:'18'},
{name:'Albert', age:'28'},
{name:'Anthony', age:'39'},
{name:'Loren', age:'25'}
];
});
</script>
</head>
<body>
<div>
<p>Main page of SPA test</p>
<div ng-view></div>
</div>
</body>
</html>
Here are the two identical views:
testAlexView1.html(testAlexView2.html is the same):
<div>
<input type="text" data-ng-model="name" /> {{ name }}
<br />
<ul>
<li data-ng-repeat="customer in customers | filter:name | orderBy:'age'">
{{customer.name}} - {{customer.age}}
</li>
</ul>
</div>
In the browser inspector, within the div where the view should load, all that appears is(both at root or root#/view.html):
<!-- ngView: -->
Batarang dosn't detect scopes nor modules neither. Thanks for any help!
There appears to be a typo in your config here:
demoApp.config =(function ($routeProvider) {
Instead try:
demoApp.config(function ($routeProvider) {
I have read and tried applying all of the approaches I can find on SO but none of them work.
I just basically want to load a different view once the user logs in:
myApp.controller('LoginCtrl', ['$scope', '$rootScope', '$location', function($scope, $rootScope, $location) {
$scope.Login = function () {
$location.path('/view1');
// $scope.$apply(); <- error when trying this
};
}]);
Nothing happens. If I try $scope.$apply after changing the location then I get the 'action already in progress' error (http://docs.angularjs.org/error/$rootScope:inprog?p0=$apply)
I have also tried $location.url, etc. Can someone please clue me in on what is happening?
Here is my routing config:
angular.module('myApp', [
'ngRoute',
'myApp.filters',
'myApp.services',
'myApp.directives',
'myApp.controllers'
]).
config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/login', {templateUrl: 'views/login.html', controller: 'LoginCtrl' });
$routeProvider.when('/view1', {templateUrl: 'views/partial1.html', controller: 'MyCtrl1'});
$routeProvider.when('/view2', {templateUrl: 'views/partial2.html', controller: 'MyCtrl2'});
$routeProvider.otherwise({redirectTo: '/login'});
}]);
Index File:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title>Foxy Flakes of Steel</title>
<link rel="icon" href="favicon.ico" type="image/x-icon" />
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
<link rel="stylesheet" href="assets/plugins/bootstrap/css/bootstrap.min.css" />
<link rel="stylesheet" href="assets/css/app.css" />
</head>
<body>
<div class="container">
<div class="row" ng-view></div>
</div>
<script src="assets/plugins/jquery/jquery-2.0.3.min.js"></script>
<script src="assets/plugins/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/plugins/angularjs/angular.min.js"></script>
<script src="assets/plugins/angularjs/angular-route.js"></script>
<script src="assets/js/app.js"></script>
<script src="assets/js/services.js"></script>
<script src="assets/js/controllers.js"></script>
<script src="assets/js/filters.js"></script>
<script src="assets/js/directives.js"></script>
</body>
</html>
And here is the login.html view:
<form class="col-md-5 col-md-offset-3">
<div class="rounded-gray">
<div class="row" style="padding: 30px;">
<div class="input-group" style="margin-bottom: 10px;">
<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
<input type="text" placeholder="username" class="form-control" ng-model="username">
</div>
<div class="input-group" style="margin-bottom: 10px;">
<span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
<input type="text" placeholder="password" class="form-control" ng-model="password">
</div>
<div class="row">
Login
</div>
</div>
</div>
</form>
Two tips that I found;
you cannot use $location.path('/view1') during routing is on proress.
it's better to check logged in or not at the level of application stage.
app.run(['$rootScope', '$location', 'Auth', function ($rootScope, $location, Auth) {
$rootScope.$on('$routeChangeStart', function () {
if (!Auth.isLoggedIn()) {
$location.path('/login');
} else {
$location.path('/home');
}
});
}]);
Reference:
1. AngularJS and location.path()
2.
Redirecting to a certain route based on condition
3. AngularJS- Login and Authentication in each route and controller
Your Login link should be a button. The href is overriding your ng-click action.
<button type='button' class='btn btn-primary pull-right' ng-click='Login()'>
Login
</button>
Also, you don't need the semicolon inside ng-click.
(in-line styles are very bad form, btw)
You may use ng-href="#/view1" in your view instead of calling Login method from your controller via ng-click.
I am new to AngularJs.
In app.js I have the following
angular.module('module1', ['module2'])
.config(function($routeProvider) {
$routeProvider
.when('/',
{
controller: 'Controller1',
templateUrl: '/app/module/module1/partials/module1.html'
});
});
My module1 controller
angular.module('module1').controller('Controller1', function($scope) {
$scope.module1Name = "Module1";
});
In module2 folder I have Index.js
angular.module('module2', []).config(function($routeProvider) {
$routeProvider
.when('/test',
{
controller: 'Controller1',
templateUrl: '/app/module/module2/view/test.html'
});
});;
Module2 controller
angular.module('module2').controller('Controller1', function ($scope) {
$scope.module2Name = "Module2";
});
Here is my index.html
<html data-ng-app="module1">
<head>
<meta name="viewport" content="width=device-width" />
<title>Angular</title>
<script src="~/Scripts/angular.min.js"></script>
<script src="~/App/app.js"></script>
<script src="~/App/module/module2/index.js"></script>
<script src="~/App/module/module2/controller/Controller1.js"></script>
<script src="~/App/module/module1/controller/Controller1.js"></script>
</head>
<body>
<div data-ng-view=""></div>
</body>
</html>
and module1.html
<div>
f4b view {{module1Name}}
<br/>
<a data-ng-href="#/test">Test page</a>
</div>
and test.html
<div>
Test view {{module2Name}} <br/>
<a data-ng-href="#/">f4b page</a>
</div>
when I start the application the module1 name is displayed but when I click the link all I see is "Test view" without module2
{{module2Name}} is not displayed...
Can someone tell me what am I doing wrong?
Thank you
Angular's $injector can't disambiguate between controllers that use the same name. One workaround is to manually namespace them:
angular.module('module1').controller('mod1.Controller1',
...
angular.module('module2').controller('mod2.Controller1',
jsfiddle
See also https://groups.google.com/d/topic/angular/SZMFAKfx1Q8/discussion