$routeProvider - modal of a single page with different URL - angularjs

I have a list of items showed in a page. The idea is to click on an item, and open a modal showing the information of the selected item, and in the background the list remains.
When the modal opens, the URL should change. So the idea would be to have a specific URL for every item, so when you access the url, you should see the modal, with the item info and in the background the main page.
I'm using $routeProvider for routing.
Example:
I would like to have something similar to this
http://www.eltrecetv.com.ar/articulo/le-salio-del-alma-el-emotivo-recuerdo-de-la-china-suarez-para-su-papa-en-una-fecha_087466
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.when('/meals', {
templateUrl: 'views/meals/meals.html',
controller: 'MealsCtrl'
})
.when('/meal/:mealId', {
templateUrl: 'views/meals/meal-profile.html',
controller: 'MealCtrl'
})
The /meal/:mealId should be shown in a modal, and the URL should change when the modal is opened.
I've searched a lot, but I couldn't find a suitable answer for this.
Thanks for the help!!

You can specify states you want to show as modal and when it is handled, return to state you want to. For example:-
app.config(function ($stateProvider) {
$stateProvider.state('tasks', {
url: '/tasks',
templateUrl: 'tasks.html',
controller: 'TasksCtrl'
url: "/tasks/:id",
onEnter: function($stateParams, $state, $modal) {
$modal.open({
templateUrl: "show.html",
resolve: {},
controller: function($scope, $state) {
$scope.ok = function () {
$scope.$close();
};
$scope.dismiss = function () {
$scope.$dismiss();
};
}
}).result.then(function (result) {
// $scope.$close
}, function (result) {
// $scope.$dismiss
}).finally(function () {
// finally
return $state.transitionTo("tasks");
});
}
});
});
Here is plunker code for it : code
I will edit my answer for routeProvider also.

Related

broadcast and emit does not work with ng-router?

I want pass the value to one nerds controller to geek controller but unable to pass in ng-router.
<button type="Submit" ng-click="showUser()">Show Details</button>
.when('/geeks', {
templateUrl: 'views/geek.html',
controller: 'GeekController'
})
.when('/nerds', {
templateUrl: 'views/nerd.html',
controller: 'NerdController'
})
In Nerds controller I have this function
$scope.showUser=function(){
$rootScope.$broadcast('btnName',{message:"msg"})
}
In geek controller I receiving the value on page load itself but i am not getting the value pls help me to find the solution
$rootScope.$on('btnName',function(event,args){
$scope.msg=args.message;
console.log("$scope.message nnnn",$scope.msg)
})
The NerdController and the GeekController are in two separate pages, only one of the controllers can be active at a time, since angular has only one page open in the tab. So what I suggest is, pass the variable as a parameter to the route, you can see this in the example below.
JSFiddle Demo
JS:
var routingExample = angular.module('Example.Routing', []);
routingExample.controller('NerdController', function ($scope, $location) {
$scope.showUser = function(){
console.log("show");
$location.path('/geek/1');
}
});
routingExample.controller('GeekController', function ($scope, $routeParams) {
$scope.id = $routeParams.id;
});
routingExample.config(function ($routeProvider) {
$routeProvider.
when('/nerds', {
templateUrl: 'home.html',
controller: 'NerdController'
}).
when('/geek/:id', {
templateUrl: 'blog.html',
controller: 'GeekController'
}).
otherwise({
redirectTo: '/nerds'
});
});

angular state.go function does not redirect to previous page

I have to display a modal from the main menu. The modal displays correctly. But when I close the modal, i want the previous url to be displayed.
This is the code for the modal:
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'views/home.html',
controller: 'HomeCtrl'
})
.state('pos',{
url: '/pos',
templateUrl: 'views/pos.html',
controller: 'PosCtrl'
})
.state('vAnalyze',{
url: '/vAnalyze',
templateUrl: 'views/vAnalyze.html',
controller: 'VAnalyzeCtrl'
})
.state('reportSetting',{
url: '/reportSettingModal',
onEnter: function($modal){
$modal.open({
templateUrl: 'views/reportSettingModal.html',
controller: 'ReportSettingModalCtrl'
});
}
})
.state('error', {
url: '/error',
templateUrl: 'lib/views/error.html',
controller: 'ErrorCtrl'
});
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/home');
})
.run(['AuthService', 'configSettings', '$rootScope', function (AuthService, configSettings, $rootScope)
{ // Apply Product Code
configSettings.productCode = 'VANALYZE';
AuthService.configProduct(configSettings.productCode);
$rootScope.$on('$stateChangeSuccess', function(event, to, toParams, from, fromParams) {
$rootScope.$previousState = from;
});
} ]);
This is the function to close the modal:
$scope.close = function() {
$uibModalInstance.close();
$state.go($rootScope.$previousState.name, {
url: $rootScope.$previousState.url,
templateUrl: $rootScope.$previousState.templateUrl,
controller: $rootScope.$previousState.controller
});
};
When I step into the code the url, templateUrl and controller all have the correct data. But the page is not displayed.
The page displayed when I close the modal is reportSettingModal.
What am I doing wrong?
You can go by using $state.go but that is not a good practise. Because, in general, there should not be any relation between displaying a modal and state change. Showing a modal should be independent of route configuration. Just use something like addClass or removeClass to show the modal when you click on link or button.
$scope.show = function (){
// open modal here by adding a class to the modal element
}
In the same way close the modal.

Separate nav from ng-view

I'm brand new to Angularjs and am trying to set up a new site but I'm confused as to the set up. I have a module and am using $route to successfully navigate but I'm lost as to what to do with my nav. When I load the module I want to read my database for a list of links that the user is allowed to access then spit them out in the nav. I don't want to repeat this in every view because I don't need to. So I'm trying to figure out how to run the ajax call once and then keep changing the view (I'd also like to add a class .selected to whatever view they're on). How would I go about doing that, with a directive?
(function () {
var app = angular.module('manage', ['ngRoute', 'manageControllers']);
/*
I've tried this but obviously $http isn't injected. Can I even do that?
var thisApp = this;
$http.get('/test/angular/php/angular.php', {params: {'function': 'nav'}}).then(function successCallback(response) {
});
*/
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'templates/dash.html',
controller: 'DashCtrl'
}).
when('/inventory/', {
templateUrl: 'templates/inventory.html',
controller: 'InventoryCtrl'
}).
when('/inventory/:mvKey', {
templateUrl: 'templates/inventory.html',
controller: 'InventoryCtrl'
}).
when('/inventory/:mvKey/:tab', {
templateUrl: 'templates/inventory.html',
controller: 'InventoryCtrl'
}).
/* etc...*/
}
]);
})();
EDIT:
My attempt at getting the nav to run once
controllers.js
var manageControllers = angular.module('manageControllers', []);
var thisApp = this;
nav = null;
navSelected = '/';
manageControllers.controller('NavCtrl', ['$scope', '$http', function($scope, $http) {
if (thisApp.nav === null) {
$http.get('php/angular.php', {params: {'function': 'nav'}}).then(function successCallback(response) {
console.log(response.data);
thisApp.nav = response.data;
$scope.nav = thisApp.nav;
$scope.select = thisApp.navSelected;
});
} else {
$scope.nav = thisApp.nav;
$scope.select = thisApp.navSelected;
}
}]);
manageControllers.controller('DashCtrl', ['$scope', function($scope) {
thisApp.navSelected = '/';
}]);
I would swith to UI Router (https://github.com/angular-ui/ui-router) instead of $route. It allows you being much more flexible with your routing.
A Small example:
app.config(['$stateProvider',
function($stateProvider) {
$stateProvider.
state('/', {
url: '/',
views: {
'': {
templateUrl: 'templates/dash.html',
controller: 'DashCtrl'
},
'nav#': {
templateUrl: 'path/to/nav.html',
controller: 'NavCtrl'
},
}
}).
state('/inventory/', {
url: '/',
views: {
'': {
templateUrl: 'templates/dash.html',
controller: 'DashCtrl'
},
'nav#': {
templateUrl: 'path/to/nav.html',
controller: 'NavCtrl'
},
}
}).
// ...
and in your index.html
<div ui-view="nav"></div>
<div ui-view ></div>
Take a closer look at UI Router's doc, there's much more you can do with it!

Dynamically switch ng-include between controllers

I have the following bit of code for my navigation that I want to update dynamically between pages.
<nav ng-include="menuPath"></nav>
Here is my app and routing set up
var rxApp = angular.module('ehrxApp', ['ngRoute']);
// configure our routes
rxApp.config(function ($routeProvider) {
$routeProvider
.when('/', {
controller: 'mainController',
templateUrl: '/content/views/index.html'
})
.when('/census', {
templateUrl: '/content/views/admission/census.html',
controller: 'censusController'
})
.when('/messages', {
templateUrl: '/content/views/account/messages.html',
controller: 'messagesController'
})
.when('/profile', {
templateUrl: '/content/views/account/profile.html',
controller: 'profileController'
})
});
In my main controller I set the menuPath value here:
rxApp.controller('mainController', function (userService, $scope, $http) {
evaluate_size();
$scope.menuPath = "/content/views/index.menu.html";
});
rxApp.controller('censusController', function ($scope, $http, $sce, censusService) {
$scope.menuPath = "/content/views/admission/census.menu.html";
evaluate_size();
});
When the page switches to the census view it should change the menu. What happens though is the first page loads the main menu, then no matter what other page you go to the menu never updates.
I imagine this problem has something to do with a primitive values and prototypical inheritance between child scopes, but would need to see more of your html to determine that. Without that, I propose an alternative way that may solve your problem and keep the config all in one place.
$routeProvider will accept variables and keep them on the route, even if angular doesn't use them. so we modify your routing by including the menuPath like so:
var rxApp = angular.module('ehrxApp', ['ngRoute']);
// configure our routes
rxApp.config(function ($routeProvider) {
$routeProvider
.when('/', {
controller: 'mainController',
templateUrl: '/content/views/index.html',
menuPath: '/content/views/index.menu.html'
})
.when('/census', {
templateUrl: '/content/views/admission/census.html',
controller: 'censusController',
menuPath: '/content/views/admission/census.menu.html'
})
.when('/messages', {
templateUrl: '/content/views/account/messages.html',
controller: 'messagesController'
})
.when('/profile', {
templateUrl: '/content/views/account/profile.html',
controller: 'profileController'
})
});
Remove setting $scope.menuPath from each controller, then finally add a watch on rootScope that will change the menuPath on $routeChangeSuccess
rxApp.run(['$rootScope', function ($rootScope) {
$rootScope.$on('$routeChangeSuccess', function(event, current) {
if (current && current.$$route && current.$$route.menuPath) {
$rootScope.menuPath = current.$$route.menuPath;
} else {
$rootScope.menuPath = '';
}
});
}]);

How to know next state in ui-router

I'm showing and hiding a modal when the user go to a specific state (/login), but I would keep the modal in background if the users goes to /register from /login.
If the user is in /login and then goes to /register, I would the login modal to stay opened, while if the user is in /login and then goes to a different page, I would the login modal to disappear.
Actually I set the Angular-ui-router $stateProvider in this way:
app.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
$stateProvider
.state('home', {
url: "/",
templateUrl: "templates/home.html",
controller: 'HomeCtrl'
})
.state('login', {
url: "/login",
onEnter: function ($stateParams, $state, Modal) {
// * modalCtrl for Login
if (window.loginModal) {
window.loginModal.remove();
delete window.loginModal;
Modal.fromTemplateUrl('templates/user/login.html', function (modal) {
window.loginModal = modal;
loginModal.show();
});
} else {
Modal.fromTemplateUrl('templates/user/login.html', function (modal) {
window.loginModal = modal;
loginModal.show();
});
}
},
onExit: function ($stateParams, $state) {
if ( window.loginModal && /* condition like "!nextState.is('register')" */ ) {
window.loginModal.hide();
}
}
})
.state('register', {
url: "/register",
onEnter: function ($stateParams, $state, Modal, SlideBoxDelegate) {
// * modalCtrl for Register
if (window.registerModal) {
window.registerModal.remove();
delete window.registerModal;
Modal.fromTemplateUrl('templates/user/register.html', function (modal) {
window.registerModal = modal;
SlideBoxDelegate.update();
registerModal.show();
});
} else {
Modal.fromTemplateUrl('templates/user/register.html', function (modal) {
window.registerModal = modal;
SlideBoxDelegate.update();
registerModal.show();
});
}
},
onExit: function ($stateParams, $state) {
if ( window.registerModal ) {
window.registerModal.hide();
}
}
})
.state('not_found', {
url: "/not_found",
templateUrl: 'templates/not_found.html',
controller: 'NotFoundCtrl'
})
$urlRouterProvider.otherwise("/not_found");
$locationProvider.html5Mode(true);
})
Is there a way to set the condition like "!nextState.is('register')"?
Thank you for reading :)
You can listen for $stateChangeStart and note the value of the to parameter some place that is accessible to your onExit function, i.e. an injectable value or service.
In the future, there will be an injectable service that will represent the transition itself, which you'll be able to inspect and manipulate for things like this.
The best trick I have found so far is to use the promise inside the $state service, in the onExit function :
onExit: function ($state) {
$state.transition.then(toState => {
if (toState.name === 'nameOfTheWantedNextState') {
$state.go($state.current, {}, {reload: true});
}
})
}
This avoids listening to the event and storing the name somewhere, it only uses whats available at the time of the transition. Quite neat !

Resources