angular ui bootstrap modal on different routes - angularjs

How would I open routes template in bootstrap modal, without to leave the current page, taking in cosideration the following scenario ?
I have the router
$routeProvider
.when('/', {
templateUrl: '/views/products.html',
controller: 'MainCtrl'
})
.when('/product/:articleId', {
templateUrl: '/views/product-detail.html',
controller: 'ProductDetailCtrl'
})
.otherwise({
redirectTo: '/'
});
Controller
angular.module('n2goApp')
.controller('MainCtrl', function($scope, $location, $cookieStore, api) {
api.products().then(function(response) {
$scope.products = response;
$scope.totalItems = response.total;
$('#loading').hide();
})
});
produced 1st View which is a list and hyperlinks ro 2nd view and will be opened in modal
<div ng-controller="MainCtrl"><h2><div ng-repeat="product in products">{{ product.productname}}</h2></div></div>
now when user clicks on link will be routed to the 2nd controller, and modal will be produced but leaving the current page // should not leave, behind should stay the current view
angular.module('n2goApp')
.controller('ProductDetailCtrl', function ($scope,$modal, api, $routeParams) {
var articleID = $routeParams.articleId;
$scope.edited = api.product(articleID);
$modal.open({templateUrl:'/views/product-detail.html'});
});
when user closes modal should see the before visited view

I don't think you need routes for this. Why don't you simply use an AngularJS Anchor, clicking on which would load the modal with a template. Routes are for switching URLs but you don't want to do that.
If you absolutely have to use routes then you could simulate this by transitioning back to the '/' route once the modal is closed (in the onClose() handler or equivalent call $location.path("/")).
Of course this would mean your controller for the home page would get re-executed.

Related

Angularjs UI bootstrap temporarily change URL on open and revert to original URL on close

I want to temporarily change the browser url when the ui bootstrap modal is opened ( The page behind should remain as is, only the url changes ). When the modal is closed the url should be reverted back to the original one.
Steps :
User loads the page
url : xyz.com/home
User clicks a link opens a modal
url : xyz.com/detail/123
possible solution : changing url with html5 push state
problem : Angular ui-router tries to run its routes as per the changed url, eventually changing the background page.
User closes the modal
url : xyz.com/home
possible solution : html5 pop state
problem : Reloads the background page, which kills the purpose
Example implementation : Pinterest pins and their pin details popup.
You can use ui-router-extras sticky state to solve your problem. There is simple example with modal by the link. You should create two named views, one for main content (background) and one for modal.
<div ui-view="app"></div>
<div ui-view="modal"></div>
Mark the state, from what you want to access to modal as sticky: true in route definition.
.state('main', {
abstract: true,
url: '/',
templateUrl: '_layout.html'
})
.state('main.index', {
url: '',
sticky: true,
views: {
'app': {
templateUrl: 'index.html'
}
}
})
.state('main.login', {
url: 'login/',
views: {
'modal': {
templateUrl: 'login.html'
}
}
})
Also add an event for stateChangeSuccess:
$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
if ((from.views && !from.views.modal) || !from.views) {
$rootScope.from = from;
$rootScope.fromParams = fromParams;
}
});
so, when you need to close modal, you can just
$state.go($rootScope.from, $rootScope.fromParams);
There is small problem for that solution. If you reload page on the modal state, then the app ui-view will be empty.
This can be achieved by having a nested state and triggering the modal using onEnter callback:
$stateProvider
.state('contacts', {
url: '/home',
templateUrl: 'home.html',
controller: function($scope, MyService){
$scope.contacts = MyService.getContacts();
}
})
.state('contacts.details', {
url: "^/details/:id", // using the absolute url to not have the "/home" prepended
onEnter: function($state, $uibModal) {
var modal = $uibModal.open({
templateUrl: 'details.html',
controller: function($scope, $stateParams, MyService) {
// get data from service by url parameter
$scope.contact = MyService.getContact($stateParams.id);
}
});
modal.result.finally(function() {
$state.go('^'); // activate the parent state when modal is closed or dismissed
});
}
});
This technique is described in the ui-router's FAQ.
Here the plunk. In this example the modal's scope is created as a child of the $rootScope - the default $uibModal's behavior when no scope is passed to it. In this case we should use the service in the modal's controller to obtain the data by url parameter.
To have master and details URLs look like these - xyz.com/home and xyz.com/detail/123 - we should use the absolute URL (^/details/:id) in the child state.
Using this solution you can open the detail URLs directly and still have both, master and detail states, activated properly, so sharing the detail URL is possible.
I think you can achive that with ngSilent module
https://github.com/garakh/ngSilent
using $ngSilentLocation.silent('/new/path/');
(once you open modal and again after closing it)
Managed to implement this using https://github.com/christopherthielen/ui-router-extras/tree/gh-pages/example/stickymodal

Can I force controller to reload some data when people hit back button even on the same route in angular?

In my angular app, this is my route pattern:
$routeProvider
.when('/DocumentUploader/folder/:folderid?', {
templateUrl: '/FileManagers/views/items.html',
controller: 'ItemsCtrl',
controllerAs: 'items'
})
.otherwise({
redirectTo: '/DocumentUploader/folder'
});
When the page loads, the default route is:
http://localhost:5460/Workbenchv2.cshtml#/DocumentUploader/folder
So this will go to the root folder.
Then user can click a folder name, and the route changes to
http://localhost:5460/Workbenchv2.cshtml#/DocumentUploader/folder/92E39760-156D-4C62-A295-E4D1C20706CD (internal ID for the folder)
Now if user hit the back button, angular will not reload the controller (as it is the same route), so I can't refresh my data.
Is it possible to force angularjs to reload the controller, even if the route is the same?
I've created a Plunker here: Plunker Link
In my case when user click the back button, the controller is reloaded. Here is the controller that I'm using:
myApp.controller('ItemsCtrl', ['$scope', '$routeParams',
function($scope, $routeParams){
var folderId = $routeParams.folderid;
if(!folderId){
$scope.msg = 'You are in root folder';
} else {
$scope.msg = 'You are in folderId=' + folderId;
}
}
]);

AngularJS - Ionic : execute code in controller when coming back to it

I'm new in AngularJS Community and I'm developping my first app with this Framework.
I created a new controller with this code :
.controller('AccountCtrl', function($scope, $location) {
alert('test');
})
And my route :
.state('app.account', {
url: "/account",
views: {
'menuContent': {
templateUrl: "templates/account.html",
controller: 'AccountCtrl'
}
}
})
The alert popup is shown the first time I access to the controller. But, if I change URL and I come back to AccountCtrl (with a classic html a), the alert popup is not shown again.
Could somebody explain to me why ?
Thanx for your help !
In Ionic Framework views and controllers will be cached by default. You ma add a listener to the views scope to receive a notification when the view is re-active again. For more information see: http://ionicframework.com/docs/api/directive/ionView/
and http://ionicframework.com/docs/api/directive/ionNavView/
You may also disable the cache on a view <ion-view cache-view="false">
.controller('AccountCtrl', function($scope, $location) {
$scope.$on('$ionicView.beforeEnter', function () {
// update campaigns everytime the view becomes active
// (on first time added to DOM and after the view becomes active after cached
alert('test');
});
})`
to reload Controller each time in ui router, use reload: true option on the .state
$stateProvider
.state('app.account', {
url: "/account",
reload: true //forcefully reload route and load controller again
})

AngularJs with routes and anchor tags, working on second click

I have a simple view representing a simple menu which should be using anchor behavior. On the same page there's a bunch of H2 tags with id that the links should scroll to.
I'm using the $anchorScroll and $location.
THE ISSUE: The first time I click a link, I can see that the route is updated, e.g.:
http://localhost:60002/#!/docs/view/somedoc#someResourceId
But it triggers a route, the SECOND time I click it, it behaves as expected.
UPDATE: It's not the anchorScroll() did it manually using element.scrollIntoView(true) same behavior. If I don't use $location.hash it works, but then I loose the possibility of linking to anchors.
Any ideas?
VIEW:
<div ng-controller="DocsMenuCtrl">
<ul ng-repeat="menuItem in menuItems">
<li><a ng-click="foo(menuItem.resourceId)">{{menuItem.title}}</a></li>
</ul>
</div>
...
...
<h2 id="...">Test</h2>
...
CONTROLLER:
module.controller('DocsMenuCtrl', ['$scope', '$http', '$location', '$anchorScroll', 'session', function ($scope, $http, $location, $anchorScroll, session) {
$scope.foo = function (resourceId) {
$location.hash(resourceId);
$anchorScroll();
};
$http.get('/api/menu/').success(function (d) {
$scope.menuItems = d;
}).error(function () {
session.logger.log(arguments);
});
}]);
ROUTEPROVIDER CONFIG etc
$locationProvider.hashPrefix('!');
$routeProvider
.when('/default', {
templateUrl: 'clientviews/default',
controller: 'DefaultCtrl'
})
.when('/docs/view/:id', {
templateUrl: 'clientviews/docs',
controller: 'DocsCtrl'
})
.otherwise({
redirectTo: '/default'
});
$location does not reload the page even if it is used to change the url. See the "What does it not do?" section of this page: $location ngDoc.
As Ganonside said, the location service does not reload the url. Once you are certain that the url changes you can use the route service, specifically $route.reload() to trigger your routing.
The best solution I've found is here: https://github.com/angular/angular.js/issues/1699#issuecomment-22509845
Another option, if you don't use search params, is to tell the route provider not to reload on hash or search changes (unfortunately, it is one option for both).
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/group/:groupName', {
templateUrl: '/templates/groupView.html',
reloadOnSearch: false
}).otherwise({redirectTo: '/'});
}]);

AngularJS $location not updated properly when using $routeProvider

I have an Angular JS application with a defaultController which controls the header of the app. Then I have some other controllers one for each view. The views are loaded in the <main>. I load the views using the $routeProvider with this code:
myapp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/login', {
templateUrl: 'templates/login.html',
controller: 'loginController'
}).
when('/dashboard', {
templateUrl: 'templates/dashboard.html',
controller: 'dashboardController'
}).
...
I am trying to display a LOGOUT button inside the header when the loaded view is the dashboard and hide it if the loaded view is the login view. In order to do that I have on the defaultController the $location object and I properly add and remove classes from the LOGOUT button with ng-class.
There is only one problem: $location gives me the correct path the first time I load the page, but after I change the view (changed by the $routeProvider) that variable is not updated anymore, so when I am actually on /#/dashboard , the $location.url is still on /login. Here the controller code:
controllers.controller('defaultController', ['$scope', 'ipCookie', '$location', function($scope, ipCookie, $location) {
$scope.url = $location.url();
...
I also tried with $window.location.hash with the same result.
Any idea?
EDIT: after the accepted answer this is what I ve added on the defaultController in order to make it work
$scope.$on("$locationChangeSuccess", function() {
$scope.url = $location.url();
});
The location is probably updated in the service after your default controller is loaded.
You can either inject the $location service into the scope and make decisions in your template based on it (then it will automatically be watched and re-evaluated) or you could listen for the $locationChangeSuccess event.
When injecting, you can simply $scope.location = $location and then use something like <a ng-hide="location.path() != '/something'">.
$location broadcasts the $locationChangeSuccess on the root scope, so you should be able to listen for it on whichever scope you have available: $scope.$on( "$locationChangeSuccess", function() { /* do something */ } );

Resources