angularJS, after injecting service, it still reports unknow provider - angularjs

I have injected the new service into my controller, but it always says unknown provider
my code:
export service:
class AlertService {
constructor($rootScope,$injector) {
this.rootScope = $rootScope;
this.injector = $injector;
}
showAlert(alertTitle='Alert',alertBody='') {
this.injector.get('$uibModal').open({
template: '<header><div class="alert-header"><h1>' + alertTitle + '</h1></div><div class="alert-close" ng-click="ok()"><i class="icon icon--close" aria-hidden="true"></i></div></header>'
+ '<section class="content-section content-section-alert"><p>' + alertBody + '</p></section>'
+ '<footer><button class="btn btn-primary" ng-click="ok()">ok</button>',
controller: function($scope, $uibModalInstance,$rootScope) {
$rootScope.ok = function() {
$uibModalInstance.dismiss('cancel');
};
},
windowClass: 'alert-modal'
});
}
}
AlertService.$inject = ['$rootScope','$injector'];
export default angular.module('services.alertService', [])
.service('alertService', AlertService)
.name;
inject the service into controller:
export default class StartController {
constructor($scope, alertService, $location){
this.alertService = alertService
this.scope = $scope
this.location = $location
this.watchUrl()
}
watchUrl() {
let url = this.location.url()
if(url.indexOf('start') == -1)
return
this.alertService.showAlert('alert','some error')
}
}
StartController.$inject = ['$scope', 'alertService', '$location'];
it would always report unknown provider:
Unknown provider: tProvider <- t
if I change the alertService to alert(), then it works
what would be the reason? thanks

You haven't provided dependency injection annotations for the modal's controller
controller: function($scope, $uibModalInstance, $rootScope) { ... }
Either extract it to a function or class so you can set the $inject property or use the array annotation, eg
controller: ['$scope', '$uibModalInstance', '$rootScope',
function($scope, $uibModalInstance, $rootScope) { ... }]

Related

Unknown provider: DashboardServiceProvider <- DashboardService <- DashboardController

even if I read a lot of solutions according my problem, still to have this Error.
This is my Controller:
#Controller
#RequestMapping( "/dashboard" )
public class DashboardController {
#RequestMapping( value = "", method = RequestMethod.GET )
public HttpEntity<String> dashboard() {
SimpleDateFormat sdf = new SimpleDateFormat( "dd-MM-yyyy" );
return new HttpEntity<String>( "Today is " + sdf.format( new Date() ) );
}
}
this is my index.jsp
<body ng-app="dashboard">
<div ng-controller="DashboardController">
<p>Nome: <input type="text" ng-model="nome"></p>
<p>Cognome: <input type="text" ng-model="cognome"></p>
<input type="button" value="LOGIN" ng-click="login()"/>
</div>
<jsp:include page="includes.jsp"></jsp:include>
<div ng-show="value==1">
{{data}}
</div>
<div ng-show="value==0">
{{ResponseDetails}}
</div>
</body>
this is my module
var Dashboard = angular.module( 'dashboard', ['DashboardService'] )
.config(['$routeProvider', '$locationProvider',
function ($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider.when('/dashboard', {
templateUrl: '/WEB-INF/pages/dashboard.jsp',
controller: 'DashboardController'
});
}]);
my service
Dashboard.factory('DashboardService', function ($http) {
return {
dashboard: function(successCallback, errorCallback) {
$http.get("/dashboard")
.success(
function (response) {
$scope.data = response;
}
).error(
function (response) {
$scope.data = "ERROR!";
}
)
}
}
});
and finally my controller
angular.module("dashboard", [])
.controller( 'DashboardController', function ($scope, DashboardService) {
$scope.nome = "Daniele";
$scope.cognome = "Comandini";
var data = {
nome: $scope.nome,
cognome: $scope.cognome
};
$scope.value = 0;
var login = function() {
alert("LOGIN ON DASHBOARD");
DashboardService.dashboard();
};
$scope.login = login;
});
My JSP page must only send the request to the DashBoardcontroller, that it has the return the page dashboard.jsp with the current date.
You must not inject dependencies in your module. Dependencies like service, factory have to be injected in controllers. By the way, don't forget to inject ngRoute.
Module becomes:
var Dashboard = angular.module( 'dashboard', ['ngRoute'] )
.config(['$routeProvider', '$locationProvider',
function ($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider.when('/dashboard', {
templateUrl: '/WEB-INF/pages/dashboard.jsp',
controller: 'DashboardController'
});
}]);
Your controller code is good, just one thing: if you want to use a code compiler like Grunt, Gulp or Webpack, don't forget to add your dependencies as strings:
angular.module('dashboard')
.controller( 'DashboardController', ['$scope', 'DashboardService'], function ($scope, DashboardService) {
I copied your controller with the service injection
.controller( 'DashboardController', ['$scope', 'DashboardService'], function ($scope, DashboardService) {
but in the end I had to write this
Dashboard.controller( 'DashboardController', ['$scope', 'DashboardService' , function ($scope, DashboardService) {
$scope.nome = "Daniele";
$scope.cognome = "Comandini";
var data = {
nome: $scope.nome,
cognome: $scope.cognome
};
$scope.value = 0;
var login = function() {
alert("LOGIN ON DASHBOARD");
DashboardService.dashboard();
};
$scope.login = login;
}]);
I mean I had to include the function into [], and not outside.

Angular controller not injected in test

I have a simple login controller:
'use strict';
angular.module('login', ['ngRoute'])
.config(['$routeProvider', function ($routeProvider) {
}])
.controller('LoginCtrl', ["$scope", "$route", "LoginService", function ($scope, $route, LoginService) {
var self = this;
this.showGuestLogin = true;
this.showUserLogin = false;
this.toggleUserLoginType = function () {
this.showGuestLogin = !this.showGuestLogin;
this.showUserLogin = !this.showUserLogin;
}
this.submitGuestLogin = function()
{
if(this.guestName === undefined || this.guestName.trim() == '')
{
self.loginError = "Name cannot be blank";
return;
}
LoginService.loginAsGuest(this.guestName.trim())
.then(function()
{
self.loginError = null;
$route.reload();
})
.catch(function(err)
{
self.loginError = 'An error occured. Please try again';
});
}
}]);
I am trying to test it with:
describe('LoginCtrl', function()
{
beforeEach(module('login'));
var ctrl;
beforeEach(inject(function($controller)
{
ctrl = $controller('LoginCtrl');
}));
it('should set error if guest name is undefined', function(done)
{
ctrl.guestName = undefined;
ctrl.submitGuestLogin();
expect(ctrl.loginError).toBeDefined();
});
});
But I am getting this error in console when test runs
Error: [$injector:unpr]
http://errors.angularjs.org/1.5.8/$injector/unpr?p0=%24scopeProvider%20%3C-%20%24scope%20%3C-%20LoginCtrl
I can see in the developer console in the karma driven browser that the controller and it's dependant files are all being loaded correctly.
I can't see what is wrong?
UPDATE
I have tried the suggestions of passing an empty object:
beforeEach(inject(function($controller, $scope, $route, LoginService)
{
ctrl = $controller('LoginCtrl', {
});
}));
and setting up the dependencies:
beforeEach(inject(function($controller, $scope, $route, LoginService)
{
ctrl = $controller('LoginCtrl', {
$scope: $scope,
$route: $route,
LoginService: LoginService
});
}));
Both of which give me this error:
Error: [$injector:unpr]
http://errors.angularjs.org/1.5.8/$injector/unpr?p0=%24scopeProvider%20%3C-%20%24scope
It's because you need to add in the scope in the injection like this:
beforeEach(inject(function($controller, $scope) {
ctrl = $controller('LoginCtrl', { $scope: $scope });
}));
Similarly, if your real controller has injections that you will be using for testing, you'll need to add them in. So for example (and this is only an example):
ctrl = $controller('LoginCtrl',
{
$scope: $scope,
SomeService: SomeService,
moment: moment,
dateFormat: dateFormat
});
Found an answer here which worked: Angular Unit Test Unknown provider: $scopeProvider
beforeEach(inject(function($controller, $rootScope, $route, LoginService)
{
scope = $rootScope.$new();
ctrl = $controller('LoginCtrl', {
$scope: scope
});
}));
In my case I didn't actually need $scope injected into my controller, so I removed it an the original code now works:
beforeEach(inject(function($controller, $rootScope, $route, LoginService)
{
ctrl = $controller('LoginCtrl');
}));
I need to read up on how mocks and injection works!

how to call the method of controller in routeProvider resolve function

I wanna update the data and then show the view bound with this controller, the code is as follow
angular.module('myApp.student', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/student', {
templateUrl: 'student/student.html',
css: 'student/assets/student.css',
controller: 'studentCtrl',
demand: 'admin'
});
}])
.controller('studentCtrl', ['$scope', 'baseDataUrl', '$http', function($scope, baseDataUrl, $http) {
$scope.update = function() {
$http.get(baseDataUrl + '/student/list').then(function(res) {
$scope.students = res.data;
});
};
$scope.orderProp = "name";
$scope.update();
}]);
how can i do this as there is no way to inject the controller to the config as I know
You could write something like...
angular.module('myApp.student', ['ngRoute'])
.config('routeConfig', function($routeProvider) {
$routeProvider.when('/student', {
templateUrl: 'student/student.html',
css: 'student/assets/student.css',
controller: 'studentCtrl',
demand: 'admin',
resolve: { students : function ($http, baseDataUrl) {
return $http.get(baseDataUrl + '/student/list').then(function (res) {
return res.data;
});
}
}
});
})
.controller('studentCtrl', ['$scope', function($scope, students) {
$scope.students = students;
$scope.orderProp = "name";
}]);
Note that baseDataUrl must either be a constant, or a provider that calls a function to get the required data (in which case, it should be something like baseDataUrl.getUrl()).
With this, it is ensured that every time the /student route is accessed, the scope variable $scope.students contains updated data.

AngularJS controller as syntax "this" is not $scope

I'm new to angularjs and I'm trying to employ the styles outlined from this post: https://github.com/johnpapa/angular-styleguide. When using the var vm = this style, rather than $scope, the vars I'm trying to bind to in the template are unavailable. Inspecting vm in the console shows an empty object, not the same as $scope.
/* index.js */
angular.module('myApp', ['ngAnimate', 'ngCookies', 'ngTouch', 'ngSanitize', 'ngResource', 'ngRoute', 'ui.bootstrap', 'loginModule', 'sidebarModule', 'jm.i18next'])
.value('baseUri', "/myApp/api")
.config(config)
.run(function($rootScope, $injector) {
$injector.get("$http").defaults.transformRequest = function(data, headersGetter) {
if ($rootScope.oauth !== undefined) {
console.log($rootScope.oauth);
headersGetter()['Access-Token'] = $rootScope.oauth.access_token;
}
if (data) {
return angular.toJson(data);
}
};
});
function config($routeProvider, $i18nextProvider) {
$routeProvider
.when('/', {
templateUrl: 'app/my-module-login/login.html',
controller: 'loginController',
conrollerAs: 'vm' // not available in template
})
.otherwise({
redirectTo: '/'
});
/* login.module.js */
angular.module('loginModule', ['utils']);
/* login.controller.js */
(function(){
'use strict';
angular.module('loginModule')
.controller('loginController', login);
login.$inject = ['$rootScope', '$scope', 'credsFactory', 'loginFactory'];
function login($rootScope, $scope, credsFactory, loginFactory) {
var vm = this; //empty object
vm.user = {};
vm.login = doLogin;
function doLogin(user) {
//user creds
var creds = {
userName: user.username,
password: user.password
};
loginFactory.login(creds)
.success(function (data) {
credsFactory.setCreds(data);
$scope.status = 'Logged in user!';
$scope.creds = creds;
var storageCreds = credsFactory.getCreds();
$rootScope.oauth = {};
$rootScope.oauth.access_token = storageCreds.accessToken;
window.location.hash = "#/logged-in";
}).
error(function(error) {
$scope.status = 'Unable to login user: ' + error.message;
});
}
}
})();
/* login.html */
<div class="form-group form-group-sm">
<div class="text-center">
<!-- how to access vm, {{vm.login(user)}} doesn't work -->
<button type="button" class="btn btn-default" id="login-submit" ng-i18next="button.cancel" ng-click="login(user)"></button>
</div>
</div>
You can declare the controllerAs when setting up the route - there is a typo in your example. (The name does not have to be the same as in loginController function)
Route:
$routeProvider
.when('/', {
templateUrl: 'app/my-module-login/login.html',
controller: 'loginController',
controllerAs: 'vm'
})
View:
<button ng-click="vm.login(user)"></button>
Also, when using "var vm = this;" in the controller function, you do not need to inject $scope. Instead of $scope in doLogin success function:
vm.status = 'Logged in user!';

Ui-router modal injection error on minification

I'm using ui-router and ui-bootstrap/modal
I've got a sale screen split in 2 so I have a left side with the cart and the right one can have the catalog, an edit product or a payment section.
I need to have a modal in all states so I've created a function to add in some ui-router states.
Here's the function:
var modalSaleDelete = ['$state', '$modal',
function($state, $modal) {
$modal.open({
templateUrl: 'views/sale/delete.html',
resolve: {
parentScope: function($rootScope) {
return $rootScope.parentScope;
}
},
controller: function($scope, parentScope) {
$scope.delete = function() {
// TODO: change the way this is called
parentScope.resetOrder();
parentScope = null;
$scope.$close('cancel');
};
$scope.cancel = function() {
parentScope = null;
$scope.$dismiss('cancel');
};
}
}).result.then(function() {
return $state.transitionTo($state.$current.parent);
}, function() {
return $state.transitionTo($state.$current.parent);
});
}
];
Then I put that in every state:
.state('sale.new.catalog.delete', {
url: '/delete',
onEnter: modalSaleDelete
})
It works great on development but when I minify this I get an error:
Error: [$injector:unpr] Unknown provider: aProvider <- a
http://errors.angularjs.org/1.2.24/$injector/unpr?p0=aProvider%20%3C-%20a
at http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:3:26944
at http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:4:11462
at Object.c [as get] (http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:4:10723)
at http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:4:11557
at c (http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:4:10723)
at Object.d [as invoke] (http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:4:11008)
at http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:8:20044
at Object.f [as forEach] (http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:3:27387)
at j (http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:8:19961)
at Object.k.open (http://localhost/ociWeb/code/dist/scripts/vendor.29d508bc.js:8:20414)
I debugged that and aProvider should be '$state'.
Any idea on how to make that work?
You need to annotate EVERY injection for minification to work. Or, if you are using an angular-aware minifier, it probably doesn't understand which functions are injected by UI-Router and which are standard functions.
var modalSaleDelete = ['$state', '$modal',
function($state, $modal) {
$modal.open({
templateUrl: 'views/sale/delete.html',
resolve: {
parentScope: [ '$rootScope', function($rootScope) {
return $rootScope.parentScope;
}]
},
controller: [ '$scope', 'parentScope', function($scope, parentScope) {
$scope.delete = function() {
// TODO: change the way this is called
parentScope.resetOrder();
parentScope = null;
$scope.$close('cancel');
};
$scope.cancel = function() {
parentScope = null;
$scope.$dismiss('cancel');
};
}]
}).result.then(function() {
return $state.transitionTo($state.$current.parent);
}, function() {
return $state.transitionTo($state.$current.parent);
});
}
];
Try injecting them manually by creating an inject property. Do you have a jsfiddle or plunker set up?
modalSaleDelete.$inject = ['$state', '$modal'];
Well, I've figured it out. I don't see why but the problem was in resolve.
I solved it injecting '$state' in resolve though it's not needed.
When debugging I just saw the aProvider was trying to be injected in there.
var modalSaleDelete = ['$rootScope', '$state', '$modal',
function($rootScope, $state, $modal) {
$modal.open({
templateUrl: 'views/sale/delete.html',
resolve: {
parentScope: ['$state', '$rootScope', function($state, $rootScope) {
return $rootScope.parentScope;
}]
},
controller: ['$scope', '$state', 'parentScope', function($scope, $state, parentScope) {
$scope.delete = function() {
// TODO: change the way this is called
parentScope.resetOrder();
parentScope = null;
$scope.$close();
};
$scope.cancel = function() {
parentScope = null;
$scope.$dismiss();
};
}]
}).result.then(function() {
// close
return $state.transitionTo($state.current.name.replace('.delete', ''));
}, function() {
// dismiss
return $state.transitionTo($state.current.name.replace('.delete', ''));
});
}
];

Resources