var app = angular.module('part3', []);
app.controller('Part3Controller' ,function ($scope) {
$scope.Message1 = "apek";
$scope.IsLogedIn = false;
$scope.Message = '';
$scope.Submitted = false;
$scope.IsFormValid = false;
$scope.LoginData = {
UserName: '',
Password: ''
};
$scope.$watch('f1.$valid', function (newVal) {
$scope.IsFormValid = newVal;
});
$scope.Login = function () {
$scope.Submitted = true;
if ($scope.IsFormValid) {
alert("eeeeee")
alert("dsds")
serv.GetUser($scope.LoginData).then(function (d) {
alert("dsdsdfsdfs");
if (d.data.UserName != null) {
alert("he;llo1");
$scope.IsLoggedIn = true;
$scope.Message = "Successfully Login" + d.data.FullName;
}
else {
alert("Invalid Credential")
}
})
}
}
})
app.factory('serv', function ($http) {
alert("helloo");
var fac = {};
fac.GetUser = function (d) {
$scope.Submitted = true;
return $http({
url: '/Data/UserLogin',
method: 'POST',
data: JSON.stringify(d),
header: { 'content-type': 'application/json' }
});
};
return fac;
});
I had written above code for login functionality in my app but it is not calling factory "serv" its showing error "angular.min.js:92 ReferenceError: serv is not defined"
"angular.min.js:92 ReferenceError: serv is not defined"
When you want to use a factory or service with a controller in angular, you need to inject them with that. We have:
app.factory('name_of_factory', factory_function);
and controller:
app.controller('name_of_controller', controller_function($scope,factory_name_you_want_to_use) { //blah blah });
That was some of explanation, you just need to inject name of factory with your controller. Your Controller JS will look like this:
app.controller('Part3Controller' ,function ($scope,serv){//yourcode});
need to inject serv factory to the controller
controller('Part3Controller' ,function ($scope,serv) {
Related
I have a problem where I'm trying to ng-show a view using ng-view when the user is logged in. By default the value vm.isLoggedIn is false when the controller initializes and vm.isLoggedIn gets set to true when they are logged in.
But this doesn't update the UI to reflect the changes, the ng-show will still have class="ng-hide", which is put there by AngularJS when you decalred it with ng-show.
How do I get the UI to reflect the changes when vm.isLoggedIn is updated to true on a return of a promise?
Here is the HTML:
<div id="loggedInContainer" ng-show="vm.isLoggedIn">
<div ng-view></div>
</div>
This is my controller where everything is being set:
(function () {
"use strict";
var app = angular.module("productManagement");
var MainCtrl = function ($scope, $timeout, userAccount) {
var vm = this;
vm.isLoggedIn = false;
vm.message = "";
vm.userData = {
userName: "",
email: "",
password: "",
confirmPassword: ""
};
var applyChanges = function () {
$timeout(function () {
$scope.$apply();
});
}
vm.registerUser = function () {
vm.userData.confirmPassword = vm.userData.password;
vm.userData.userName = vm.userData.email;
userAccount.registration.registerUser(vm.userData, function (data) {
vm.confirmPassword = "";
vm.message = "Registration Successful";
vm.login();
}, function (errorResponse) {
vm.isLoggedIn = false;
vm.message = errorResponse.statusText + "\r\n";
if (errorResponse.data.exceptionMessage) {
vm.message += errorResponse.data.exceptionMessage;
}
// Validation Errors
if (errorResponse.data.modelState) {
for (var key in errorResponse.data.modelState) {
vm.message += errorResponse.data.modelState[key] + "\r\n";
}
}
});
}
vm.login = function () {
vm.userData.grant_type = "password";
vm.userData.userName = vm.userData.email;
userAccount.login.loginUser(vm.userData, function (data) {
vm.isLoggedIn = true; // This is where vm.isLoggedIn is set to true
vm.message = "";
vm.password = "";
vm.token = data.access_token;
//$("#loggedInContainer").removeClass("ng-hide"); // Hack used to manually remove the class
}, function (errorResponse) {
vm.password = "";
vm.isLoggedIn = false;
vm.message = errorResponse.statusText + "\r\n";
if (errorResponse.data.exceptionMessage) {
vm.message += errorResponse.data.exceptionMessage;
}
if (errorResponse.data.error) {
vm.message += errorResponse.data.error;
}
});
}
}
app.controller("MainCtrl", ["$scope", "$timeout", "userAccount", MainCtrl]);
})();
This is the service I'm using to Login the user, which uses $resource
(function () {
"use strict";
var app = angular.module("common.services");
var userAccount = function ($resource, $http, appSettings) {
return {
registration: $resource(appSettings.serverPath + "/api/Account/Register", null,
{
"registerUser": { method: "POST" }
}),
login: $resource(appSettings.serverPath + "/Token", null,
{
"loginUser": {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
transformRequest: function (data, headersGetter) {
var str = [];
for (var d in data) {
str.push(encodeURIComponent(d) + "=" + encodeURIComponent(data[d]));
}
return str.join("&");
}
}
})
}
}
app.factory("userAccount", ["$resource", "$http", "appSettings", userAccount]);
})();
I've tried to manually use $scope.$apply(), $scope.$digest(), even $timeout(), but none of them are working properly. I either get a $digest is already running error or nothing happens at all.
The only work around I can use is to manually remove the class on the div using jQuery, but that's not the correct way to do it using AngualrJS.
So, I'm trying to learn Ionic Framework, but, I've got a problem already, I'm running the Ionic Backand Starter app (like an example app) and I've got two different results when testing it.
Ripple: When I run it from VS on Ripple, it works perfectly fine, the Database is how it is supposed to be, everything is running fine.
Device: When I run it from VS on my Android Device (Samsung Galaxy S5 Mini, without root), the application has a problem when loading the Backand Database. It looks completely empty.
Im going to leave prints of the 2 trials and also my Controller.js, App.js and Services.js, also, I'm leaving the github project link, in case you want more detailed stuff.
GitHub Project:
GitHub Backand Ionic Starter Project
Prints:
Device: http://prntscr.com/a3iq45
Ripple: http://prntscr.com/a3iqgd
CODES:
App.js:
// Ionic template App
// angular.module is a global place for creating, registering and retrieving Angular modules
// 'SimpleRESTIonic' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
angular.module('SimpleRESTIonic', ['ionic', 'backand', 'SimpleRESTIonic.controllers', 'SimpleRESTIonic.services'])
.run(function ($ionicPlatform) {
$ionicPlatform.ready(function () {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
}
if (window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleLightContent();
}
});
})
.config(function (BackandProvider, $stateProvider, $urlRouterProvider, $httpProvider) {
BackandProvider.setAppName('ionicstarter'); // change here to your app name
BackandProvider.setSignUpToken('4ce88904-75c5-412c-8365-df97d9e18a8f'); //token that enable sign up. see http://docs.backand.com/en/latest/apidocs/security/index.html#sign-up
BackandProvider.setAnonymousToken('87c37623-a2d2-42af-93df-addc65c6e9ad'); // token is for anonymous login. see http://docs.backand.com/en/latest/apidocs/security/index.html#anonymous-access
$stateProvider
// setup an abstract state for the tabs directive
.state('tab', {
url: '/tabs',
abstract: true,
templateUrl: 'templates/tabs.html'
})
.state('tab.dashboard', {
url: '/dashboard',
views: {
'tab-dashboard': {
templateUrl: 'templates/tab-dashboard.html',
controller: 'DashboardCtrl as vm'
}
}
})
.state('tab.login', {
url: '/login',
views: {
'tab-login': {
templateUrl: 'templates/tab-login.html',
controller: 'LoginCtrl as login'
}
}
});
$urlRouterProvider.otherwise('/tabs/dashboard');
$httpProvider.interceptors.push('APIInterceptor');
})
.run(function ($rootScope, $state, LoginService, Backand) {
function unauthorized() {
console.log("user is unauthorized, sending to login");
$state.go('tab.login');
}
function signout() {
LoginService.signout();
}
$rootScope.$on('unauthorized', function () {
unauthorized();
});
$rootScope.$on('$stateChangeSuccess', function (event, toState) {
if (toState.name == 'tab.login') {
signout();
}
else if (toState.name != 'tab.login' && Backand.getToken() === undefined) {
unauthorized();
}
});
})
Controller.js:
angular.module('SimpleRESTIonic.controllers', [])
.controller('LoginCtrl', function (Backand, $state, $rootScope, LoginService) {
var login = this;
function signin() {
LoginService.signin(login.email, login.password)
.then(function () {
onLogin();
}, function (error) {
console.log(error)
})
}
function anonymousLogin(){
LoginService.anonymousLogin();
onLogin();
}
function onLogin(){
$rootScope.$broadcast('authorized');
$state.go('tab.dashboard');
}
function signout() {
LoginService.signout()
.then(function () {
//$state.go('tab.login');
$rootScope.$broadcast('logout');
$state.go($state.current, {}, {reload: true});
})
}
login.signin = signin;
login.signout = signout;
login.anonymousLogin = anonymousLogin;
})
.controller('DashboardCtrl', function (ItemsModel, $rootScope) {
var vm = this;
function goToBackand() {
window.location = 'http://docs.backand.com';
}
function getAll() {
ItemsModel.all()
.then(function (result) {
vm.data = result.data.data;
});
}
function clearData(){
vm.data = null;
}
function create(object) {
ItemsModel.create(object)
.then(function (result) {
cancelCreate();
getAll();
});
}
function update(object) {
ItemsModel.update(object.id, object)
.then(function (result) {
cancelEditing();
getAll();
});
}
function deleteObject(id) {
ItemsModel.delete(id)
.then(function (result) {
cancelEditing();
getAll();
});
}
function initCreateForm() {
vm.newObject = {name: '', description: ''};
}
function setEdited(object) {
vm.edited = angular.copy(object);
vm.isEditing = true;
}
function isCurrent(id) {
return vm.edited !== null && vm.edited.id === id;
}
function cancelEditing() {
vm.edited = null;
vm.isEditing = false;
}
function cancelCreate() {
initCreateForm();
vm.isCreating = false;
}
vm.objects = [];
vm.edited = null;
vm.isEditing = false;
vm.isCreating = false;
vm.getAll = getAll;
vm.create = create;
vm.update = update;
vm.delete = deleteObject;
vm.setEdited = setEdited;
vm.isCurrent = isCurrent;
vm.cancelEditing = cancelEditing;
vm.cancelCreate = cancelCreate;
vm.goToBackand = goToBackand;
vm.isAuthorized = false;
$rootScope.$on('authorized', function () {
vm.isAuthorized = true;
getAll();
});
$rootScope.$on('logout', function () {
clearData();
});
if(!vm.isAuthorized){
$rootScope.$broadcast('logout');
}
initCreateForm();
getAll();
});
Services.js:
angular.module('SimpleRESTIonic.services', [])
.service('APIInterceptor', function ($rootScope, $q) {
var service = this;
service.responseError = function (response) {
if (response.status === 401) {
$rootScope.$broadcast('unauthorized');
}
return $q.reject(response);
};
})
.service('ItemsModel', function ($http, Backand) {
var service = this,
baseUrl = '/1/objects/',
objectName = 'items/';
function getUrl() {
return Backand.getApiUrl() + baseUrl + objectName;
}
function getUrlForId(id) {
return getUrl() + id;
}
service.all = function () {
return $http.get(getUrl());
};
service.fetch = function (id) {
return $http.get(getUrlForId(id));
};
service.create = function (object) {
return $http.post(getUrl(), object);
};
service.update = function (id, object) {
return $http.put(getUrlForId(id), object);
};
service.delete = function (id) {
return $http.delete(getUrlForId(id));
};
})
.service('LoginService', function (Backand) {
var service = this;
service.signin = function (email, password, appName) {
//call Backand for sign in
return Backand.signin(email, password);
};
service.anonymousLogin= function(){
// don't have to do anything here,
// because we set app token att app.js
}
service.signout = function () {
return Backand.signout();
};
});
Thanks!!
I wrote a page that allows me to change my password. The code works and it does everything I want it to do, so I started writing tests. Since I'm not as experienced in Angular testing this had proven to be quite difficult and I can't get passed this error:
TypeError: 'undefined' is not an object (evaluating 'plan.apply')
at /Users/denniegrondelaers/asadventure/myproject-web/src/users/controllers/userPasswordController.js:9
at /Users/denniegrondelaers/asadventure/myproject-web/test/unitTests/specs/users/controllers/userPasswordControllerSpec.js:98
The controller:
userPasswordController.js
users.controllers.controller('userPasswordController',
['$scope', 'Session', '$state', 'UserService', 'languages',
function ($scope, Session, $state, UserService, languages) {
$scope.languages = languages;
$scope.password = "";
$scope.notEqual = false;
$scope.isSuccessful = false;
$scope.changePassword = function() {
var pw = {
userId: Session.getCurrentSession().userId,
oldPassword: encrypt($scope.password.oldPassword),
newPassword: encrypt($scope.password.newPassword),
newPasswordRepeat: encrypt($scope.password.newPasswordRepeat)
};
if (pw.newPassword === pw.newPasswordRepeat) {
$scope.notEqual = false;
UserService.setNewPassword(pw).then(function(res) {
$scope.formErrors = undefined;
$scope.isSuccessful = true;
}, function (error) {
$scope.formErrors = error.data;
}
);
} else {
$scope.notEqual = true;
}
};
var encrypt = function (password) {
var encrypted = CryptoJS.md5(password);
return encrypted.toString(CryptoJS.enc.Hex);
};
}
]
);
The service:
userService.js
userService.setNewPassword = function (password) {
return $http
.put(EnvironmentConfig.endpointUrl +
"/password/change", password)
};
The test:
userPasswordControllerSpec.js
describe('Users', function () {
describe('Controllers', function () {
fdescribe('userPasswordController', function () {
var $scope,
controller,
$q,
willResolve,
mockSession,
mockState,
mockUserService,
mockLanguages;
beforeEach(function () {
module('mysite.users.controllers');
module(function ($provide) {
$provide.value('translateFilter', function (a) {
return a;
});
$provide.value('$state', function (a) {
return a;
});
});
mockSession = {
getCurrentSession: function () {
return {userId: 4};
}
};
mockState = {
params: {
id: 1
},
go: function () {
}
};
mockLanguages = {
getLanguages : function () {
var deferred = $q.defer();
deferred.resolve({
data: [{}]
});
return deferred.promise;
}
};
mockUserService = {
setNewPassword : function () {
var deferred = $q.defer();
if (willResolve) {
deferred.resolve({
data: [{}]
});
}
return deferred.promise;
}
};
inject(function (_$q_, $controller, $rootScope) {
controller = $controller;
$q = _$q_;
$scope = $rootScope.$new();
});
controller('userPasswordController', {$scope: $scope, Session: mockSession, $state: mockState,
UserService: mockUserService, languages: mockLanguages
});
willResolve = true;
});
it('should change password', function () {
spyOn(mockUserService, 'setNewPassword').and.callThrough();
spyOn(mockState, 'go').and.callThrough();
spyOn(mockSession, 'getCurrentSession').and.callFake();
expect(mockUserService.setNewPassword).not.toHaveBeenCalled();
expect($scope.isSubmitable()).not.toBeTruthy();
$scope.compareStoreSelection = function () {
return true;
};
$scope.password = {
oldPassword: "123456",
newPassword: "password",
newPasswordRepeat: "password"
};
expect($scope.isSubmitable()).toBeTruthy();
>>> $scope.changePassword(); <<< LOCATION OF ERROR, line 98
expect(mockUserService.setNewPassword).toHaveBeenCalled();
$scope.$apply();
});
});
});
});
I've marked the line that gives the code in the test.
Anybody any idea how to fix this? A colleague suggested altering my controller code, but I'd like to keep it as it is, since it seems logical that this code shouldn't be altered for testing to work, right?
Solution
Yarons' suggestion to change the mockSession.getCurrentSession.callFake to mockSession.getCurrentSession.callThrough fixed it!
I try to assign a property of a service object by using the $http but I have confusing results. Why this doesn't work (here is my code):
.service('config', function ($http) {
var config = {
get_host: function () {
if (online == 0) {
return offlineHost;
}
return onlineHost;
},
online: 'false',
host: 'false',
checkConnection: function () {
//this wont work;
/*
$http.get(this.host + http_url ).then(function(response) {
return response.data.ping;
});
*/
//this will work
return 'oke';
},
_load: function () {
this.host = this.get_host();
this.online = this.checkConnection();
this.url_api = this.host + http_url;
if (this.online == 1) {
this.offline_message = 'Maaf aplikasi tidak bisa terkoneksi dengan server atau anda offline';
}
}
};
//run constructor and get value;
config._load();
return config;
}) //end config class
In my controller :
var online = config.online;
alert(online) //return undefined, but the $http request on firebug is showed return value
service:
.service('config', function ($http, $q) {
var config = {
get_host: function () {
if (online == 0) {
return offlineHost;
}
return onlineHost;
},
online: 'false',
host: 'false',
checkConnection: function () {
var deferred = $q.defer();
$http.get(this.host + http_url ).then(function(response) {
$q.resolve(response.data.ping);
});
return $q.promise;
},
_load: function () {
this.host = this.get_host();
this.online = this.checkConnection();
this.url_api = this.host + http_url;
if (this.online == 1) {
this.offline_message = 'Maaf aplikasi tidak bisa terkoneksi dengan server atau anda offline';
}
}
};
//run constructor and get value;
config._load();
return config;
}) //end config class
controller:
config.online.then(function(data){
alert(data);
var online = data;
handleDate(online); // this is a predefined function to handle your data when it's downloaded
});
That's because the $http service calls are asynchronous.
The easiest way to handle this is to make your service return a promise:
return $http.get(this.host + http_url);
(return in front of $http is crucial here). Then anywhere in the code:
config.checkConnection().then(function(response) {
// there you get the response.data.ping
});
See your modified and simplified code here: http://plnkr.co/edit/cCHXCLCG3xJUwAPPlJ3x?p=preview
You can read more about that:
http://chariotsolutions.com/blog/post/angularjs-corner-using-promises-q-handle-asynchronous-calls/
http://lennybacon.com/post/2014/03/21/chaining-asynchronous-javascript-calls-with-angular-js
https://docs.angularjs.org/api/ng/service/$q
I'm having an odd issue in AngularJS where MainCtrl isn't fire at all. I go to localhost/ and it redirects to localhost/#/ but the page is blank. There are no errors/messages in console. I can confirm that /views/main.html is publicly accessible. I don't know why this isn't working. Am I missing anything?
angular.module('TurkApp', ['ngCookies']).config([
'$routeProvider',
function ($routeProvider) {
$routeProvider.when('/', {
templateUrl: '/views/main.html',
controller: 'MainCtrl'
}).otherwise({ redirectTo: '/' });
}
]);
angular.module('TurkApp', []).controller('MainCtrl', [
'$scope',
'$http',
'$location',
'$cookies',
function ($scope, $http, $location, $cookies) {
$scope.questionIsLoading = true;
$scope.answerButtonsDisabled = true;
$scope.showHelp = false;
$scope.currentRetries = 0;
$scope.acceptedHit;
$scope.currentQuestionText = null;
$scope.currentQuestionID = null;
var AssignmentID, Interest;
var getInterest = function () {
return $cookies.interest;
};
var getAssignmentID = function () {
var qsRegex = new RegExp('(?:\\?|&)AssignmentID=(.*?)(?=&|$)', 'gi'), m, assignmentID = false;
while ((match = qsRegex.exec(document.location.search)) != null) {
assignmentID = match[1];
}
if (!assignmentID) {
assignmentID = $location.search()['AssignmentID'];
}
$scope.acceptedHit = assignmentID == 'ASSIGNMENT_ID_NOT_AVAILABLE' || !assignmentID ? false : true;
return assignmentID;
};
$scope.loadNextQuestion = function () {
$scope.questionIsLoading = $scope.answerButtonsDisabled = true;
$http.get('/workers/' + Interest + '/next-question').success(function (data, status) {
$scope.currentQuestionText = data.text;
$scope.currentQuestionID = data.id;
$scope.questionIsLoading = $scope.answerButtonsDisabled = false;
}).error(function () {
console.log('Answer send failed');
});
};
$scope.sendAnswer = function (answer) {
if (!$scope.questionIsLoading && !$scope.answerButtonsDisabled) {
$scope.questionIsLoading = $scope.answerButtonsDisabled = true;
$http.post('/workers/' + Interest + '/answer-question', {
question_id: $scope.currentQuestionID,
question_text: $scope.currentQuestionText,
answer: answer
}).success(function (data, status) {
$scope.loadNextQuestion();
}).error(function () {
console.log('Answer send failed');
});
}
};
$scope.toggleHelp = function () {
$scope.showHelp = $scope.showHelp ? false : true;
};
var init = function () {
AssignmentID = getAssignmentID();
Interest = getInterest();
$scope.loadNextQuestion();
};
init();
}
]);
You are creating the module 'TurkApp' twice, thereby losing the configuration registered with the first module:
angular.module('TurkApp', ['ngCookies'])
When you include the second parameter to the angular.module function, it creates the module. If you omit the second parameter, it assumes the modules exists and "extends" it.
Change:
angular.module('TurkApp', [])
to:
angular.module('TurkApp')
See the usage section here - http://docs.angularjs.org/api/angular.module