AngularJs cannot read property 'then' of undefined - angularjs

I have an authenticationService which contains this function:
//this.userApi = Restangular.service('api/sessions');
login(user) {
let that = this;
this.userApi.post(user).then(function(user) {
that.session.create(user.sessionId, user.userId, user.username);
return user;
});
}
And in my controller:
login() {
this.authService
.login(that.user)
.then(function(user) {
$scope.setCurrentUser(user);
},
function(result) {
console.log('fail', result.status);
});
}
I don't understand why I get 'Cannot read property 'then' of undefined' on this line: that.authService.login(that.user).then(function (user) ...

In your first snippet, you need to return the promise so that you can continue the chain in your other snippet.
//this.userApi = Restangular.service('api/sessions');
login(user) {
let that = this;
return this.userApi.post(user).then(function(user) {
that.session.create(user.sessionId, user.userId, user.username);
return user;
});
}

You should try this :
//this.userApi = Restangular.service('api/sessions');
login(user) {
let that = this;
return this.userApi.post(user).then(function(user) {
that.session.create(user.sessionId, user.userId, user.username);
return user;
});
}

Related

Creating new function in angularjs controller won't work

When creating new function in angularjs controller and assign it to button with ng-click and function is simple,
function toLogin() {
console.log("Entered function");
$state.go('login');
}
I tried with $scope and still does not work.
this is my controller:
'use strict';
angular.module('crudApp').controller('UserController',
['UserService', '$scope','$state', function( UserService, $scope, $state) {
var self = this;
self.user = {};
self.users=[];
self.user.enabled = false;
self.user.confirmationToken = '';
self.loggedUser = null;
self.submit = submit;
self.getAllUsers = getAllUsers;
self.createUser = createUser;
self.updateUser = updateUser;
self.removeUser = removeUser;
self.editUser = editUser;
self.reset = reset;
self.firstNamePattern=/^[A-Z][a-z]*\S$/;
self.lastNamePattern=/^[A-Z][a-z]*\S$/;
self.userNamePattern= /^\S*$/;
self.passwordPattern = /^\S*$/;
self.phonePattern = /^[0-9]+\S$/;
self.successMessage = '';
self.errorMessage = '';
self.done = false;
self.onlyIntegers = /^\d+$/;
self.onlyNumbers = /^\d+([,.]\d+)?$/;
function toLogin() {
console.log('Entered function');
// $state.go('login');
}
function submit() {
console.log('Submitting');
if (self.user.id === undefined || self.user.id === null) {
console.log('Saving New User', self.user);
createUser(self.user);
} else {
updateUser(self.user, self.user.id);
console.log('User updated with id ', self.user.id);
}
}
$scope.moje = function () {
console.log('Submitting');
if (self.user.id === undefined || self.user.id === null) {
console.log('Saving New User', self.user);
createUser(self.user);
} else {
updateUser(self.user, self.user.id);
console.log('User updated with id ', self.user.id);
}
}
function createUser(user) {
console.log('About to create user');
UserService.createUser(user)
.then(
function (response) {
console.log('User created successfully');
self.successMessage = 'User created successfully';
self.errorMessage='';
self.done = true;
self.user={};
$scope.registerForm.$setPristine();
$scope.registerForm.$setUntouched();
// $state.reload();
},
function (errResponse) {
console.error('Error while creating User');
self.errorMessage = 'Error while creating User: ' + errResponse.data.errorMessage;
self.successMessage='';
}
);
}
function updateUser(user, id){
console.log('About to update user');
UserService.updateUser(user, id)
.then(
function (response){
console.log('User updated successfully');
self.successMessage='User updated successfully';
self.errorMessage='';
self.done = true;
$scope.myForm.$setPristine();
},
function(errResponse){
console.error('Error while updating User');
self.errorMessage='Error while updating User '+errResponse.data;
self.successMessage='';
}
);
}
function removeUser(id){
console.log('About to remove User with id '+id);
UserService.removeUser(id)
.then(
function(){
console.log('User '+id + ' removed successfully');
},
function(errResponse){
console.error('Error while removing user '+id +', Error :'+errResponse.data);
}
);
}
function getAllUsers(){
return UserService.getAllUsers();
}
function editUser(id) {
self.successMessage='';
self.errorMessage='';
UserService.getUser(id).then(
function (user) {
self.user = user;
},
function (errResponse) {
console.error('Error while removing user ' + id + ', Error :' + errResponse.data);
}
);
}
function reset(){
self.successMessage='';
self.errorMessage='';
self.user={};
$scope.myForm.$setPristine(); //reset Form
}
}
]);
And and I using ui-routing and this is where I assign controller to my view:
}).state('success',{
url: '/success',
templateUrl: 'partials/successMessage',
controller: 'UserController',
controllerAs: 'sCtrl'
});
And the ftl part of code is here:
<button type="button" ng-click='sCtrl.toLogin()' class="btn btn-primary">Login</button>
It won't even print to console, but when assigning older function it works perfectly, although it is much more complicated. Ps. Sorry for bad clarification at first, I am new to community and still learning a proper way to ask question.
You're not registering the method to the controller, to do that.
Add this below in self.onlyNumbers
self.toLogin = toLogin;
You need to use $scope
$scope.toLogin = function(){
console.log("Entered function");
$state.go('login');
}

routeprovider resolve not restricting access with parse.com

I want to restrict page to only Administrators. I am finding that my auth factory is not completing before resolve returns answer to route. When i follow/watch the code path page gets loaded before the factory finishes.
I am thinking i need to do better with promises and /or ".then()".
Any help would be appreciated. Thanks
My route code:
.when("/admin", {
templateUrl : "templates/admin.htm",
controller: 'AdminCtrl',
resolve : {
'auth' : function(AuthService){
return AuthService.isAdmin();
}
}
}).run(function($rootScope, $location){
$rootScope.$on('$routeChangeError', function(event, current, previous, rejection){
if(rejection === 'Not Administrator'){
$location.path('/404');
}
if(rejection === 'Not Authenticated'){
$location.path('/404');
}
});
});
My factory:
app.factory('AuthService', function($q){
var isAuthenticated = Parse.User.current();
var isAdmin = undefined;
var currentUser = Parse.User.current();
return {
authenticate : function(){
if(isAuthenticated){
return true;
} else {
return $q.reject('Not Authenticated');
}
},
isAdmin : function(){
if(isAuthenticated){
userHasRole(currentUser, "Administrator").then(function(isRole) {
console.log((isRole)? "user is admin" : "user is not admin");
isAdmin = isRole;
return isAdmin;
}).then(function(isAdmin){
if(isAdmin){
return true;
} else {
return $q.reject('Not Administrator');
}
});
} else {
return $q.reject('Not Authenticated');
}
}
};
});
function userHasRole(user, roleName) {
var query = new Parse.Query(Parse.Role);
query.equalTo("name", roleName);
query.equalTo("users", user);
return query.find().then(function(roles) {
if(roles.length > 0){
return true;
}else{
return false;
}
});
}
So close.
isAdmin is returning undefined because you're missing the return statement before userHasRole, so you're calling it, but then isAdmin hits the end of the if( isAuthenticated ) block without a return value since it doesn't know it's supposed to return the result of userHasRole.

WebRTC remote video stream not working despite having src

I'm trying to make a simple AngularJS WebRTC video chat app based on this tutorial.
I'm able to connect to connect clients, add streams and play my own stream, but somehow I can't play the remote stream.
When I check the elements I can see that the videoplayer does in fact have a blob source, but it won't play it.
Can anyone tell me why it won't show?
HTML element:
Room controller:
angular.module('publicApp').controller('RoomCtrl', function ($sce, VideoStream, $location, $routeParams, $scope, Room)
{
if (!window.RTCPeerConnection || !navigator.getUserMedia) {
$scope.error = 'WebRTC is not supported by your browser. You can try the app with Chrome and Firefox.';
return;
}
var stream;
VideoStream.get()
.then(function (s) {
stream = s;
Room.init(stream);
stream = URL.createObjectURL(stream);
if (!$routeParams.roomId) {
Room.createRoom()
.then(function (roomId) {
$location.path('/room/' + roomId);
});
} else {
Room.joinRoom($routeParams.roomId);
}
}, function () {
$scope.error = 'No audio/video permissions. Please refresh your browser and allow the audio/video capturing.';
});
$scope.peers = [];
Room.on('peer.stream', function (peer) {
console.log('Client connected, adding new stream');
$scope.peers.push({
id: peer.id,
stream: URL.createObjectURL(peer.stream)
});
console.log($scope.peers);
});
Room.on('peer.disconnected', function (peer) {
console.log('Client disconnected, removing stream');
$scope.peers = $scope.peers.filter(function (p) {
return p.id !== peer.id;
});
});
$scope.getLocalVideo = function () {
return $sce.trustAsResourceUrl(stream);
};
});
Room factory:
angular.module('publicApp').factory('Room', function ($rootScope, $q, Io, config)
{
var iceConfig = { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }]},
peerConnections = {},
currentId, roomId,
stream;
function getPeerConnection(id)
{
if (peerConnections[id]) {
return peerConnections[id];
}
var pc = new RTCPeerConnection(iceConfig);
peerConnections[id] = pc;
pc.addStream(stream);
pc.onicecandidate = function (evnt) {
socket.emit('msg', { by: currentId, to: id, ice: evnt.candidate, type: 'ice' });
};
pc.onaddstream = function (evnt) {
console.log('Received new stream');
api.trigger('peer.stream', [{
id: id,
stream: evnt.stream
}]);
if (!$rootScope.$$digest) {
$rootScope.$apply();
}
};
return pc;
}
function makeOffer(id)
{
var pc = getPeerConnection(id);
pc.createOffer(function (sdp) {
pc.setLocalDescription(sdp);
console.log('Creating an offer for', id);
socket.emit('msg', { by: currentId, to: id, sdp: sdp, type: 'sdp-offer' });
}, function (e) {
console.log(e);
},
{ mandatory: { OfferToReceiveVideo: true, OfferToReceiveAudio: true }});
}
function handleMessage(data)
{
var pc = getPeerConnection(data.by);
switch (data.type) {
case 'sdp-offer':
pc.setRemoteDescription(new RTCSessionDescription(data.sdp), function () {
console.log('Setting remote description by offer');
pc.createAnswer(function (sdp) {
pc.setLocalDescription(sdp);
socket.emit('msg', { by: currentId, to: data.by, sdp: sdp, type: 'sdp-answer' });
});
});
break;
case 'sdp-answer':
pc.setRemoteDescription(new RTCSessionDescription(data.sdp), function () {
console.log('Setting remote description by answer');
}, function (e) {
console.error(e);
});
break;
case 'ice':
if (data.ice) {
console.log('Adding ice candidates');
pc.addIceCandidate(new RTCIceCandidate(data.ice));
}
break;
}
}
var socket = Io.connect(config.SIGNALIG_SERVER_URL),
connected = false;
function addHandlers(socket)
{
socket.on('peer.connected', function (params) {
makeOffer(params.id);
});
socket.on('peer.disconnected', function (data) {
api.trigger('peer.disconnected', [data]);
if (!$rootScope.$$digest) {
$rootScope.$apply();
}
});
socket.on('msg', function (data) {
handleMessage(data);
});
}
var api = {
joinRoom: function (r) {
if (!connected) {
socket.emit('init', { room: r }, function (roomid, id) {
currentId = id;
roomId = roomid;
});
connected = true;
}
},
createRoom: function () {
var d = $q.defer();
socket.emit('init', null, function (roomid, id) {
d.resolve(roomid);
roomId = roomid;
currentId = id;
connected = true;
});
return d.promise;
},
init: function (s) {
stream = s;
}
};
EventEmitter.call(api);
Object.setPrototypeOf(api, EventEmitter.prototype);
addHandlers(socket);
return api;
});
Directive:
angular.module('publicApp').directive('videoPlayer', function ($sce) {
return {
template: '<div><video ng-src="{{trustSrc()}}" autoplay></video></div>',
restrict: 'E',
replace: true,
scope: {
vidSrc: '#'
},
link: function (scope) {
console.log('Initializing video-player');
scope.trustSrc = function () {
if (!scope.vidSrc) {
console.log('No vidSrc found');
return undefined;
}
return $sce.trustAsResourceUrl(scope.vidSrc);
};
}
};
});
Room.html:
<div class="video-wrapper">
<video-player class="col-md-4" ng-repeat="peer in peers" vid-src="{{peer.stream}}"></video-player>
</div>
<div class="video-wrapper">
<div class="col-md-2">
<video ng-src="{{getLocalVideo()}}" autoplay muted></video>
</div>
</div>

Empty var in second service function

I have a service:
.service('VacanciesService', function($http) {
var vacancies = [];
var usedVacancies = [];
return {
getVacanciesForUniversity: function(university_id) {
return $http.get("http://jobs.app/api/vacancies/" + university_id).then(function(response){
vacancies = response.data.vcancies;
return vacancies;
}, function(error){
return error;
});
},
getRandomVacancy: function() {
console.log(vacancies);
}
}
})
This is the calling controller
.controller('jobsCtrl', function($ionicLoading, locker, UniversitiesService, VacanciesService) {
var vm = this;
user = locker.get('userDetails');
UniversitiesService.getUniversity(user.university.id).then(function(university) {
vm.university = university.university;
});
VacanciesService.getVacanciesForUniversity(user.university.id).then(function(vacancies) {
vm.vacancies = vacancies;
}, function error(error) {
});
vm.addCard = function(name) {
newVacancy = VacanciesService.getRandomVacancy();
};
vm.addCard();
})
And I can't figure out why the vacancies variable in in the console.log is empty in the second function? I assumed as it was set in the initial function (called prior) that it should be populated?
TIA!
if you call getVacanciesForUniversity getRandomVacancy like below, you will get empty array
VacanciesService.getVacanciesForUniversity(uniId)
VacanciesService.getRandomVacancy() //you will get empty
you must getRandomVacancy inside getVacanciesForUniversity returned promise
VacanciesService.getVacanciesForUniversity(uniId).then(function(){
VacanciesService.getRandomVacancy()
})
alo you misstype response.data.vcancies; instead response.data.vacancies;
The answer is READ YOUR CODE PROPERLY.
There was a glaringly obvious typo in my code that I missed from staring at it too long.
Big thanks to Daniel Dawes and aseferov for attempting to help!
In your service :
getVacanciesForUniversity: function(university_id) {
return $http.get("http://jobs.app/api/vacancies/" + university_id);
}
In your controller :
$scope.getVacancies = function () {
your_service.getVacanciesForUniversity().then(
function(response) {
if (response.status = 200) {
$scope.vacancies = response.data.vacancies;
}, function errorCallback (response) {
...
}
);
};
$scope.getVacancies(); // you call one time your function here
$scope.getRandomVacancy : function() {
console.log($scope.vacancies);
};

How do I unit test further .then and .catch branching in an Angular controller?

(function() {
'use strict';
angular
.module('walletInformation')
.controller('WalletInformationController', WalletInformationController);
/* #ngInject */
function WalletInformationController(
$q,
$scope,
config,
logger,
session,
$interpolate,
flowstack,
profileService,
walletInformationFormlyService,
postMsg
) {
// jshint validthis: true
var vm = this;
var app = $scope.app;
var user = session.get('profile').profile || {};
vm.saveWalletInformation = saveWalletInformation;
vm.onClickCancel = onClickCancel;
vm.deleteWallet = deleteWallet;
vm.model = {
walletInformation : {
firstName: user.name.first,
lastName: user.name.last,
emailAddress: user.emailAddress,
phoneNumber: user.mobilePhone.phoneNumber,
keepMeUpdated: user.preferences.receiveEmailNotification
}
};
activate();
////////////////
/**
* #function activate
* #description init function for the controller
* Calls paymentCard to get the
* */
function activate() {
createFormFields();
logger.info('Activated the Wallet Information View.');
}
function createFormFields() {
vm.fields = walletInformationFormlyService.getFormlyFields($scope.app.text);
}
function saveWalletInformation() {
var updatedProfile = createLegacyProfileInformation();
profileService.updateProfileInformation(updatedProfile).then(onSuccess).catch(onError);
function onSuccess(response) {
session.set('profile', {
profile: response.profile
});
if (vm.model.walletInformation.currentPassword && vm.model.walletInformation.newPassword) {
changePasswordRequest();
} else {
flowstack.add('accountManagement');
flowstack.next();
}
}
function onError(error) {
logger.error('Verify save Wallet Information Error: ', error);
}
//changePassword
function changePasswordRequest() {
var updatedPassword = {
data: {
currentPassword: vm.model.walletInformation.currentPassword,
newPassword: vm.model.walletInformation.newPassword
}
};
profileService
.changePassword(updatedPassword)
.then(onChangePasswordSuccess, onChangePasswordError);
function onChangePasswordSuccess(response) {
flowstack.add('accountManagement');
flowstack.next();
logger.info('Change password request: ', response);
}
function onChangePasswordError(response) {
logger.error('Change Password Error: ', response);
}
}
}
function deleteWallet() {
var appText = app.text.walletInformation;
console.log(appText);
flowstack.add('confirmation');
flowstack.next({
data: {
title: appText.deleteWalletConfirmationTitle,
body: appText.deleteWalletConfirmationBody,
cancelButton: appText.deleteWalletConfirmationCancelButton,
confirmButton: appText.deleteWalletConfirmationConfirmButton,
onConfirm: function() {
profileService.deleteWallet().then(deleteProfileSuccess, deleteProfileFailure);
function deleteProfileSuccess(response) {
if (response.profile) {
logger.info('profile is successfully deleted.', response);
postMsg.send('closeSwitch');
}
}
function deleteProfileFailure(error) {
logger.error('something went wrong while deleting profile.', error);
}
},
onCancel: function() {
flowstack.add('walletInformation');
flowstack.next();
}
}
});
}
function createLegacyProfileInformation() {
var updatedProfile = user;
var formlyField = vm.model.walletInformation;
//Update the profile
updatedProfile.name = {
first: formlyField.firstName,
last: formlyField.lastName
};
updatedProfile.mobilePhone.phoneNumber = formlyField.phoneNumber;
updatedProfile.preferences.receiveEmailNotification = formlyField.keepMeUpdated;
return {
data: updatedProfile
};
}
function onClickCancel() {
flowstack.back();
}
}
})();
Coverage is saying that onSuccess of saveWalletInformation and changePasswordRequest isnt't covered but I'm not sure exactly how to test it, the only thing I've tested now is that the saveWalletInformation function is calling the profile service:
describe.only('WalletInformationController ---', function() {
var controller, scope;
var userProfile = {
profile: {
name: {
first: 'someonefirstname',
last: 'someoneslastname'
},
emailAddress: 'someone#something.com',
mobilePhone: {
countryCode: 'US+1',
phoneNumber: '123 212 2342'
},
preferences: {
receiveEmailNotification: true
}
}
};
beforeEach(function() {
bard.appModule('walletInformation');
bard.inject(
'$q',
'$controller',
'$rootScope',
'api',
'flowstack',
'logger',
'session',
'profileService'
);
session.set('profile', userProfile);
});
beforeEach(function() {
sandbox = sinon.sandbox.create();
scope = $rootScope.$new();
scope.app = {
text: {
global: {},
walletInformation: {
deleteWalletConfirmationTitle: 'Confirm Wallet Deletion?'
},
userInformation: {
emailValidation: 'Please enter valid email'
},
signin: {
rememberMeLabel: 'remember me'
}
}
};
controller = $controller('WalletInformationController', {
$scope: scope
});
loggerErrorStub = sandbox.stub(logger, 'error');
sandbox.stub(logger, 'info');
controller = $controller('WalletInformationController', {
$scope: scope
});
});
describe('saveWalletInformation method', function() {
beforeEach(function() {
// apiStub.restore();
sandbox.stub(profileService, 'updateProfileInformation', function() {
return $q.when(userProfile);
});
});
it('should saveWalletInformation successfully', function() {
controller.saveWalletInformation();
expect(profileService.updateProfileInformation).to.have.been.called;
});
it('should log error msg when saveWalletInformation call fails', function() {
profileService.updateProfileInformation.restore();
sandbox.stub(profileService, 'updateProfileInformation', function() {
return $q.reject();
});
controller.saveWalletInformation();
scope.$apply();
expect(loggerErrorStub).to.have.been.calledOnce;
});
it('should call changePasswordRequest when currentPassword and newPassword are set', function() {
sandbox.stub(profileService, 'changePassword', function() {
return $q.when({
success: true,
extensionPoint: null
});
});
sandbox.stub(flowstack, 'add');
sandbox.stub(flowstack, 'next');
controller.saveWalletInformation();
// scope.$apply();
// expect(flowstack.next).to.have.been.calledOnce;
// expect(flowstack.add).to.have.been.calledOnce;
expect(profileService.updateProfileInformation).to.have.been.called;
// expect(profileService.changePassword).to.have.been.called;
});
});
You can let the service call go a step further and instead of verifying that service function was called, as you do here:
expect(profileService.updateProfileInformation).to.have.been.called;
You can instead mock the response from the api call with $httpBackend:
httpBackend.expectGET('your/url/here').respond(200, {response object...});
or
httpBackend.expectGET('your/url/here').respond(500, {error object...});
Then you'll be hitting both the error and success functions when your tests run

Resources