I have the Angular controller below. When it is run, I get the error "TypeError: t.getDealers is not a function". This is caused by the minification of the javascript. However, I'm not sure how to fix this.
myApp.controller('DLOController', ['$scope', 'DLOFactory',
function ($scope, DLOFactory) {
$scope.init = function () {
$scope.searchType = [{ id: 1, name: "Search by Postcode" }, { id: 2, name: "Search by State" }, { id: 3, name: "Search by Dealer" }];
$scope.selectedSearchType = 1;
$scope.selectedState = -1;
$scope.postcode = "";
$scope.dealerName = "";
$scope.states = [];
$scope.dealers = [];
getStates(2);
getDealers(2);
}
function getStates(categoryType) {
DLOFactory.getStates(categoryType)
.success(function (val) {
$scope.states = val;
})
.error(function (error) {
// REVISIT: LOG ERROR HERE.
});
}
function getDealers(categoryType) {
DLOFactory.getDealers(categoryType)
.success(function (val) {
$scope.dealers = val;
console.log($scope.dealers);
})
.error(function (error) {
// REVISIT: LOG ERROR HERE.
});
}
}
]);
Here is my factory:
myApp.factory('DLOFactory', ['$http', function ($http) {
var stateList = [];
var dealerList = [];
return {
getStates: function (categoryType) {
return $http({
method: 'GET',
url: '/Addresses/GetStateList',
params: { categoryType: categoryType }
})
.success(function (responseData) {
stateList.push(responseData);
});
},
getStateList: function () {
return stateList;
},
setStateList: function (sl) {
stateList = sl;
}
}
return {
getDealers: function (categoryType) {
return $http({
method: 'GET',
url: '/Websites/GetDealers',
params: { categoryType: categoryType }
})
.success(function (responseData) {
dealerList.push(responseData);
});
},
getDealerList: function () {
return dealerList;
},
setDealerList: function (dl) {
dealerList = dl;
}
}
}]);
The minified code looks like this:
myApp.controller("DLOController",["$scope","DLOFactory",function(n,t){function i(i){t.getStates(i).success(function(t){n.states=t}).error(function(){})}function r(i){t.getDealers(i).success(function(t){n.dealers=t;console.log(n.dealers)}).error(function(){})}n.init=function(){n.searchType=[{id:1,name:"Search by Postcode"},{id:2,name:"Search by State"},{id:3,name:"Search by Dealer"}];n.selectedSearchType=1;n.selectedState=-1;n.postcode="";n.dealerName="";n.states=[];n.dealers=[];i(2);r(2)}}]);
You have two returns on the factory so second return won't execute. So merge both returns & try.
Related
I am having a controller like below
(function () {
var mockController = function ($scope, MockService) {
$scope.message = "This is a text message";
$scope.getCities = function () {
return MockService.getCities();
};
};
var mockService = function ($http) {
this.getCities = function () {
return $http.get("../rest/url", {
headers: {
'Accept': 'application/yang.data+json'
}
});
};
};
angular.module("MockApp", [])
.service("MockService", mockService)
.controller("MockController", mockController);
}())
I am trying to write a UT mocking the service like below
describe("MockController", function () {
var $scope;
beforeEach(function () {
module("MockApp");
inject(function (_$controller_, _$rootScope_, MockService) {
$scope = _$rootScope_.$new();
spyOn(MockService, "getCities").and.callFake(function () {
return [{
city: "Bangalore"
, country: "India"
}];
});
controller = _$controller_("MockController", {
$scope: $scope
});
});
});
describe("Test", function () {
it("Should be Bangalore", function () {
$scope.getCities()
.then(function (data) {
console.log("got it");
})
});
});
});
Its throwing an error saying
TypeError: $scope.getCities(...).then is not a function
Please help me.
I think:
$scope.getCities = function () {
return MockService.getCities();
};
should be:
$scope.getCities = function () {
return MockService(getCities());
};
I am working on an app to allow users to login with different level or access to an application. I added a resolve dependencies to get the list of users. It did return a list of correct users. How do I pass this object to the controller?
I follow a similar example on the website, but my getPrelogin object is always undefined. What did I do wrong?
.state('registration.login', {
url: '/Login',
resolve: {
preLoginFactory: 'preLoginFactory',
getPrelogin: function (preLoginFactory) {
var result = preLoginFactory();
result.then(function (result) {
return result.data.Model.IntroMessage;
})
}
},
views: {
"content#": {
templateUrl: '/Account/Login',
controller: function ($scope, $stateParams, $location, LoginFactory, getPrelogin, preLoginFactory) {
console.log('the value of get pre login')
console.log(getPrelogin);
$scope.introMessage = getPrelogin;
$scope.loginForm = {
emailAddress: '',
password: '',
rememberMe: false,
returnUrl: $stateParams.returnUrl,
loginFailure: false
};
$scope.login = function () {
var result = LoginFactory($scope.loginForm.emailAddress, $scope.loginForm.password, $scope.loginForm.rememberMe);
result.then(function (result) {
if (result.success) {
if ($location.loginForm.returnUrl !== 'undefined') {
$location.path('/routeOne');
} else {
$location.path($scope.loginForm.returnUrl);
}
} else {
$scope.loginForm.loginFailure = true;
}
});
};
}//"LoginController"
}
}
})
Your resolve object getPrelogin should return result variable, because promise preLoginFactory factory does return promise object. By injecting getPrelogin inside controller you would directly get data returned from getPrelogin which is result.data.Model.IntroMessage.
Code
resolve: {
preLoginFactory: 'preLoginFactory',
getPrelogin: function(preLoginFactory) {
var result = preLoginFactory();
return result.then(function(response) {
return response.data.Model.IntroMessage;
})
}
},
You must return your promise:
getPrelogin: function (preLoginFactory) {
var result = preLoginFactory();
return result.then(function (result) {
return result.data.Model.IntroMessage;
})
}
I'm trying to setup a restful API interface via AngularJS with the following code:
'use strict';
(function(angular) {
function ApiAction($resource, ResourceParameters) {
return $resource(ResourceParameters.route,
{ },
{ api_index: {
method: ResourceParameters.method,
isArray: true
}
});
return $resource(ResourceParameters.route,
{ },
{ create: {
method: ResourceParameters.method,
isArray: true
}
}
);
}
function ResourceParameters($scope) {
var factory = {};
factory.method = '';
factory.route = '';
factory.SetMethod = function(method) {
factory.method = method;
}
factory.SetRoute = function(route) {
factory.route = route;
}
return factory;
}
function superheroCtr($scope, ApiAction, ResourceParameters) {
$scope.superheroSubmit = function() {
// ApiAction.create({}, { superhero_name: $scope.superheroName, age: $scope.superheroAge });
angular.forEach($scope.superheroes, function(hero) {
// ApiAction.create({}, { superhero_name: hero.superhero_name, age: hero.age });
});
};
var heroesResources = ResourceParameters($scope).SetRoute('/api/');
var heroes = ApiAction.api_index({}, heroesResources);
$scope.superheroes = [];
heroes.$promise.then(function(data) {
angular.forEach(data, function(item) {
$scope.superheroes.push(item);
});
}, function(data) {
//if error then...
});
$scope.appendSuperheroFields = function() {
var i = $scope.superheroes.length + 1;
$scope.superheroes.push({"id": i, age: "", superhero_name: "" })
}
}
var superheroApp = angular.module('superheroApp', ['ngResource']);
superheroApp.controller('superheroCtr', ['$scope', 'ApiAction', 'ResourceParameters', superheroCtr]);
superheroApp.factory('ResourceParameters', ['$scope', ResourceParameters]);
superheroApp.factory('ApiAction', ['$resource', ResourceParameters, ApiAction]);
})(angular);
Yet, when I run it I get the following error:
Error: [$injector:itkn] Incorrect injection token! Expected service name as string, got function ResourceParameters($scope)
Why is this?
Simply you can not inject $scope OR you can not have access to $scope
inside a factory
Your problem is at this line
superheroApp.factory('ResourceParameters', ['$scope', ResourceParameters]);
You need to replace that line with
superheroApp.factory('ResourceParameters', [ResourceParameters]);
Factory
function ResourceParameters() { //<--removed $scope from here
var factory = {};
factory.method = '';
factory.route = '';
factory.SetMethod = function(method) {
factory.method = method;
}
factory.SetRoute = function(route) {
factory.route = route;
}
return factory;
}
Update
Additionally you should correct the declaration of ApiAction where ResourceParameters should be placed inside ' single qoutes
superheroApp.factory('ApiAction', ['$resource', 'ResourceParameters', ApiAction]);
I am trying to create a tag layout filled with categories, but I am not getting my Authentication because I am trying to resolve that service in my Router.
this is my Router code
(function () {
'use strict';
angular
.module('learningApp')
.config(sslRouter);
// Minification safe dependency Injection
sslRouter.$inject = ['$stateProvider'];
function sslRouter ($stateProvider) {
// SSL Route Definition
$stateProvider.state('ssl', {
parent: 'policy',
url: '/ssl',
data: {
roles: ['USER']
},
views: {
'policyConfig': {
templateUrl: 'components/configuration/service/policy/ssl/ssl.tpl.html',
controller: 'SSL'
}
},
resolve: {
'sslServiceData': function(sslService) {
return sslService.promise;
}
}
});
}
}());
This is my Service
(function() {
'use strict';
angular
.module('learningApp')
.factory('sslService', sslResource);
sslResource.$inject = ['Principal', '$resource', 'BASE_URL', 'exDomainService'];
function sslResource (Principal, $resource, BASE_URL, exDomainService) {
debugger;
var res = $resource(BASE_URL + '/api/companies/' + Principal.company() + '/sconfig/ssl/sslConfiguration', {}, {
query: {
method: 'GET',
isArray: false
},
update: {
method: 'PUT'
}
});
var data = {};
var servicePromise = _initService();
servicePromise.$promise.then(function (d) {
data = d;
if (!data.excludedCategories) {
data.excludedCategories = [];
}
if (!data.excludedDomains) {
data.excludedDomains = [];
}
exDomainService.tableData = getExcludedDomains();
});
function _initService () {
return res.query();
}
return {
promise: servicePromise,
rest: res
}
}
}());
This is my controller
(function() {
'use strict';
angular
.module('learningApp')
.controller('SSL', SSLController);
SSLController.$inject = ['$scope', 'sslService', 'preDefinedCategoryService', '$timeout', 'exDialog', 'exDomainService'];
function SSLController ($scope, sslService, preDefinedCategoryService, $timeout, exDialog, exDomainService) {
var vm = $scope;
/**
* #desc Flags for different type checks
* Booleans and Categories
*/
vm.flags = {
// By default true
enableInspectSSLTraffic: sslService.getSSlInspectionFlag(),
allowUntrustedCertificates: sslService.getUntrustedCertificatesFlag(),
allowHostnameMismatch: sslService.getHostnameMismatchFlag(),
selectedCategory: undefined,
initializing: true
};
vm.excludedCategories = sslService.getExcludedCategories();
vm.predefinedCategories = preDefinedCategoryService.rest.query();
vm.predefinedCategories.$promise.then(function() {
vm.categories = _processedCategories(vm.predefinedCategories, vm.excludedCategories);
});
}
}());
So basically problem is, I am getting Principal.Identity as undefined, but if I remove resolution from Router, I got identity but then I lose my data coming from service. I want my service to be loaded completely before its Controller, and I want my principal service to be loaded before service.
for Reference, This is my Principal Class
'use strict';
angular.module('learningApp')
.service('Principal',['$q', 'Account', 'localStorageService', function Principal($q, Account, localStorageService) {
var _identity,
_authenticated = false;
return {
isIdentityResolved: function () {
return angular.isDefined(_identity);
},
isAuthenticated: function () {
return _authenticated;
},
isInRole: function (role) {
if (!_authenticated || !_identity || !_identity.roles) {
return false;
}
return _identity.roles.indexOf(role) !== -1;
},
isInAnyRole: function (roles) {
if (!_authenticated || !_identity.roles) {
return false;
}
for (var i = 0; i < roles.length; i++) {
if (this.isInRole(roles[i])) {
return true;
}
}
return false;
},
company: function () {
debugger;
if (_identity) return _identity.companyId;
},
authenticate: function (identity) {
_identity = identity;
_authenticated = identity !== null;
},
identity: function (force) {
var deferred = $q.defer();
if (force === true) {
_identity = undefined;
}
// check and see if we have retrieved the identity data from the server.
// if we have, reuse it by immediately resolving
if (angular.isDefined(_identity)) {
deferred.resolve(_identity);
return deferred.promise;
}
// rather than retrieving from server, use cookie or whatever method
var cookieFound = UTIL.cookie("token");
if (cookieFound) {
var response = JSON.parse(JSON.parse(cookieFound));
var expiredAt = new Date();
expiredAt.setSeconds(expiredAt.getSeconds() + response.expires_in);
response.expires_at = expiredAt.getTime();
localStorageService.set('token', response);
}
// retrieve the identity data from the server, update the identity object, and then resolve.
Account.get().$promise
.then(function (account) {
account.data.roles = ["ADMIN", 'USER'];
account.data.langKey = "en";
_identity = account.data;
_authenticated = true;
deferred.resolve(_identity);
})
.catch(function() {
_identity = null;
_authenticated = false;
deferred.resolve(_identity);
});
return deferred.promise;
}
};
}]);
I am tring to setup a counter where for each country in my list I can keep count of how many clicks there has been plus an overall tally.
I have the below so far which can be viewd in this fiddle. The issue I am having is that I am not able to keep the count unique for each country. How can this be achieved?
<div ng-app="myApp">
<div data-ng-view></div>
</div>
'use strict';
var myApp = angular.module('myApp', ['ngRoute', 'templates/view1.html', 'templates/view2.html']);
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'templates/view1.html',
controller: 'CountryListCtrl'
})
.when('/:id', {
templateUrl: 'templates/view2.html',
controller: 'CountryCtrl'
})
}]);
myApp.factory('Countries', ['$q', function ($q) {
var countriesList = [];
// perform the ajax call (this is a mock)
var getCountriesList = function () {
// Mock return json
var contriesListMock = [
{
"id": "0",
"name": "portugal",
"abbrev": "pt"
}, {
"id": "1",
"name": "spain",
"abbrev": "esp"
}, {
"id": "2",
"name": "angola",
"abbrev": "an"
}
];
var deferred = $q.defer();
if (countriesList.length == 0) {
setTimeout(function () {
deferred.resolve(contriesListMock, 200, '');
countriesList = contriesListMock;
}, 1000);
} else {
deferred.resolve(countriesList, 200, '');
}
return deferred.promise;
}
var getCountry = function(id) {
var deferred = $q.defer();
if (countriesList.length == 0) {
getCountriesList().then(
function() {
deferred.resolve(countriesList[id], 200, '');
},
function() {
deferred.reject('failed to load countries', 400, '');
}
);
} else {
deferred.resolve(countriesList[id], 200, '');
}
return deferred.promise;
}
var cnt = 0;
var cntryCnt = 0;
var incCount = function() {
cnt++;
return cnt;
}
var incCntryCount = function(id) {
cntryCnt++;
return cntryCnt;
}
return {
getList: getCountriesList,
getCountry: getCountry,
getCount : function () {
return cnt;
},
getCntryCount : function () {
return cntryCnt;
},
incCount: incCount,
incCntryCount: incCntryCount
};
}]);
myApp.controller('CountryListCtrl', ['$scope', 'Countries', function ($scope, Countries) {
$scope.title = '';
$scope.countries = [];
$scope.status = '';
Countries.getList().then(
function (data, status, headers) { //success
$scope.countries = data;
},
function (data, status, headers) { //error
$scope.status = 'Unable to load data:';
}
);
}]);
myApp.controller('CountryCtrl', ['$scope', '$routeParams', 'Countries', function ($scope, $routeParams, Countries) {
$scope.country = {
id: '',
name: '',
abbrev: ''
};
var id = $routeParams.id;
Countries.getCountry(id).then(
function(data, status, hd) {
console.log(data);
$scope.country = data;
$scope.countOverall = Countries.getCount;
$scope.countCntry = Countries.getCntryCount;
$scope.clickCnt = function () {
$scope.countTotal = Countries.incCount();
$scope.country.clicks = Countries.incCntryCount(id);
console.log($scope);
};
},
function(data, status, hd) {
console.log(data);
}
);
}]);
angular.module('templates/view1.html', []).run(["$templateCache", function ($templateCache) {
var tpl = '<h1>{{ title }}</h1><ul><li ng-repeat="country in countries"><a href="#{{country.id}}">{{country.name}}</div></li></ul>';
$templateCache.put('templates/view1.html', tpl);
}]);
angular.module('templates/view2.html', []).run(["$templateCache", function ($templateCache) {
var tpl = '<div>{{country.name}} clicks {{countCntry()}} <br> overall clicks {{countOverall()}}</div><button>BACK</button><button ng-click="clickCnt()" >count clicks ++ </button>';
$templateCache.put('templates/view2.html', tpl);
}]);
The problem is that you are not incrementing a count based on the country. Working on the fiddle right now.
EDIT:
I've updated the fiddle: http://jsfiddle.net/1xtc0zhu/2/
What I basically did was making the cntryCnt an object literal which takes the country id as a property and keeps the right counting per each id, like so:'
var cnt = 0;
var cntryCnt = {};
...
// The function now receives the country id and increments the specific country clicks only.
var incCntryCount = function(id) {
cntryCnt[id] = cntryCnt[id] || 0;
cntryCnt[id]++;
return cntryCnt[id];
}
The rest of the changes are in the templates, and are basically only sending the country id as a param when getting or incrementing the counts.
Also, this is not an Angular Specific question, but more a programming in general question.