Firebase Authentication "sticky" in Ionic - angularjs

I am trying to incorporate $firebaseAuth into my Ionic project. I used a sample example, logging in with Twitter (auth.$authWithOAuthPopup('twitter')), from the Firebase website and incorporated it into my Ionic Framework. The code is shown below.
I am using the following versions (everything is up to date as of today):
firebase 2.0.4
angularfire 0.9.1
ionic 1.0.0-beta.14 "magnesium-mongoose"
Clicking on the button "Login" correctly opens the popup window and I can login. After that, however, in the Ionic project nothing has changed, while actually being logged in. When I refresh my browser, then it shows my displayname and it also notifies me that I am correctly logged in.
I had the same "stickyness" when trying to incorporate the ui-router authentication of Firebase, also copying the code from the website. Moreover, I had to refresh for changes to be processed.
Why is there this delay? Isn't firebase supposed to be real-time? My guess is that it has to do something with the settings of Ionic, since using the Angularfire-seed (without Ionic) works perfectly fine. Or maybe its something else?
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', 'firebase', '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.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(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.friends', {
url: '/friends',
views: {
'tab-friends': {
templateUrl: 'templates/tab-friends.html',
controller: 'FriendsCtrl'
}
}
})
.state('tab.friend-detail', {
url: '/friend/:friendId',
views: {
'tab-friends': {
templateUrl: 'templates/friend-detail.html',
controller: 'FriendDetailCtrl'
}
}
})
.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');
});
services.js
angular.module('starter.services', [])
// let's create a re-usable factory that generates the $firebaseAuth instance
.factory("Auth", ["$firebaseAuth", function($firebaseAuth) {
var ref = new Firebase("https://cloakit.firebaseio.com/");
return $firebaseAuth(ref);
}])
controllers.js
// other controllers
// AccountCtrl
.controller("AccountCtrl", ["$scope", "Auth", function($scope, Auth) {
$scope.settings = {
enableFriends: true
};
$scope.auth = Auth;
$scope.user = $scope.auth.$getAuth();
}]);
tab-account.html
<ion-view view-title="Account">
<ion-content>
<ion-list>
<ion-item class="item-toggle">
Enable Friends
<label class="toggle">
<input type="checkbox" ng-model="settings.enableFriends">
<div class="track">
<div class="handle"></div>
</div>
</label>
</ion-item>
<ion-item>
<div ng-show="user">
<p>Hello, {{ user.twitter.displayName }}</p>
<button ng-click="auth.$unauth()">Logout</button>
</div>
<div ng-hide="user">
<p>Welcome, please log in.</p>
<button ng-click="auth.$authWithOAuthPopup('twitter')">Login</button>
</div>
</ion-item>
</ion-list>
</ion-content>
</ion-view>
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- firebase js -->
<script src="lib/firebase/firebase.js"></script>
<script src="lib/firebase/angularfire/angularfire.min.js"></script>
<!-- loading bar -->
<script src="lib/angular-loading-bar/src/loading-bar.js"></script>
<link href='lib/angular-loading-bar/src/loading-bar.css' rel='stylesheet' />
<!-- cordova script (this will be a 404 during development) -->
<script src="lib/ngCordova/dist/ng-cordova.js"></script>
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/services.js"></script>
</head>
<body ng-app="starter">
<!--
The nav bar that will be updated as we navigate between views.
-->
<ion-nav-bar class="bar-stable">
<ion-nav-back-button>
</ion-nav-back-button>
</ion-nav-bar>
<!--
The views will be rendered in the <ion-nav-view> directive below
Templates are in the /templates folder (but you could also
have templates inline in this html file if you'd like).
-->
<ion-nav-view></ion-nav-view>
</body>
</html>

You might want to take a look at $onAuth.
$onAuth Listens for changes to the client’s authentication state.
So your code would look like:
$scope.auth = Auth;
var authData = $scope.auth.$getAuth();
$scope.auth.$onAuth(function(authData) {
if (authData) {
$scope.user = authData
} else {
console.error("Could not retrieve user");
}
});
You may need to run a $scope.$apply(). I'm thinking you won't since $firebase should be within Angulars digest cycle, but I would throw one in there if it still doesn't work just to be sure you don't need it

Related

Ionic delete button in header view toggle delete button in list view

I have a simple list of items and want to have a button in the header that shows and hides a delete button next to each list item. My header and content are made up of separate views.
After much reading, it seems a controller is attached to a view rather than a state, so I need to have a separate controller for each view (one controller for the header and one controller for the content). As I can't share variables between controllers, what is the best way to have a button in one view (header.html) show/hide buttons in a list in a different view (content.html)?
My HTML is below:
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->
<!--For users deploying their apps to Windows 8.1 or Android Gingerbread, platformOverrided.js
will inject platform-specific code from the /merges folder -->
<script src="js/platformOverrides.js"></script>
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<script src="Scripts/angular-resource.min.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/services.js"></script>
</head>
<body ng-app="starter">
<ion-view view-title="Playlists">
<div ui-view="header"></div>
<div ui-view="content"></div>
</ion-view>
</body>
</html>
header.html
<ion-header-bar class="bar-positive">
<div class="buttons">
<button class="button button-icon icon ion-ios-minus-outline"
ng-click="data.showDelete = !data.showDelete"></button>
</div>
<h1 class="title">my test app</h1>
</ion-header-bar>
content.html
<ion-content class="has-header has-footer" overflow-scroll="true">
<ion-list show-delete="data.showDelete">
<ion-item ng-repeat="movie in movies" href="#/home/{{movie.id}}">
{{movie.title}}
<ion-delete-button class="ion-minus-circled"
ng-click="onItemDelete(movie)">
</ion-delete-button>
<ion-option-button class="button-assertive" ui-sref="editMovie({id:movie.id})">Edit</ion-option-button>
</ion-item>
</ion-list>
</ion-content>
and my js is below.....
app.js
angular.module('starter', ['ionic', 'ngResource', '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 (cordova.platformId === "ios" && window.cordova && 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) {
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', {
url: '/',
views: {
'header': {
templateUrl: 'templates/header.html',
controller: 'headerCtrl'
},
'content': {
templateUrl: 'templates/content.html',
controller: 'contentCtrl'
},
'footer': {
templateUrl: 'templates/footer.html'
}
}
});
});
controllers.js
angular.module('starter.controllers', [])
.controller('headerCtrl', function ($scope) {
$scope.showDelete = function () {
$scope.data.showDelete = !$scope.data.showDelete;
};
})
.controller('contentCtrl', function ($scope, $state, $stateParams, Movie) {
// populate list withg all items from database
$scope.movies = Movie.query();
// handle delete button click
$scope.onItemDelete = function (movie) {
$scope.movies.splice($scope.movies.indexOf(movie), 1);
movie.$delete();
$scope.data.showDelete = false;
};
});
You actually can share variables between controllers, by using what Angular calls a "service".
AngularJS: How can I pass variables between controllers?

How to set information into index.html outside the ng-view

I'm working with angular for the first time and having some trouble showing some dynamic information in my index.html file. Everything inside the ng-view tag is working great.
When a user authenticates, a global variable with user information is put into the $rootScope and into a cookie. I've tried to access to $rootScope in the index by doing something like {{$rootScope.globals.currentUser.username}} but it doesn't work. So considering the code below, how can I show the logged user information in my index.html?
I have tried creating a controller in my app.js and putting the ng-controller on the body. While this works, it doesn't refresh when the user logout (required a page refresh to update the app controller). The same happens after the user login (it requires a whole page refresh for the information to appear).
Code to set cookie and the object in $rootScope.
function SetCredentials(username, password, token) {
$rootScope.globals = {
currentUser: {
username: username,
token: token
}
};
$http.defaults.headers.common['Authorization'] = 'Bearer ' + token;
$cookies.put('globals', JSON.stringify($rootScope.globals));
}
I also have the following index.html file. As you can see, i have set the {{$rootScope.globals.currentUser.username}} but nothing shows after the user is logged in
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<base href="/" />
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>My App</title>
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<!-- css references -->
</head>
<body class="hold-transition skin-blue sidebar-mini">
<div class="wrapper">
<!-- Main Header -->
<header class="main-header">
<!-- Header Navbar -->
<nav class="navbar navbar-static-top" role="navigation">
<!-- Sidebar toggle button-->
<a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button">
<span class="sr-only">Toggle navigation</span>
</a>
<!-- Navbar Right Menu -->
<div class="navbar-custom-menu">
{{$rootScope.globals.currentUser.username}}
</div>
</nav>
</header>
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<ng-view></ng-view>
</div>
<!-- /.content-wrapper -->
<!-- Main Footer -->
<footer class="main-footer">
<!-- To the right -->
<div class="pull-right hidden-xs">
something here
</div>
<!-- Default to the left -->
<strong>Copyright © 2016 NPF.</strong> All rights reserved.
</footer>
</div>
<!-- ./wrapper -->
<!-- REQUIRED JS SCRIPTS -->
<!-- jQuery 2.2.0 -->
<script src="Scripts/jquery-2.2.3.js"></script>
<script src="Scripts/bootstrap.js"></script>
<script src="Scripts/app.min.js"></script>
<script src="Scripts/linq.min.js"></script>
<script src="scripts/angular/angular.min.js"></script>
<script src="scripts/angular/angular-route.min.js"></script>
<script src="scripts/angular/angular-resource.min.js"></script>
<script src="scripts/angular/angular-cookies.min.js"></script>
<!-- application scripts -->
<!-- Main app -->
<script src="app/app.js"></script>
<!-- controllers -->
<script src="app/home/home.controller.js"></script>
<!-- services -->
<script src="app/services/authentication.service.js"></script>
<script src="app/services/user.service.js"></script>
</body>
</html>
My app file, is as follows
(function () {
'use strict';
angular
.module('myApp', ['ngRoute', 'ngCookies', 'treeControl'])
.constant("appSettings",
{
serverPath: "http://localhost:64789/",
webApiPath: "http://localhost:64789/api/"
})
.config(config)
.run(run);
config.$inject = ['$routeProvider', '$locationProvider'];
function config($routeProvider, $locationProvider) {
$locationProvider.html5Mode({
enabled: true,
});
$routeProvider
.when('/', {
controller: 'HomeController',
templateUrl: 'app/home/home.html',
controllerAs: 'viewModel'
})
.when('/login', {
controller: 'LoginController',
templateUrl: 'app/login/login.html',
controllerAs: 'viewModel'
})
.when('/register', {
controller: 'RegisterController',
templateUrl: 'app/register/register.html',
controllerAs: 'viewModel'
})
.otherwise({ redirectTo: '/login' });
};
run.$inject = ['$rootScope', '$location', '$cookies', '$http'];
function run($rootScope, $location, $cookies, $http) {
// keep user logged in after page refresh
try {
$rootScope.globals = JSON.parse($cookies.get('globals'));
}
catch (err) {
$rootScope.globals = {};
}
if ($rootScope.globals && $rootScope.globals.currentUser) {
$http.defaults.headers.common['Authorization'] = 'Bearer ' + $rootScope.globals.currentUser.token;
}
//config.headers.Authorization = 'Bearer ' + authData.token;
$rootScope.$on('$locationChangeStart', function (event, next, current) {
// redirect to login page if not logged in and trying to access a restricted page
var restrictedPage = $.inArray($location.path(), ['/login', '/register', '/gds']) === -1;
try {
var loggedIn = $rootScope.globals.currentUser;
}
catch (err) {
}
if (restrictedPage && !loggedIn) {
$location.path('/login');
}
});
}})();
As mentioned in my comment $rootScope is not required in HTML markup expressions.
But if you forgot to add a controller to your HTML outside of ng-view that can also cause that the variable is undefined. (No controller = no $scope)

Angular Controller Never called

Im trying to use the Ionic Framework to create an app but i have problems to get a simple example to work. This is the html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- pouchdb -->
<script src="lib/pouchdb/pouchdb.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
<script src="js/modules/home.js"></script>
<script src="js/controller/home.js"></script>
</head>
<body ng-app="App">
<ion-nav-view></ion-nav-view>
</body>
</html>
My app.js
angular.module("App", ["ionic", "App.Home"])
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider.state("app", {
url: "/app",
abstract: true,
templateUrl: "templates/home.html",
});
$urlRouterProvider.otherwise("/app/home");
})
.run(function ($ionicPlatform) {
$ionicPlatform.ready(function () {
if (window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if (window.StatusBar) {
StatusBar.styleDefault();
}
});
});
My module home:
angular.module("App.Home", [])
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider.state("app.home", {
url: "/home",
views: {
"main": {
templateUrl: "templates/home.html",
controller: "HomeController"
}
}
});
});
As you can see here i want the home.html to use the HomeController So here is the HomeController
angular.module("App.Home")
.controller("HomeController", function() {
console.log("controller");
});
But the home controller actually never is called. The logoutput never appears. My home.html is showing:
<ion-view view-title="Home">
<ion-content>
Home
</ion-content>
</ion-view>
I mapped the controller to the template so why isnt the controller method getting called?
EDIT
if i change my home.html to the following:
<ion-view view-title="Home">
<ion-content ng-controller="HomeController">
Home
</ion-content>
</ion-view>
It works. So setting ng-controller="HomeController" works fine but
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider.state("app.home", {
url: "/home",
templateUrl: "templates/home.html",
controller: "HomeController"
});
});
or
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider.state("app.home", {
url: "/home",
views: {
"main": {
templateUrl: "templates/home.html",
controller: "HomeController"
}
}
});
Does not work. For me that makes no sense. I want to use the stateProvider to set the controller.
EDIT 2
created a plunker
Fixed!
The controller gets instantiated when it gets bound to the view.
I set the templateUrl of my abstract state to be templates\home.html
That is wrong. I just had to do:
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider.state("app", {
url: "/app",
abstract: true,
templateUrl: "",
});
$urlRouterProvider.otherwise("/app/home");
})
and to use:
angular.module("App.Home", [])
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider.state("app.home", {
url: "/home",
templateUrl: "templates/home.html",
controller: "HomeController"
});
});
So without to define views.

transform an existing angular app in ionic

I encounter a problem with an angular app that I want to migrate in ionic
I used ui-router for angular and here is my app.js(taken here : https://github.com/tarlepp/angular-sailsjs-boilerplate-frontend/blob/master/src/app/app.js ). I haven't made any changes on this file for my project
Now I want to reuse this file for my project so I replace app.js given by ionic by this one and added
$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) {
StatusBar.styleDefault();
}});
inside app.run
here's my index.html :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
</head>
<body ng-app="frontend">
<ion-pane>
<ion-header-bar class="bar-stable">
<h1 class="title">Ionic Blank Starter</h1>
</ion-header-bar>
<ion-content>
</ion-content>
</ion-pane>
</body>
</html>
I just replace the name of ng-app by frontend and ionic theme isn't charged properly.
I don't know if the problem comes from ui-retour dependencies or something else? I think I'm missing something
Note: I know that I will have to change my html and css files for the project , but for index.html I just have what is provided by ionic and I don't have the ionic tab with 'ionic blank starter' as if I begin a blank ionic project
here's my router changed :
enter code here
(function() {
'use strict';
angular.module('frontend', [
'ionic',
'frontend-templates',
'frontend.core',
'frontend.myportfolio',
'frontend.mysocial',
'frontend.myleads',
'frontend.admin'
]);
angular.module('frontend')
.config([
'$stateProvider', '$locationProvider', '$urlRouterProvider', '$httpProvider', '$sailsSocketProvider',
'$tooltipProvider', 'cfpLoadingBarProvider',
'toastrConfig',
'AccessLevels',
function config(
$stateProvider, $locationProvider, $urlRouterProvider, $httpProvider, $sailsSocketProvider,
$tooltipProvider, cfpLoadingBarProvider,
toastrConfig,
AccessLevels
) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
// Add interceptors for $httpProvider and $sailsSocketProvider
$httpProvider.interceptors.push('AuthInterceptor');
$httpProvider.interceptors.push('ErrorInterceptor');
// Iterate $httpProvider interceptors and add those to $sailsSocketProvider
angular.forEach($httpProvider.interceptors, function iterator(interceptor) {
$sailsSocketProvider.interceptors.push(interceptor);
});
// Set tooltip options
$tooltipProvider.options({
appendToBody: true
});
// Disable spinner from cfpLoadingBar
cfpLoadingBarProvider.includeSpinner = false;
cfpLoadingBarProvider.latencyThreshold = 200;
// Extend default toastr configuration with application specified configuration
angular.extend(
toastrConfig,
{
allowHtml: true,
closeButton: true,
extendedTimeOut: 3000
}
);
// Yeah we wanna to use HTML5 urls!
$locationProvider
.html5Mode({
enabled: true,
requireBase: false
})
.hashPrefix('!')
;
// Routes that needs authenticated user
$stateProvider
.state('profile', {
abstract: true,
template: '<ui-view/>',
data: {
access: AccessLevels.user
}
})
$urlRouterProvider.otherwise('/myportfolio/mydatabase');
}
])
;
angular.module('frontend')
.run([
'$rootScope', '$state', '$injector','$ionicPlatform',
'editableOptions',
'AuthService',
function run(
$rootScope, $state, $injector,$ionicPlatform,
editableOptions,
AuthService
) {
$rootScope.$on('$stateChangeStart', function stateChangeStart(event, toState) {
if (toState.url=='/login' || toState.url=='/register' ) {
$rootScope.myStyle = {'background-color':'#333'}
$rootScope.headerIsloaded = false;
$rootScope.sidebarIsloaded = false;
}else{
$rootScope.myStyle = {};
$rootScope.headerIsloaded = true;
$rootScope.sidebarIsloaded = true
};
if (!AuthService.authorize(toState.data.access)) {
event.preventDefault();
console.log(toState.data.access)
$state.go('auth.login');
}
});
// Check for state change errors.
$rootScope.$on('$stateChangeError', function stateChangeError(event, toState, toParams, fromState, fromParams, error) {
event.preventDefault();
$injector.get('MessageService')
.error('Error loading the page');
$state.get('error').error = {
event: event,
toState: toState,
toParams: toParams,
fromState: fromState,
fromParams: fromParams,
error: error
};
return $state.go('error');
});
//bout de code ionic
$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) {
StatusBar.styleDefault();
}
});
}
])
;
}());
Aren't you missing the markup for ui.router to inject your state views into?
<ion-view view-title="your-view">
</ion-view>
if you create a new app with
ionic start myApp
it defaults to the tab template which includes the following body in it's index.html
<body ng-app="starter">
<!--
The nav bar that will be updated as we navigate between views.
-->
<ion-nav-bar class="bar-stable">
<ion-nav-back-button>
</ion-nav-back-button>
</ion-nav-bar>
<!--
The views will be rendered in the <ion-nav-view> directive below
Templates are in the /templates folder (but you could also
have templates inline in this html file if you'd like).
-->
<ion-nav-view></ion-nav-view>
</body>
here the ion-nav-view is what allows ui.router to insert its views

Can not render a child view outside the of the parent`s parent view with ui router

I have created a plunker repro here: http://plnkr.co/edit/zU3PtJamS61Ac0bAKToD?p=preview
When you go to the projects tab and click the Edit button I would expect that the Edit.Html view is rendered in the ui-view "outer".
When I debug then even the ProjectsEditController is created but the state is not really activated and the ui sticks to the projects view.
What do I wrong?
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<link rel="stylesheet" href="style.css" />
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.3/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.min.js"></script>
<script src="http://angular-ui.github.io/ui-router/release/angular-ui-router.js"></script>
<script src="app.js"></script>
<script src="AdministrationController.js"></script>
<script src="ProjectsController.js"></script>
<script src="ProjectsEditController.js"></script>
<script src="SettingsController.js"></script>
</head>
<body ng-app="routedTabs" >
<div class="wrapper">
<div ui-view="outer">
<header class="aside">thats the header </header>
<div ui-view="menu" id="menu" class="aside">this is the menu aside</div>
<div ui-view="content" class="main container">
<h1>Working on it... </h1>
</div>
</div>
</div>
</body>
</html>
Edit.html
<div ng-bind="title"></div>
<button ui-sref="main.projects.edit({id: 10})" class="btn btn-default primary">Edit</button>
app.js
var app = angular.module("routedTabs", ["ui.router", "ui.bootstrap"]);
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("");
$stateProvider
.state("main", {
abtract: true,
url: "",
views: {
'content#': {
templateUrl: 'administration.html',
controller: 'AdministrationController'
}
}
})
.state("main.projects", {
url: "/projects",
views: {
'menu#': {
template: 'test'
},
'planner#main': {
templateUrl: 'projects.html',
controller: 'ProjectsController'
}
}
}).state('main.projects.edit', {
url: '/edit/:id',
views: {
'outer#': {
templateUrl: 'edit.html',
controller: 'ProjectsEditController'
}
}
})
.state("main.tab2", {
url: "/settings",
views: {
'menu#': {
template: 'bla'
},
'planner#main': {
templateUrl: 'settings.html',
controller: 'SettingsController'
}
}
});
});
UPDATE
According to #Karthik`s statement I can not render the edit view into the "outer" ui-view.
I have prepared here a plunker without abstract main state and tabs. In this sample is just a projects view with an edit project button which should render the edit view into the ui-view called "outer" and indeeded it works!
http://plnkr.co/edit/ogQIpfHz7Cy9Jo03czKL?p=preview
So my new question is, what is the difference between those samples that it works in this plunker but not in the tabs plunker?
And how can I concretely make it work with tabs then?
Your projects is working and edit tab is displayed (if you debug your js code you will see it). In your case problem is in your AdministrationController.js.
On every update event form tabset is called go function with route /projects (current tab)
$scope.go = function(route){
$state.go(route);
};
This changes state back to main.projects so it seems like state was not changes which it actually was.
You probably want to re-write triggering within AdministrationController.js or found out why is update/go function triggered when leaving tab.
See if answer in this topic helps. You could use this approach instead of update function.
As temporary solution could be used something like:
$scope.go = function(route){
if($state.$current.name != 'main.projects.edit'){
$state.go(route);
}
}

Resources