I'm crazy with it: Error: Cannot transition to abstract state - javascript

Hi I 'm developing an app with IONIC Framework and am developing the user validation and error have not let me go , I leave some details of logic I'm using:
app.js:
angular.module('skulApp', ['ionic', 'ionic-material', 'ionMdInput', 'ngCordova'])
.run(function($ionicPlatform, $rootScope, $state, AUTH_EVENTS, _Auth_Service, sqliteService){
$ionicPlatform.ready(function(){
if (window.cordova && window.cordova.plugins.Keyboard)
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
if (window.StatusBar)
StatusBar.styleDefault();
sqliteService.preloadDataBase(true);
});
$rootScope.$on('$stateChangeStart', function(event, next, nextParams, fromState) {
if ('data' in next && 'authorizedRoles' in next.data) {
var authorizedRoles = next.data.authorizedRoles;
if (!_Auth_Service.isAuthorized(authorizedRoles)) {
event.preventDefault();
$state.go($state.current, nextParams, {reload: true});
$rootScope.$broadcast(AUTH_EVENTS.notAuthorized);
}
}
if (!_Auth_Service.isAuthenticated()) {
if (next.name !== 'login') {
event.preventDefault();
$state.go('login');
}
}
});
})
app.config.js:
.config(function($stateProvider, $urlRouterProvider, $ionicConfigProvider, USER_ROLES) {
$stateProvider
.state('main', {
url: '/',
abstract: true,
templateUrl: 'templates/main.html'
})
.state('login', {
url: '/login',
templateUrl: 'templates/login.html',
controller: 'LoginCtrl'
})
.state('main.dashboard', {
url: 'main/dashboard',
views: {
'menuContent': {
templateUrl: 'templates/dashboard.html',
controller: 'DashboardCtrl'
},
'fabContent': {
template: '<button id="fab-profile" class="button button-fab button-fab-bottom-right button-energized-900" ui-sref="main.edit"><i class="icon ion-edit"></i></button>',
controller: function($timeout) {
$timeout(function() {
document.getElementById('fab-profile').classList.toggle('on');
}, 800);
}
}
},
data: {
authorizedRoles: [
USER_ROLES.admin,
USER_ROLES.teacher,
USER_ROLES.father
]
}
})
.state('main.edit', {
url: 'main/edit',
views: {
'menuContent': {
templateUrl: 'templates/edit.html',
controller: 'EditCtrl'
},
'fabContent': {
template: ''
}
}
});
$urlRouterProvider.otherwise(function($injector, $location){
var $state = $injector.get("$state");
$state.go('main.dashboard');
});
});
The error is:
Error: Cannot transition to abstract state '[object Object]'
at Object.transitionTo (ionic.bundle.js:40332)
at Object.go (ionic.bundle.js:40262)
at app.js:52
at Scope.$broadcast (ionic.bundle.js:23003)
at Object.transitionTo (ionic.bundle.js:40395)
at Object.go (ionic.bundle.js:40262)
at app.config.js:210
at check (ionic.bundle.js:39247)
at update (ionic.bundle.js:39259)
at Scope.$broadcast (ionic.bundle.js:23003)
Te line in app.js is that:
$state.go($state.current, nextParams, {reload: true});
Here I do not include services , constants, controls , policies, and others, if they consider it necessary I do know and update the question. Please i don't do! Help me

I think your problem is due to your $stateChangeStart method.
In case it enters the first couple of if conditions, this line:
$state.go($state.current, nextParams, {reload: true});
Will abourt your try to go to /main/dashboard, and the state will remain in /.

Well if you open your broswer on '/' the only matching state is your abstract one. Since it's matching otherwise doesn't get executed.
Use this instead of otherwise to redirect to your dashboard.
$urlRouterProvider.when('/', '/main/dashboard');

Related

Add a code into app.js

I'm new to Javascript. I'm building an app using Ionic.
First I created app using ionic start MyAPPOne tabs
Then I installed Cordova Text-to-SpeechPlugin
This is my app.js
// Ionic Starter App
// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' 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'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js
angular.module('starter', ['ionic', 'starter.controllers', 'starter.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.styleDefault();
}
});
})
.config(function($stateProvider, $urlRouterProvider) {
// Ionic uses AngularUI Router which uses the concept of states
// Learn more here: https://github.com/angular-ui/ui-router
// Set up the various states which the app can be in.
// Each state's controller can be found in controllers.js
$stateProvider
// setup an abstract state for the tabs directive
.state('tab', {
url: '/tab',
abstract: true,
templateUrl: 'templates/tabs.html'
})
// Each tab has its own nav history stack:
.state('tab.dash', {
url: '/dash',
views: {
'tab-dash': {
templateUrl: 'templates/tab-dash.html',
controller: 'DashCtrl'
}
}
})
.state('tab.chats', {
url: '/chats',
views: {
'tab-chats': {
templateUrl: 'templates/tab-chats.html',
controller: 'ChatsCtrl'
}
}
})
.state('tab.chat-detail', {
url: '/chats/:chatId',
views: {
'tab-chats': {
templateUrl: 'templates/chat-detail.html',
controller: 'ChatDetailCtrl'
}
}
})
.state('tab.account', {
url: '/account',
views: {
'tab-account': {
templateUrl: 'templates/tab-account.html',
controller: 'AccountCtrl'
}
}
});
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/tab/dash');
});
I want to add this code into my app.js.
angular.module('starter', ['ionic'])
.controller('AppCtrl', function($scope) {
$scope.data = {
speechText: ''
};
$scope.recognizedText = '';
$scope.speakText = function() {
TTS.speak({
text: $scope.data.speechText,
locale: 'en-GB',
rate: 1.5
}, function () {
// Do Something after success
}, function (reason) {
// Handle the error case
});
};
$scope.record = function() {
var recognition = new SpeechRecognition();
recognition.onresult = function(event) {
if (event.results.length > 0) {
$scope.recognizedText = event.results[0][0].transcript;
$scope.$apply()
}
};
recognition.start();
};
});
So how can I do it? I tried to merge this by pasted this code in app.js but when I checked this via ionic serve the app didn't show tabs. How can I merge this?
Replace this line
angular.module('starter', ['ionic'])
with
angular.module('starter.controllers')

UI Router nested views

I've tried with various anwsers without any luck.
I have this two ui-views:
<div ui-view class="expand"></div> //Inside index.html
<div ui-view></div> //Inside home.html
And this is my routing:
$stateProvider
.state('home', {
url: '/',
views: {
'#': {
templateUrl: 'app/components/home/home.html',
controller: 'HomeCtrl'
}
}
})
.state('clients', {
url: '/clients',
views: {
'#home': {
templateUrl: 'app/components/clients/clients.html',
controller: 'ClientsCtrl'
}
}
})
I've tried putting names on the view and calling them in different ways but clients.html never gets display even though the route url changes.
I'm not entirely familiar with the view syntax that you're using with $stateProvider. I'll give you two versions, the first will seem very similar to your example and the second is more aligned with best practices.
$stateProvider
.state('base', {
abstract: true,
url: '',
templateUrl: 'views/base.html'
})
.state('login', {
url: '/login',
parent: 'base',
templateUrl: 'views/login.html',
controller: 'LoginCtrl'
})
.state('dashboard', {
url: '/dashboard',
parent: 'base',
templateUrl: 'views/dashboard.html'
})
Best practice version:
(function () {
'use strict';
angular
.module('app.core')
.config(stateConfig)
.run(errorHandler);
stateConfig.$inject = ['$stateProvider', '$urlRouterProvider', '$locationProvider'];
getZipCodes.$inject = ['googleMapService'];
errorHandler.$inject = ['$rootScope', 'logger'];
function stateConfig($stateProvider, $urlRouterProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$urlRouterProvider.otherwise('/');
$stateProvider.state('core', {
url: '/',
templateUrl: 'app/core/core.html',
controller: 'CoreController',
controllerAs: 'vm',
resolve: {
getZipCodes : getZipCodes
}
})
}
/** #desc: Ping the back-end for a JSON object that will be converted into an array of NYC zip codes */
function getZipCodes(googleMapService) {
return googleMapService.getZipCodes();
}
/** #desc: $stateChangeError handler */
function errorHandler($rootScope, logger) {
$rootScope.$on('$stateChangeError', function (error, event) {
if (error) { logger.error('Error while changing states', error); }
if (event) { logger.error('The event that caused the error', event); }
})
}
})();

Angular flickers when authenticating user

I need help eliminating a flicker with Angular. I am getting a flicker every time a new route is passed through. I have a login and logout button outside the ng-view which uses ng-if="authenticated". The problem is any time a menu item is clicked and a new view is displayed the logout or login button flickers. Is there a way to eliminate this? Below is the module, config and run function.
PS. I am very new to Angular. This was a script from a tutorial on using Angular, php and mysql for a login system.
var app = angular.module('myApp', ['ngRoute', 'ngAnimate', 'ui.bootstrap', 'toaster']);
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/login', {
title: 'Login',
templateUrl: 'views/login.html',
controller: 'authCtrl'
})
.when('/logout', {
title: 'Logout',
templateUrl: 'views/login.html',
controller: 'logoutCtrl'
})
.when('/signup', {
title: 'Signup',
templateUrl: 'views/signup.html',
controller: 'authCtrl'
})
.when('/dashboard', {
title: 'Dashboard',
templateUrl: 'views/dashboard.html',
controller: 'authCtrl'
})
.when('/posts', {
title: 'Posts',
templateUrl: 'views/posts.html',
controller: 'authCtrl'
})
.when('/stats', {
title: 'Stats',
templateUrl: 'views/stats.html',
controller: 'authCtrl'
})
.when('/ambas', {
title: 'Ambassadors',
templateUrl: 'views/ambassadors.html',
controller: 'authCtrl'
})
.when('/images', {
title: 'Images',
templateUrl: 'views/images.html',
controller: 'authCtrl'
})
.when('/', {
title: 'Login',
templateUrl: 'views/login.html',
controller: 'authCtrl'
})
.otherwise({
redirectTo: '/posts'
});
}])
.run(function ($rootScope, $location, Data) {
$rootScope.$on("$routeChangeStart", function (event, next, current) {
$rootScope.authenticated = false;
Data.get('session').then(function (results) {
if (results.uid) {
$rootScope.authenticated = true;
$rootScope.uid = results.uid;
$rootScope.name = results.name;
$rootScope.email = results.email;
} else {
var nextUrl = next.$$route.originalPath;
if (nextUrl == '/signup' || nextUrl == '/login') {
} else {
$location.path("/login");
}
}
});
});
});
You are setting the authenticated value to false on every route change start. So every time a user clicks to change the route you set it to false, and then a few moments later you set it to true if authentication is fine. That will cause a flicker.
So, remove the $rootScope.authenticated = false; from the $routeChangeStart callback.
$rootScope.$on("$routeChangeStart", function (event, next, current) {
//$rootScope.authenticated = false; <--- *remove this*
Data.get('session').then(function (results) {
...........

Ionic template does not work on mobile

I have been making an app in AngularJS with Angular-ui-router based on Ionic Framework. It works perfect on the desktop in every web browser, but it does not show anything on my mobile (after build I run it on 2 devices). The problem is that it doesn't load template inside ui-view.
I have got an index.html file, the body section is below (in head section there is everything included):
<body ng-app="starter">
<div ui-view=""></div>
</body>
And the part of app.js - run and config.
angular.module('starter', ['ionic', 'ngStorage', 'ngAnimate', 'naif.base64', 'ui.router'])
.run(function($ionicPlatform, $rootScope, $location) {
$ionicPlatform.ready(function() {
if (window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if (window.StatusBar) {
StatusBar.styleDefault();
}
});
history = [];
$rootScope.$on('$routeChangeSuccess', function() {
history.push($location.$$path);
});
$rootScope.back = function () {
history.back();
};
})
.config(function($stateProvider, $urlRouterProvider) {
"use strict";
$stateProvider
.state('connectionCheck', {
url: '/',
controller: ['$scope', '$location', '$http',
function($scope, $location, $http) {
$http.get('http://pingurl.com')
.success(function(data) {
jdata = data;
if (data.status === "success") {
$location.path('/login');
}else{
$location.path('/error');
}
})
.error(function() {
$location.path('/error');
});
$scope.retry = function() {
$location.path('/');
};
}
]
})
.state('login', {
url: '/login',
templateUrl: 'login.html'
})
.state('main', {
url: '/main',
templateUrl: 'main.html',
controller: ['$scope', '$location', '$localStorage',
function($scope, $location, $localStorage) {
$scope.username = $localStorage.username;
$scope.token = $localStorage.token;
$scope.email = $localStorage.email;
$scope.goToAlerts = function() {
$location.path('/alerts');
};
$scope.goToSettings = function() {
$location.path('/settings');
};
$scope.goToLocation = function() {
$location.path('/location');
};
$scope.goToSymptoms = function() {
$location.path('/symptoms');
};
$scope.getClass = function(path) {
if ($location.path().substr(0, path.length) == path) {
return "active"
} else {
return ""
}
};
}
]
})
.state('error', {
url: '/error',
templateUrl: 'error.html'
})
.state('register', {
url: '/register',
templateUrl: 'register.html',
})
.state('push', {
url: '/push',
templateUrl: 'push.html',
})
.state('alerts', {
url: '/alerts',
templateUrl: 'alerts.html'
})
.state('newSymptom', {
url: '/newSymptom',
templateUrl: 'newsymptom.html'
})
.state('symptoms', {
url: '/symptoms',
templateUrl: 'symptoms.html'
})
.state('newAlert', {
url: '/newalert',
templateUrl: 'newalert.html'
})
.state('settings', {
url: '/settings',
templateUrl: 'settings.html'
})
.state('location', {
url: '/location',
templateUrl: 'location.html'
});
$urlRouterProvider.otherwise('/');
}).
//some controllers goes here
What I have already checked/tried to do?
I put example content to index.html - it worked.
I tried chanage the name of ui-view and add them in templateURL values of each state.
I changed the .html files to exlude error in them, but it did not helped.
Can anyone more experienced with Ionic/Angular give me a hint what is wrong here?
I seem to notice that it's often due to the modules you're loading in. So It's likely in this line.
angular.module('starter', ['ionic', 'ngStorage', 'ngAnimate', 'naif.base64', 'ui.router'])
Try checking each module by making sure:
You added it to your index.html
it's being called correctly
it's up to date
You can figure out by removing each, one at a time and then seeing if it works on the device.
Also know that AngularJS out of the box uses AngularUI Router and this uses a thing called routing for views. The UI-Router uses a thing called states that is the most used but the unofficial way for AngularJS and Ionic uses their own view state system that is basically the same thing as the UI-Router just with the Ionic namespace. So that is something you need to look up or you may find yourself running into a lot of walls during you builds because you are calling ui.router and I bet it's what's confusing your app, so remove it.

Angularjs organising/structuring states

I have over 100 pages. All pages use a different templates.
Currently, I have a long list of .state('page.html').state('page2.html') etc.
After 10-15 pages, I think this becomes unreadable/hard to manage.
Is there an easier/better way of organising states?
Javascript:
angular.module('app', ['ionic', 'ngCordova', 'app.controllers', 'app.directives', 'app.services', 'app.factories'])
.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.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if (window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.hide();
}
if (typeof navigator.splashscreen !== 'undefined') {
// org.apache.cordova.statusbar required
navigator.splashscreen.hide();
}
});
})
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'templates/main.html',
controller: 'AppCtrl'
})
.state('app.home', {
url: '/home',
views: {
'menuContent': {
templateUrl: 'templates/pages/home.html',
controller: 'PageCtrl'
}
}
})
.state('app.page2', {
url: '/page2',
views: {
'menuContent': {
templateUrl: 'templates/pages/page2.html',
controller: 'PageCtrl'
}
}
})
//100 .state('page.html')
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/app/home');
});
You can organize your pages into different modules and add states specific to the module in the corresponding module's config. Also I suggest you to use ui-router which supports nested states and many other features.
For example:
angular.module('myapp.appointments', ['ui.router', 'myapp'])
.config(['$stateProvider', function ($stateProvider) {
var templatePath = ROOT_PATH + 'scripts/modules/appointments/views/';
$stateProvider
.state('appointments', {
url: '/appointments',
abstract: true,
views: {
"containerView": {
template: '<div ui-view></div>'
}
}
})
.state('appointments.list', {
url: '/list',
controller: "AppointmentsListCtrl",
templateUrl: templatePath + '/appointments-list.html'
})
.state('appointments.add', {
url: '/add/:fromPopup',
controller: "AppointmentsAddCtrl",
templateUrl: templatePath + '/add-appointment.html'
})
}]);
angular.module('myapp.customers', ['ui.router', 'myapp'])
.config(['$stateProvider', function ($stateProvider) {
var templatePath = ROOT_PATH + 'scripts/modules/customers/views/';
$stateProvider
.state('customers', {
url: '/customers',
abstract: true,
views: {
"containerView": {
templateUrl: templatePath + '/index.html'
}
}
})
.state('customers.list', {
url: '/',
controller: "CustomersListCtrl",
templateUrl: templatePath + '/list.html'
});
}]);
and you can have your main app's config containing some common states such as
angular.module('myapp', ['ui.router', 'myapp.appointments', 'myapp.customers'])
.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('home', {
url: '/',
views: {
"containerView": {
controller: "DashboardCtrl",
templateUrl: ROOT_PATH + 'scripts/modules/dashboard/views/dashboard.html'
}
}
})
.state('404', {
url: '/404',
views: {
"containerView": {
templateUrl: ROOT_PATH + 'scripts/modules/common/views/404.html'
}
}
});
}]);
Instead of adding al these states, isn't it a better idea to dynamicly add the template based on a variable?
You might be looking for dynamic template name based on the state params
$stateProvider.state('app.page', {
templateUrl: function ($stateParams){
return 'templates/pages/page/' + $stateParams.pageid+ '.html';
}
})
Found this answer in:
ui-router dynamic template path

Categories