I am using ionic modal in which once i open the ionic modal and submit the button the ionic remove model is not working as well as even the animation is not working in the modal.I have tried using ionic hide instead of remove but still it is not working can anyone tell me what is the issue in ionic modal.
Modal:
'use strict';
(function () {
angular.module('main')
.service('ModalService', ModalService);
ModalService.$inject = ['$ionicModal', '$log'];
function ModalService ($ionicModal, $log) {
var init = function (tpl, $scope) {
var promise;
var a = $scope;
$scope = a;
promise = $ionicModal.fromTemplateUrl(tpl, {
scope: $scope,
animation: 'slide-in-right'
}).then(function (modal) {
$scope.modal = modal;
return modal;
});
$scope.openModal = function () {
$log.log('openModal function got clicked', $scope);
$scope.modal.show();
};
$scope.closeModal = function () {
$scope.modal.hide();
};
$scope.removeModal = function () {
$scope.modal.remove();
};
$scope.$on('$destroy', function () {
$scope.modal.remove();
});
return promise;
};
return {
init: init
};
}
})();
Controller to call the ionic remove and hide:
function modalFunction (htmlpath) {
vm.modalListType = 'category';
ModalService
.init(htmlpath, $scope)
.then(function (modal) {
$log.log('modal success');
catModal = modal;
catModal.show();
vm.search = '';
});
}
function closeModal () {
catModal.hide();
}
function removeModal () {
$log.log('removeModal got called', catModal);
catModal.remove();
}
Html file :
<div class="center-align">
<button class="button trans-but m-t-10" type="submit" ng-click="vm.addProduct()">{{'save_message' | translate}}</button>
</div>
Function which call the remove function:
function addProduct () {
$log.log('addProduct called: ', vm.product);
var data = [];
data.push({field: vm.product.type, type: 'text', name: $translate.instant('{{"producttype_message" | translate}}')});
data.push({field: vm.product.count, type: 'num', amounttype: 'Advance', name: $translate.instant('{{"ecount_message" | translate}}')});
data.push({field: vm.product.rate, type: 'num', amounttype: 'Advance', name: $translate.instant('{{"eprice_message" | translate}}')});
CommonService.validate(data).then(function () {
//vm.product.total = (vm.product.count - vm.product.deduction) * vm.product.rate;
vm.products.push(vm.product);
closeModal();
removeModal();
}, function (err) {
cordova.plugins.Keyboard.close();
CommonService.toast(err);
});
}
If you try to close the modal with the function, $scope.modal.hide();
Since if you use remove(), you will have to create the modal again.
A possible solution could be:
function closeModal () {
$scope.modal.hide();
}
Or
function closeModal () {
$scope.modal.remove();
}
This would be inside your modalFunction controller.
Related
I've been playing around with using uibModal from a factory instead of using it from within my controller. The dialog comes up, and the field data is returned to the service when OK is clicked, but, I don't know how to get the data back to my controller, where it will be added to my model Any pointers?
Here is my factory code:
'use strict';
angular.module('ngTableScopeApp')
.factory('DialogService', function($uibModal){
var DialogService = {};
DialogService.newObj = {};
DialogService.addNewItem = function(template, $q){
this.modalInstance = $uibModal.open({
templateUrl: template,
controller: function($scope, $uibModalInstance){
$scope.ok = function () {
$uibModalInstance.close($scope);
return this.newObj;
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
return null;
};
}
});
};
return DialogService;
});
Here is the controller code:
'use strict';
/**
* #ngdoc function
* #name ngTableScopeApp.controller:MainCtrl
* #description
* # MainCtrl
* Controller of the ngTableScopeApp
*/
angular.module('ngTableScopeApp')
.controller('MainCtrl', function (NgTableParams, DummyData, DialogService) {
var self = this;
self.data = DummyData.generateData(1);
var createUsingFullOptions = function() {
var initialParams = {
count: 10 // initial page size
};
var initialSettings = {
// page size buttons (right set of buttons in demo)
counts: [5, 10, 25, 50],
// determines the pager buttons (left set of buttons in demo)
paginationMaxBlocks: 13,
paginationMinBlocks: 2,
dataset: self.data //DummyData.generateData(1)
};
return new NgTableParams(initialParams, initialSettings);
};
self.customConfigParams = createUsingFullOptions();
self.addNewItem = function(){
DialogService.addNewItem('views/addNewItem.html', self);
};
});
You could use close method available on $uibModalInstance service, in which you can pass data while closing a popup. And then you can utilize result promise object which does gets called when modal gets closed. Whatever data passed from $uibModalInstance.close method is available there. Make sure you are returning promise returned by $uibModal.open method.
Factory
DialogService.addNewItem = function(template, $q){
this.modalInstance = $uibModal.open({
templateUrl: template,
controller: function($scope, $uibModalInstance){
$scope.ok = function () {
$uibModalInstance.close({ data: 'OK Called' });
};
$scope.cancel = function () {
$uibModalInstance.close({ data: 'Cancel Called' });
};
}
});
};
return this.modalInstance;
};
Controller
DialogService.addNewItem('views/addNewItem.html', self)
.result.then(function(data) {
console.log("data", data); // print { data: 'MyCustomData' }
});
Modal Controller
$scope.cancel = function () {
$uibModalInstance.close({data: 'MyCustomData'});
};
i have created the custom service like this
app.service('userService', function($http,UrlService) {
return {
init: function(callback) {
$http.get(UrlService.baseUrl +'/api/users/list').then(function(user_response) {
callback(user_response);
});
}
}
})
Inside of my project main controller i have used like this to get the angular material design modal.
$scope.replyComplaint = function(user,complaint_id) {
complaint_id=user._id;
console.log(complaint_id)
$mdDialog.show({
controller: DialogCtrl,
templateUrl: 'submodules/user_management/replydialog.html',
resolve: { complaint_id : function() {return complaint_id;} },
locals: {
users: $scope.users
},
parent: angular.element(document.body),
clickOutsideToClose: true,
})
.then(function(response) {
$scope.response = response;
console.log(response);
}, function() {
//fail
});
};
created another controller for dialog as in the angular material docs as follows
function DialogCtrl($scope, $rootScope, $mdDialog, users,complaintService, UrlService, $http) {
complaintService.init(function(complaint_response) {
$scope.complaints = complaint_response.data;
$scope.getUsers();
});
$scope.getUsers = function(complaint_id) {
console.log(complaint_id);
$scope.hide = function() {
$mdDialog.hide();
};
$scope.cancel = function() {
$mdDialog.cancel();
};
$scope.replyMail = function(complaint_id) {
console.log(complaint_id);
$http.post(UrlService.baseUrl + '/api/complaints/complaint/'+complaint_id , {
complaint: "replyText"
}, $scope)
.then(function(response) {
console.log(name);
$state.reload();
}, function(response) {
console.log(name);
});
}
}
}
Now, i need to get the user_response data in DialogController. if i put console.log('$scope.users') inside of this userservice.init function, i can get the data. but not outside of it. how to get the response data outside of the userService.init function
userService.init(function(user_response) {
$scope.users = user_response.data;
}); //this is added in DialogController
Main intension is to get the user.comlaint_id in the post request of reply mail function . that user.complaint_id is a part of the user_response
Anyone please help me. Thanks
The $http.get call returns a promise, you can just use that.
app.service('userService', function($http,UrlService) {
return {
init: function(callback) {
return $http.get(UrlService.baseUrl +'/api/users/list');
}
}
});
Controller:
function Dialog($scope,$rootScope, $mdDialog,userService,UrlService,$http) {
// console.log(userService.init());
init();
function init() {
userService.init().then(function(response) {
$scope.users = response.data;
});
}
}
This also has the advantage of easier error handling:
function Dialog($scope,$rootScope, $mdDialog,userService,UrlService,$http) {
// console.log(userService.init());
init();
function init() {
userService.init().then(function(response) {
$scope.users = response.data;
}, function(error) {
// handle error
});
}
}
You should read up on angular/javascript promises and their chaining mechanism: angular promises
Here is the solution
userService.init(function(user_response) {
$scope.users = user_response.data;
$scope.init();
});
$scope.init = function() {
You can access $scope.users here
}
Call any method instead of init() in which you require $scope.users
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 recently started to learn unit test for angular apps. And already faced up with problem. I can not take scope variable from inside executed function. Here is my factory code
angular.module('app').factory('AuthenticationService', AuthenticationService);
AuthenticationService.$inject = ['$http'];
function AuthenticationService($http) {
var service = {};
service.login = login;
return service;
function login(data, callback) {
$http({
method: 'POST',
url: CONFIG.getUrl('auth/login'),
data: data
}).then(function (response) {
callback(response);
}, function (error) {
callback(error);
});
}
Part of my controller file. I only yet wan to test login function
function AuthCtrl($scope, $location, AuthenticationService) {
var vm = this;
vm.login = login;
vm.dataLogin = {
user_id: '',
password: '',
};
function login() {
vm.dataLoading = true;
AuthenticationService.login(vm.dataLogin, function (response) {
if (response.status == 200) {
if (response.data.error_code == 'auth.credentials.invalid') {
vm.invalidCredentials = true;
} else {
vm.invalidCredentials = false;
if (response.data.session_state == 'otp_required') {
vm.userNumber = response.data.user_phone;
$localStorage['session_token'] = response.data.session_token;
vm.needForm = 'someForm';
} else {
AuthenticationService.setCredentials(response.data);
$state.go('dashboard');
}
vm.dataLoading = false;
}
}
});
}
}
});
And my spec.js
describe('AuthCtrl, ', function() {
var $scope, ctrl;
var authSrvMock;
var mockJson = {
user_id: '001',
session_token: 'some_token'
};
var mockLoginData = {
user_id: '0000102',
password: '123456'
};
var mockResponseData = {
data: {
"session_expires": 1453822506,
"session_state": "otp_required",
"session_token": "tokennnn",
"status": "success",
"user_id": "0000102",
"user_phone": "+7 (XXX) XXX-XX-89"
},
status: 200
};
beforeEach(function () {
authSrvMock = jasmine.createSpyObj('AuthenticationService', ['login', 'logout']);
module('app');
inject(function ($rootScope, $controller, $q) {
$scope = $rootScope.$new();
authSrvMock.login.and.returnValue(mockResponseData);
ctrl = $controller('AuthCtrl', {
$scope: $scope,
AuthenticationService: authSrvMock
});
});
});
it('should call login function and pass to dashboard', function () {
ctrl.login();
expect(authSrvMock.login).toHaveBeenCalled();
// until this everything works here just fine
});
});
But after I want to test vm.invalidCredentials, if I will write
expect(ctrl.invalidCredentials).toBe(false)
I will get the error
Expected undefined to be false.
Why I can't see variables?
Bit of a noob myself at Jasmine, but I'm guessing it's because you need to get the promise from your login() to return in Jasmine.
Look into using $q.defer(), or even $httpBackend.
After some more digging process and experiments I found solution.
Here what I did
(function () {
'use strict';
describe('AuthCtrl', function () {
var controller, scope, myService, q, deferred, ctrl;
var mockResponseData = {
response1: {
//...
},
response2: {
//...
},
response3: {
//...
}
};
beforeEach(module('app'));
beforeEach(inject(function ($controller, $rootScope, $q, $httpBackend, AuthenticationService) {
function mockHttp(data, callback) {
deferred = $q.defer();
deferred.promise.then(function (response) {
callback(response);
}, function (error) {
callback(error);
});
}
controller = $controller;
scope = $rootScope.$new();
myService = AuthenticationService;
q = $q;
myService.login = mockHttp;
}));
describe('when returning promises', function () {
beforeEach(function () {
ctrl = controller('AuthCtrl', {
$scope: scope,
myService: myService
});
ctrl.initController();
});
it('shows another form to validate login process', function () {
ctrl.login();
deferred.resolve(mockResponseData.response1);
scope.$digest();
expect(ctrl.invalidCredentials).toBe(false);
expect(ctrl.needForm).toEqual('2sAuth');
expect(ctrl.dataLoading).toBe(false);
});
});
});
})();
Since in my factory almost every method requires data and callback I've created mockHttp functions which takes those arguments and deferred promise. In it block I simply call need function, resolve promise with my prepared answers mock and check my expectations. Everything work. Thanks to for aiming in wich way to look
I am writing a unit test for my angular controller; which is receiving $resource object from service.
However unit test is failing saying that "Action.query(success)' is not a function.
Looking forward for your comments.
PhantomJS 1.9.8 (Windows 8 0.0.0) ActionController Action controller getList() call should return an instance of array FAILED
TypeError: '[object Object]' is not a function (evaluating 'Action.query(success)')
action.controller.js
(function() {
'use strict';
angular
.module('app.action')
.controller('ActionController', ActionController);
ActionController.$inject = ['$sce', 'ActionService'];
/* #ngInject */
function ActionController($sce, $state, $stateParams, logger, exception,
moduleHelper, httpHelper, actionService) {
var vm = this;
var Action = null;
vm.title = 'action';
vm.data = []; /* action list model */
vm.getList = getList;
activate();
////////////////
function activate() {
Action = actionService.action();
}
/**
* Provides list of actions.
* Used from list.html
*/
function getList() {
var data = Action.query(success);
function success() {
vm.data = data._embedded.actions;
return vm.data;
}
}
}
})();
action.service.js
(function () {
'use strict';
angular
.module('app.action')
.service('ActionService', ActionService);
ActionService.$inject = ['$resource'];
/* #ngInject */
function ActionService($resource) {
var module = 'action';
var exports = {
action: action
};
return exports;
////////////////
/**
* Provides $resource to action controller
* #returns {Resources} Resource actions
*/
function action() {
return $resource('app/actions/:id', {id: '#id'}, {
query:{
method: 'Get',
isArray: false
},
update: {
method: 'PUT'
}
});
}
}
})();
action.controller.spec.js
/* jshint -W117, -W030 */
describe('ActionController', function() {
var controller;
var mockActions = mockData.getMockActions();
var mConfig = mockActions.getConfig();
var mockService = function() {
var list = [{
'id' : 1,'name' : 'CREATE'
},{
'id' : 2,'name' : 'VIEW'
}];
return {
query: function() {
return list;
},
get: function() {
return list[0];
},
save: function(action) {
var length = list.length;
list.push(action);
return ((length + 1) === list.length);
},
update: function(action) {
return true;
}
};
}
beforeEach(function() {
bard.appModule('app.action');
bard.inject('$controller', '$q', '$rootScope','ActionService');
});
beforeEach(function () {
bard.mockService(ActionService, {
action: function() {
return {
query: $q.when(mockService.query()),
get: $q.when(mockService.get()),
save: function(action) {
return $q.when(mockService.save(action));
},
update: function(action) {
return $q.when(mockService.update(action));
},
};
},
_default: $q.when([])
});
controller = $controller('ActionController');
$rootScope.$apply();
});
bard.verifyNoOutstandingHttpRequests();
describe('Action controller', function() {
it('should be created successfully', function () {
expect(controller).to.be.defined;
});
describe('getList() call', function () {
it('should have getList defined', function () {
expect(controller.getList).to.be.defined;
});
it('should return an instance of array', function () {
/* getting an error here*/
expect(controller.getList()).to.be.insanceOf(Array);
});
it('should return an array of length 2', function () {
expect(controller.getList()).to.have.length(2);
});
});
});
});
});
The ordering of the values in the $inject array must match the ordering of the parameters in ActionController.
ActionController.$inject = ['$sce', 'ActionService'];
/* #ngInject */
// 'actionService' must be the second parameter in the 'ActionController' function.
function ActionController($sce, actionService, $state, $stateParams, logger, exception,
moduleHelper, httpHelper) {
var vm = this;
var Action = null;
// the rest of the code.
You can find out more here: Angular Dependency Injection