TL;DR I have a modal state that I want to have a refreshable link. The modal state is opened with ng-click and ng-show. How can I make this modal linkable?
I have a modal window that I've given a custom URL. I have the modal window as a child state (screenings.images) in my config, and it shares the same controller as the parent (screenings), like so:
.state('screenings', {
url: '/screenings/',
templateUrl: 'pages/page.php',
controller: 'screeningsController'
})
.state('screenings.images', {
url: ":image/",
controller: 'screeningsController'
})
When an image in the screenings view is clicked, the URL navigates to screenings/red/, for example.
The modal has an ng-show directive attached to it:
<div ng-show="show" class="swiper-container">
The modal is opened with an ng-click on an image container:
<div ng-click="swipeShow()" class='img_div'>
This function swipeShow() and its counterpart swipeHide() are in the controller, like this:
$scope.swipeShow = function(){
$scope.show = true;
};
$scope.swipeHide = function(){
$scope.show = false;
}
From here, I'm not sure how to make the modal window URL refreshable.
What I've Tried
I've tried giving the child state a completely separate controller:
.state('screenings.images', {
url: ":image/",
controller: 'screeningsImagesController'
})
..and then in that new controller, I've tried automatically setting:
$scope.show = true;
..so that the modal should be set to already displaying. I figured that, if this controller is what is refreshed and loaded in, then it would automatically set <div ng-show="show=true" class="swiper-container">, but that's not the case.
Related
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
I have a map with markers on it. When you click a marker a child view opens with the marker details.
.state('map', {
url: '/map',
...
})
.state('map.detail', {
url: '/:markerId',
...
})
If you open a marker's details, navigate away from the map, then back to the map using ui-sref="map" the url will change to /map/<markerId> with the child view open.
I'd like to go straight to /map when clicking on ui-sref="map" but don't want to reload the 'map' just hide any child view.
Is there a simple way to do this? I've tried combinations of cache: false on the two states but that doesn't do what I want.
I am not fully sure, what is your issue. Because this
...I'd like to go straight to /map when clicking on ui-sref="map" but don't want to reload the map just hide any child view...
is the default behavior of UI-Router. There is a working plunker
These links, will not trigger RE-init of parent controller ('map' state)
<a ui-sref="map">
<a ui-sref="map.detail({markerId:1})">
<a ui-sref="map.detail({markerId:22})">
And states like this:
.state('map', {
url: "/map",
templateUrl: 'tpl.html',
controller: 'ParentCtrl',
})
.state('map.detail', {
url: "/:markerId",
templateUrl: 'child.html',
controller: 'ChildCtrl',
})
And both controllers:
.controller('ParentCtrl', ['$scope', function ($scope) {
$scope.timestamp = new Date().getTime();
}])
.controller('ChildCtrl', ['$scope', function ($scope) {
$scope.timestamp = new Date().getTime();
}])
And we can see, that 'map' state is still not changed
Check it here
I have a text box with a search Button as below
On clicking the search button, I am calling SearchController.search method and
my expectation is it will display a new page with the result.
$scope.search = function () {
$http.get('data/results.json').success(function (data) {
$scope.activities = data;
$state.go('results',data);
});
and my app.js looks as below
var myApp = angular.module('MyApp', ['ui.router']);
myApp.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('results', {
url: '/results',
templateUrl: 'result.html',
controller: 'SearchController'
});
$urlRouterProvider.otherwise('/');
});
But when I click on search button, nothing happens and url only changes to l/#/results .
I am not having any ui-view in search page and I want to go results page to display the result. How to get this fixed? what is the mistake I am doing?
You can't send a not mapped object into $state.go.
Looking the API: http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$state
Another similar problem: AngularJS: Pass an object into a state using ui-router
If you want to display it on a different page, use the "ui-sref" on the html to navigate to the new page and call ng-init on the page e.g
<button type="button" ui-sref="results">
and on result.html, you can call the init on the parent node such as
<section ng-init="search()">
.....
....
</section>
and your controller will look like this now
$scope.search = function () {
$http.get('data/results.json').success(function (data) {
$scope.activities = data;
});
With ui-router, state changes happens and different view is displayed based on state. So , when ui-router is used , moving from one page to another page is a wrong perception . We move from one state to another state and hence parameter passing can be done using "services".
I've been aggressively working on an app that uses AngularJS and Bootstrap. To help, I've included the Bootstrap UI framework. I am successfully opening a dialog and closing the dialog. However, I'm not sure how to actually "get" the data when a user clicks "Save Item".
My Plunker is Here
As shown in the Plunker above, I have my controller defined like this:
var modalInstance = $modal.open({
templateUrl: 'item-dialog.html',
size: 'sm',
controller: function($scope, $modalInstance) {
$scope.saveItem = function () {
alert('Saving...');
alert('ID: ' + $scope.newItem.typeId);
alert('Data: ' + $scope.newItem.data);
};
$scope.cancelItem = function() {
$modalInstance.close(false);
};
}
});
When I go to show the id of the item the user selected, and the text the user entered, it doesn't work. newItem is undefined. However, in the markup, you can see ng-model="newItem.data"
How do I get the information that the user entered in my controller?
Thank you!
You are not passing the result back to the controller opening the modal when you close it, you just need to add this in the modal's controller:
$modalInstance.close($scope.newItem);
See plunk.
Another thing: I've found that if you do not manually initialize objects on the $scope of the modal controllers of angular ui, they do not get bound properly, hence the $scope.newItem={} in the controller of the modal.
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.