I got some problem when I'm trying to use an Angular service in the controlleur of my application.
When I'm trying to use function of my service in my controlleur, my console throw me an error :/
var app = angular.module('app', ['ngRoute'])
app.config(['$routeProvider',
function ($routeProvider) {
$routeProvider
.when('/login', {
controlleur: 'login',
templateUrl: 'modules/login/login.html'
})
.otherwise({
redirectTo: '/login'
});
}]);
app.service('coreServices', [function () {
this.helloConsole = function () {
console.log("console services");
};
}]);
app.controller('loginController', ['$scope', '$http', '$rootScope', '$location', 'coreServices', LoginController]);
function LoginController($scope, $http, $rootScope, coreServices) {
var vm = this;
vm.helloConsole = coreServices.helloConsole;
vm.helloConsole();
}
angular.js:13708 TypeError: vm.helloConsole is not a function
at new LoginController
I link you this fiddle to show you how I do: https://jsfiddle.net/h8yaxLap/2/
The error throwed is:
angular.js:13708 TypeError: vm.helloConsole is not a function
at new LoginController
Well in your example angular will map $location to coreService in the injected parameters in the function. So I would go for
app.controller('loginController', ['$scope', '$http', '$rootScope', '$location', 'coreServices', LoginController]);
function LoginController($scope, $http, $rootScope, $location, coreServices)
Change service function to return object
app.service('coreServices', function () {
return {
helloConsole: function () {
console.log("console services");
}
};
});
You missed $location parameter for the controller
function LoginController($scope, $http, $rootScope,$location, coreServices)
Related
I have two HTML pages. One is the exam.html and other is result.html. On certain condition in the controller ExamCtrl of exam.html, I route to result.html using $location.path. But however, on the result page, the controller ResultCtrl doesn't seem to load though I have added it in the config file.
angular config file:
angular.module('exam').config(['$stateProvider',
function ($stateProvider) {
// Exam state routing
$stateProvider
.state('exam', {
abstract: true,
url: '/exam',
template: '<ui-view/>'
})
.state('exam.list', {
url: '',
templateUrl: 'modules/exam/client/views/exam.client.view.html',
controller: 'ExamCtrl'
})
.state('/result', {
url: '/result',
templateUrl: 'modules/exam/client/views/exam-result.client.view.html',
contoller: 'ResultCtrl'
});
}
]);
ExamCtrl:
angular
.module('exam')
.controller('ExamCtrl', ['$scope', '$stateParams', '$location', 'Authentication', '$http',
function ($scope, $stateParams, $location, Authentication, $http) {
$scope.submitAnswer = function (selected) {
//some code
if (qtnCounter > 5) {
// loads the result page.
$location.path('/result');
} else {
$scope.getQues();
}
};
}
]);
ResultCtrl:
angular
.module('exam')
.controller('ResultCtrl', ['$scope', '$stateParams', '$location', 'Authentication', '$http',
function ($scope, $stateParams, $location, Authentication, $http) {
console.log('ResultCtrl');
}
]);
result.html:
<body ng-controller="ResultCtrl">
<h1>Result page!</h1>
</body>
Insted of using $location use the $state to change to a given state in your app.
Inject the $state in the controller and then call the transitionTo() which will load the view and setup the controller
angular
.module('exam')
.controller('ExamCtrl', ['$scope', '$state', 'Authentication', '$http',
function ($scope, $state, Authentication, $http) {
$scope.submitAnswer = function (selected) {
//some code
if (qtnCounter > 5) {
// loads the result page.
$state.transitionTo('/result');
} else {
$scope.getQues();
}
};
}
]);
I've got few controllers working with different templates:
curryApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'table_index.html',
controller: 'CurryListCtrl'
}).
when('/cities/:cityId/', {
templateUrl: 'template-total.html',
controller: 'CurryDetailCtrl'
}).
when('/cities/:cityId/mobile/', {
templateUrl: 'template-mobile.html',
controller: 'CurryMobileCtrl'
}).
when('/cities/:cityId/online/', {
templateUrl: 'template-online.html',
controller: 'CurryOnlineCtrl'
}).
All of theses controllers have $scope variable called cities
For example, the first one:
curryControllers.controller('CurryDesktopCtrl', ['$scope', '$routeParams', '$http', '$route',
function($scope, $routeParams, $http, $route) {
$scope.cityId = $routeParams.cityId;
$http.get('json/cities.json').success(function (data) {
$scope.cities = data;
...
The second one:
curryControllers.controller('CurryOnlineCtrl', ['$scope', '$routeParams', '$http', '$route',
function($scope, $routeParams, $http, $route) {
$scope.cityId = $routeParams.cityId;
$http.get('json/cities.json').success(function(data) {
$scope.cities = data;
...
Is it okay to have repeated $scope variables in different controllers?
How should I refactor the code in order to escape duplicates?
If cities are not going to change for every controller use services like below
Your service should look like below
app.service('myService',function($http,$q){
var cities=null;
this.getCities=function()
{
var deferred = $q.defer()
if(this.cities==null){
$http.get('json/cities.json')
.then((response) => {deferred.resolve(response);cities=response;})
.catch((error) => deferred.reject(error))
}
else { deferred.resolve(cities)}
return deferred.defer
})
});
Use the above service in the controller
app.controller('ctrl',function($scope,myService){
myService.getCities().then(function(data){ $scope.cities = data;})
})
You can create a factory:
.factory('citiesFactory', function($http) {
function getCities(){
// return promise from function
return $http.get("json/cities.json");
}
return {
getCities: getCities
}
});
then in your controller:
curryControllers.controller('CurryDesktopCtrl', ['$scope', '$routeParams', '$http', '$route', 'citiesFactory'
function($scope, $routeParams, $http, $route, citiesFactory) {
$scope.cityId = $routeParams.cityId;
citiesFactory.getCities().then(function(response){
$scope.cities = response.data;
});
...
You should do create a factory like this. Forgive the syntax, but you get the idea.
app.factory('Cities', function ($http) {
return {
'getData': function() {
$http.get('json/cities.json').success(function (data) {
return data;
}
.error(function(error){
return [];
}
}
};
}]);
and in your controller inject the factory and get the data
curryControllers.controller('CurryOnlineCtrl', ['$scope', '$routeParams', '$http', '$route', 'Cities'
function($scope, $routeParams, $http, $route) {
$scope.cityId = $routeParams.cityId;
$scope.cities = Cities.getData();
...
If the cities json is common for all the controllers.
One option would be to move the common object used across controllers into rootscope refer.
Other option would be to store the cities json in the service itself read here.
I am trying to redirect a user to different page after user is authenticated. I am using jwt authentication and I tried with $location, $window for redirection but its throwing error $state.go is not a function. I am new to angular and I am guessing there should be way to redirect may using a service in angular but I am still new to factories and service.
I have my state provider like this in state.js file:
myApp.config(function ($stateProvider, $urlRouterProvider) {
// default route
$urlRouterProvider.otherwise("/Home");
var header = {
templateUrl: 'commonViews/Header.html',
controller: function ($scope) {
}
};
var footer = {
templateUrl: 'commonViews/Footer.html',
controller: function ($scope) {
}
};
// ui router states
$stateProvider
.state('Home', {
url: "/Home",
views: {
header: header,
content: {
templateUrl: 'views/HomePage.html',
controller: function ($scope) {
}
},
footer: footer
}
})
.state('LoggedIn', {
url: "/LoggedIn",
views: {
'header': header,
'content': {
templateUrl: 'views/LoggedIn.html',
controller: function () {
}
},
'footer': footer
}
});
});
and loginController.js:
myApp.controller('loginController', ['$scope', '$http', 'jwtHelper', '$localStorage', '$state', function ($scope, $http, jwtHelper, $localStorage, $sessionStorage, $state)
{
$scope.email = "";
$scope.password = "";
$scope.token = "";
$scope.loginForm = function () {
var data = {email: $scope.email, password: $scope.password};
var url = 'rs/loginResource/login';
$http.post(url, data).then(function (response)
{
$localStorage.token = response.data.token;
console.log("Encoded Token in localstorage is:" + $localStorage.token);
if ($localStorage.token) {
// $location.url("/LoggedIn");
$state.go('/LoggedIn');
}
}, function (error)
{
console.log("error", error);
});
};
}]);
further I have to perform refresh token based on expiration time etc, so is it better to have separate the functions like using a service to do the signup and signin?
The problem is the definition of your controller and the way you're handling your injections. And no, referring to your own answer to your question, the problem is not the "order" of the injections. It's a bit worse.
myApp.controller('loginController', ['$scope', '$http', 'jwtHelper', '$localStorage', '$state', function ($scope, $http, jwtHelper, $localStorage, $sessionStorage, $state)
in this code you're mapping '$scope' to a $scope variable, '$http' to $http, 'jwtHelper' to jwtHelper, '$localStorage' to $localStorage and '$state' to $sessionStorage, and you're not mapping anything to $state. So obviously you get an error when you try to call a method on an undefined $state variable.
So in short, you're injecting 5 dependencies and you're assigning 6 variables to your dependencies, which in turn results in things not doing what they're supposed to do.
You can use Angular $window:
$window.location.href = '/index.html';
$state. go accepts the view name, not the URL. Replace '/LoggedIn' with Logged and you should be good.
Use $state.go instead of $window and location.
Add $state injector on controller
write code $state.go('LoggedIn');
Instead $state.go('/LoggedIn');
Write state name('LoggedIn') instead of url('/LoggedIn').
Hopefully this will work in your case.
You need to add $window as a dependency to your controller if you are using $window,
myApp.controller('loginController', ['$scope', '$http', 'jwtHelper', '$localStorage', '$state','$window', function ($scope, $http, jwtHelper, $localStorage, $sessionStorage, $state,$window)
{
$window.location.href = '/index.html';
}
otherwise change the route like this, here also you need to inject $state,
myApp.controller('loginController', ['$scope', '$http', 'jwtHelper', '$localStorage', '$state','$window','$state', function ($scope, $http, jwtHelper, $localStorage, $sessionStorage, $state,$window,$state)
{
$state.go('LoggedIn');
}
This is my first attempt to use the Angularjs and I'm trying to create a service and use it inside a controller:
var appTest = angular.module("appTest", ["ngRoute"]);
var appTestControllers = angular.module('appTestControllers', []);
appTest.config(['$routeProvider', '$locationProvider',
function($routeProvider, $locationProvider) {
$routeProvider.
when('/', {
templateUrl: 'partials/home.html',
controller: 'HomeCtrl'
});
$locationProvider.html5Mode(false);
}
]);
appTest.factory("booksApi", function($http){
var _getBooks = function() {
return $http.get('http://localhost/editora-voo/website/books.json');
};
return{
getBooks: _getBooks
};
});
appTest.controller('HomeCtrl', ['$scope', '$http', function($scope, $http, booksApi) {
booksApi.getBooks().success(function(data) {
$scope.books = data;
});
}]);
But it is returning an error: Cannot read property 'getBooks' of undefined
You missed to add booksApi depnedency inside your controller dependency array, You should add it first and then use that inside the function of controller.
Controller
appTest.controller('HomeCtrl', ['$scope', '$http', 'booksApi', //<--missed dependency here
function($scope, $http, booksApi) {
booksApi.getBooks().then(function(response) {
$scope.books = response.data;
});
}]);
Plunkr Here
I'm trying to modify standard user module of meanjs. I added a simple route:
state('users', {
url: '/users/:username',
templateUrl: 'modules/users/views/view-profile.client.view.html'
});
And in my view:
data-ng-controller="ViewProfileController" data-ng-init="findUser()"
I also injected $stateParams to my controller. So in my ViewProfileController - findUser function, when I write this:
console.log($stateParams.username)
I expect to get username parameter. But it returns undefined.
When I set the route this way,
state('users', {
url: '/users/:username',
template: function ($stateParams){
return $stateParams.username;
}
});
it returns username. I don't know what is wrong or missing. Any ideas?
edit: this was my full controller code
'use strict';
angular.module('users').controller('ViewProfileController', ['$scope', '$http', '$stateParams', '$location', 'Users', 'Authentication',
function($scope, $http, $location, Users, Authentication, $stateParams) {
$scope.user = Authentication.user;
$scope.findUser = function () {
console.log($stateParams);
...
};
}
]);
Your dependencies don't match up - the list of dependencies need to match the parameters in the controller function in the same order:
'use strict';
angular.module('users')
.controller('ViewProfileController', ['$scope', '$http', '$stateParams', '$location', 'Users', 'Authentication',
function($scope, $http, $stateParams, $location, Users, Authentication) {
$scope.user = Authentication.user;
$scope.findUser = function () {
console.log($stateParams);
};
}
]);
I should use controller instead of template.
Replace into you code the template: to the follow snippet:
controller: function($stateParams){
console.log('username: '+$stateParams.username);
}
You can see a complete example of this feature here