Angular ui-router: adding templateUrl breaking routing - javascript

I am having an issue where once the templateUrl is added into the ui-router child state, the application will no longer perform the routing to the state. It works fine when it's just a template.
app.js:
app.config(['$stateProvider', '$locationProvider', '$urlMatcherFactoryProvider', '$urlRouterProvider',
function ($stateProvider, $locationProvider, $urlMatcherFactoryProvider, $urlRouterProvider) {
$urlMatcherFactoryProvider.caseInsensitive(true);
$urlMatcherFactoryProvider.strictMode(false);
$urlRouterProvider.otherwise('/page-not-found');
$stateProvider
.state('dashboard', {
url: '/',
views: {
'header': {
template: 'header'
},
'nav': {
template: 'nav'
},
main: {
template: 'You are on the homepage'
}
}
});
$locationProvider.html5Mode(true);
}]);
app.run(['$rootScope', 'userService', '$state', function ($rootScope, user, $state) {
$rootScope.$on("$stateChangeError", console.log.bind(console));
if (!user.exists) {
$state.go('user.reg');
}
}]);
User.states.js:
.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('user', {
url: '/users',
abstract: true,
views: {
'header': {},
'nav': {},
'main': {
template: '<ui-view/>'
}
}
})
.state('user.reg', {
url: '/register',
//template: 'This will show fine',
templateUrl: '/app/Users/User.login.html' // this will break
});
}]);
UPDATE
If I add a ui-sref="user.reg" to my initial pages I can navigate to the state/page fine, with the templateUrl and template . So its just an issue when I try to use state.go('user.reg');
This means a work around is using the $location provider to change the path. Has the same effect but does seem rather wrong

The problem is with your relative paths.
Look at this code:
$locationProvider.html5Mode(true);
You have html5 mode enabled, and for that to work, you have your base ref set in your html, which probably looks like this:
<base href="/">
Your issue is likely that the route for your template isn't "yoursite.com/app/Users/User.login.html."
See this Plunker for a working version of your code. Then go into the html code and uncomment out the base tag, and notice that it will break.

Related

migrating from ngRoute to ui.router

I have a problem with migrating from ngroute to ui.router:
using ngroute i have couple angular files:
module.js
angular.module('betTogether', ['ngRoute']);
route.js
angular.module('betTogether').config(['$routeProvider',
function (
$routeProvider
) {
$routeProvider.
when('/descriptionBets', {
templateUrl: 'descriptionBets',
controller: 'descriptionBetsCtrl'
}).
when('/normalBets', {
templateUrl: 'normal',
controller: 'normalBetsCtrl'
}).
when('/addBet', {
templateUrl: 'addBet',
controller: 'addBetCtrl'
}).
otherwise({
redirectTo: '/descriptionBets'
});
}]);
normalBets.js
angular.module('betTogether').controller('normalBetsCtrl', [
'$scope','$http',
function($scope,$http){
$scope.typeBetsImages = [{link: "images/basketball.png", title:"basketball"},
{link: "images/tenis.png", title: "tenis"},
{link: "images/volleyball.png", title: "volleyball"},
{link: "images/football.png", title:"football"}
];
$http.get("/normalBets").success(function(data){
$scope.normalBets = data;
});
}]);
...and rest of controllers. And everything works ok.
Now i want to migrate to ui-router. so i change module.js and route.js like that:
module.js
angular.module('betTogether', ['ui.router']);
route.js
angular.module('betTogether').config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider){
// For any unmatched url, send to /business
$urlRouterProvider.otherwise("/descriptionBets")
$stateProvider
.state('descriptionBets', {//State demonstrating Nested views
url: "/descriptionBets",
templateUrl: "descriptionBets",
controller: "descriptionBetsCtrl"
})
.state('normalBets', {//nested state [products is the nested state of business state]
url: "/normalBets",
templateUrl: "normal",
controller: "normalBetsCtrl"
})
.state('addBet', {//nested state [services is the nested state of business state]
url: "/addBet",
templateUrl: "addBet",
controller: "addBetCtrl"
});
}]);
and it doesnt work. i have error:
Error: [$injector:nomod] http://errors.angularjs.org/1.3.10/$injector/nomod?p0=betTogether angular.min.js:6:417
... and it is for 1st line of each controllers.
Someone could help me?
PS: sorry for my english, hope You understand all.
Check the order of your <script> imports in your index.html. The likelihood is that you've included the ui-router module after your betTogether module whereas it should come before it because betTogether depends on ui.router.

Angularjs routing template is not displayed

I have the following app.js file:
'use strict';
var app = angular.module('app', [
'auth0',
'angular-storage',
'angular-jwt',
'ui.router',
'Environment',
'Api',
'Profile'
]);
app.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('main', {
url: '/main',
templateUrl: 'js/modules/App/views/frontpage.html'
})
.state('login', {
url: '/login',
templateUrl: 'js/modules/User/views/login.html',
controller: 'LoginCtrl'
});
$urlRouterProvider
.otherwise('/main');
}]);
app.config(['authProvider', '$httpProvider', '$locationProvider', 'jwtInterceptorProvider',
function myAppConfig(authProvider, $httpProvider, $locationProvider, jwtInterceptorProvider) {
authProvider.init({
domain: 'marcrasmussen.eu.auth0.com',
clientID: 'hphpe4JiceMW8FSA02CN7yOYl5fUaULe',
loginUrl: '/login'
});
authProvider.on('loginSuccess', ['$location', 'profilePromise', 'idToken', 'store',
function ($location, profilePromise, idToken, store) {
console.log("Login Success");
profilePromise.then(function (profile) {
store.set('profile', profile);
store.set('token', idToken);
});
$location.path('/');
}]);
//Called when login fails
authProvider.on('loginFailure', function () {
alert("Error");
});
//Angular HTTP Interceptor function
jwtInterceptorProvider.tokenGetter = ['store', function (store) {
return store.get('token');
}];
//Push interceptor function to $httpProvider's interceptors
$httpProvider.interceptors.push('jwtInterceptor');
}]);
app.run(['auth', function (auth) {
// This hooks all auth events to check everything as soon as the app starts
auth.hookEvents();
}]);
And i have the following profile.js file:
angular.module('Profile', [])
.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('profile', {
abstract: true,
url: '/profile'
})
.state('profile.index', {
url: '/index',
templateUrl: 'js/modules/Profile/views/viewProfile.html'
})
}]);
in my index.html the files are listed as such:
<script src="js/modules/Profile/lib/profile.js"></script>
<script src="js/modules/App/lib/app.js"></script>
<script src="js/modules/App/directives/login/login.js"></script>
And lastly ofcourse i have my view port:
<div class="main" ui-view>
</div>
As you can tell my application starts on the route /main this works perfectly fine and frontpage.html is being rendered with all the html inside that file.
However when i go to profile.index or /profile/index no error is displayed in the console and no html within the template file js/modules/Profile/views/viewProfile.html is displayed.
Can anyone tell me why this is happening? what am i doing wrong?
I think the issue may be your abstract state. You are not defining a template or templateUrl for this state. Also note that the template for your abstract state must include a ui-view directive in order for its children to populate.
https://github.com/angular-ui/ui-router/wiki/nested-states-%26-nested-views#abstract-state-usage-examples
You may need to do something along the lines of:
.state('profile', {
abstract: true,
url: '/profile',
template: '<ui-view />
})

Switch between views based on some condition

I am new to angular and ionic, my app information goes like this: I have a splash screen on which I have my login page,followed by home screen.Now the problem is if the user has logged in once,then whenever the app is closed and opened again it shows the login screen,instead it should show home screen. How do I achieve that. I have tried many solutions, but none of them worked. Kindly help.
var kit = angular.module('starter', ['ionic','ionic.service.core', 'ngCordova']);
kit.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('start', {
url: '/',
templateUrl: 'templates/start.html',
controller: 'StartController'
})
.state('home', {
url: '/home',
templateUrl: 'templates/home.html',
controller: 'HomeController'
})
.state('scrollView', {
url: '/scroll',
templateUrl: 'templates/ScrollEx.html',
controller: 'ScrollExController'
})
.state('check', {
url: '/check',
templateUrl: 'templates/check.html',
controller: 'CheckController'
})
$urlRouterProvider.otherwise('/');
});
In your login page's controller, I assume this is StartController, you can use something like:
// Note you need $location for navigation here:
app.controller('StartController', ['$rootScope', '$scope', '$location', /*...*/
function ($rootScope, $scope, $location /*...*/) {
// Test condition, just an example:
if (sessionStorage.user.id) {
$location.path('/home');
}
// Controller code goes here
});
This is assuming you condition is sessionStorage.user.id.
Angular's $location will handle router navigation elegantly for you.
Source: AngularJS: $location

opening a modal in a route in AngularJS with angular-ui-bootstrap

I am trying to do what was essentially answered here Unable to open bootstrap modal window as a route
Yet my solution just will not work. I get an error
Error: [$injector:unpr] Unknown provider: $modalProvider <- $modal
My app has the ui.bootstrap module injected - here is my application config
var app = angular.module('app', ['ui.router', 'ui.bootstrap','ui.bootstrap.tpls', 'app.filters', 'app.services', 'app.directives', 'app.controllers'])
// Gets executed during the provider registrations and configuration phase. Only providers and constants can be
// injected here. This is to prevent accidental instantiation of services before they have been fully configured.
.config(['$stateProvider', '$locationProvider', function ($stateProvider, $locationProvider) {
// UI States, URL Routing & Mapping. For more info see: https://github.com/angular-ui/ui-router
// ------------------------------------------------------------------------------------------------------------
$stateProvider
.state('home', {
url: '/',
templateUrl: '/views/index',
controller: 'HomeCtrl'
})
.state('transactions', {
url: '/transactions',
templateUrl: '/views/transactions',
controller: 'TransactionsCtrl'
})
.state('login', {
url: "/login",
templateUrl: '/views/login',
controller: 'LoginCtrl'
})
.state('otherwise', {
url: '*path',
templateUrl: '/views/404',
controller: 'Error404Ctrl'
});
$locationProvider.html5Mode(true);
}])
I have reduced my controller to the following:
appControllers.controller('LoginCtrl', ['$scope', '$modal', function($scope, $modal) {
$modal.open({templateUrl:'modal.html'});
}]);
Ultimately, what I am hoping to achieve is when login is required not actually GO to the login page, but bring up a dialog.
I have also tried using the onEnter function in the ui-router state method. Couldn't get this working either.
Any ideas?
UPDATE
Ok - so as it turns out, having both ui-bootstrap.js AND ui-bootstrap-tpls breaks this - After reading the docs I thought you needed the templates to work WITH the ui-bootstrap. though it seems all the plunkers only load in the ..tpls file - once I removed the ui-bootstrap file my modal works...Am i blind? or doesn't it not really say which one you need in the docs on github? -
Now i just need to figure out how to prevent my url from actually going to /login, rather than just show the modal :)
update 2
Ok, so by calling $state.go('login') in a service does this for me.
Hi I had a hard time getting through the similar problem.
However, I was able to resolve it.
This is what you would probably need.
app.config(function($stateProvider) {
$stateProvider.state("managerState", {
url: "/ManagerRecord",
controller: "myController",
templateUrl: 'index.html'
})
.state("employeeState", {
url: "empRecords",
parent: "managerState",
params: {
empId: 0
},
onEnter: [
"$modal",
function($modal) {
$modal.open({
controller: "EmpDetailsController",
controllerAs: "empDetails",
templateUrl: 'empDetails.html',
size: 'sm'
}).result.finally(function() {
$stateProvider.go('^');
});
}
]
});
});
Click here for plunker. Hope it helps.
I'm working on something similar and this is my solution.
HTML code
<a ui-sref="home.modal({path: 'login'})" class="btn btn-default" ng-click="openModal()">Login</a>
State configuration
$stateProvider
// assuming we want to open the modal on home page
.state('home', {
url: '/',
templateUrl: '/views/index',
controller: 'HomeCtrl'
})
// create a nested state
.state('home.modal', {
url: ':path/'
});
Home controller
//... other code
$scope.openModal = function(){
$modal.open({
templateUrl: 'path/to/page.html',
resolve: {
newPath: function(){
return 'home'
},
oldPath: function(){
return 'home.modal'
}
},
controller: 'ModalInstanceController'
});
};
//... other code
Finally, the modal instance controller.
This controller synchronizes the modal events (open/close) with URL path changes.
angular.module("app").controller('ModalInstanceController', function($scope, $modalInstance, $state, newPath, oldPath) {
$modalInstance.opened.then(function(){
$state.go(newPath);
});
$modalInstance.result.then(null,function(){
$state.go(oldPath);
});
$scope.$on('$stateChangeSuccess', function () {
if($state.current.name != newPath){
$modalInstance.dismiss('cancel')
}
});
});
You may create a state with the same templateUrl and controller as your page where you want to show the modal, adding params object to it
$stateProvider
.state('root.start-page', {
url: '/',
templateUrl: 'App/src/pages/start-page/start-page.html',
controller: 'StartPageCtrl'
})
.state('root.login', {
url: '/login',
templateUrl: 'App/src/pages/start-page/start-page.html',
controller: 'StartPageCtrl',
params: {
openLoginModal: true
}
})
And in controller of the page, use this parameter to open the modal
.controller("StartPageCtrl", function($scope, $stateParams) {
if ($stateParams.openLoginModal) {
$scope.openLoginModal();
}
I found a handy hint to get this working. There are probably caveats, but it works for me. You can pass a result still but I have no need for one.
Using finally instead of the then promise resolve sorted this for me. I also had to store the previous state on rootScope so we knew what to go back to.
Save previous state to $rootScope
$rootScope.previousState = 'home';
$rootScope.$on('$stateChangeSuccess', function(ev, to, toParams, from, fromParams){
$rootScope.previousState = from.name;
})
State using onEnter
$stateProvider.state('contact', {
url: '/contact',
onEnter: function ($state, $modal, $rootScope){
$modal.open({
templateUrl: 'views/contact.html',
controller: 'ContactCtrl'
}).result.finally(function(){
$state.go($rootScope.previousState);
})
}
});

Stop a common template from being reloaded

I have an Angular application that depends on Angular ui-router. This application has multiple pages which share a common template such as the navbar:
var app = angular.module('app', ['ngSanitize', 'ngResource', 'ngRoute', 'ui.router'])
.config(['$urlRouterProvider', '$stateProvider', ($urlRouterProvider, $stateProvider) => {
$urlRouterProvider.otherwise("/index");
$stateProvider
.state('index', {
url: "/index",
views: {
'navbar': {
templateUrl: 'Views/Partials/navbar.cshtml',
controller: 'App.Controllers.NavbarController'
},
'content': {
templateUrl: 'Views/index.cshtml',
controller: 'App.Controllers.IndexController'
}
}
})
.state('settings', {
url: "/settings",
views: {
'navbar': {
templateUrl: 'Views/Partials/navbar.cshtml',
controller: 'App.Controllers.NavbarController'
},
'content': {
templateUrl: 'Views/settings.cshtml',
controller: 'App.Controllers.SettingsController'
}
}
});
}]);
Both '/index' and '/settings' share the same template 'Views/Partials/navbar.cshtml'. Upon testing, i found out, that every time a "page" is loaded for an url, all the views in it are reloaded.
Is it possible to avoid reloading the navbar, if it has been previously loaded already?
You should be able to extract the navbar into a parent state of your existing states. This way the navbar only loads when the parent state is entered and you should be able to change child states that share this parent without affecting it.
While there are better organised ways to do this, my quick and dirty way would be to rename the states you have to withnav.index and withnav.settings. Then remove the navbar view from them and add the following state.
$stateProvider
.state('withnav', {
abstract: true,
views: {
'navbar': {
templateUrl: 'Views/Partials/navbar.cshtml',
controller: 'App.Controllers.NavbarController'
}
}
});

Categories

Resources