Hi all angularjs developer, I have followed the ng document (link) .I have searched since many times but i did not find any solution that will help me properly. I need to change route without reloading the controller and template. I have written a route that look like this below:-
$routeProvider
.when('/page1', {
templateUrl: 'page1',
controller: 'page1Ctrl',
caseInsensitiveMatch: true,
reloadOnSearch: false
})
.when('/page2', {
templateUrl: 'page2',
controller: 'page2Ctrl',
caseInsensitiveMatch: true,
reloadOnSearch: false
})
.when('/page3', {
templateUrl: 'page3',
controller: 'page3Ctrl',
caseInsensitiveMatch: true,
reloadOnSearch: false
}).otherwise({ redirectTo: '/index' });
Moreover, at first I go to the page1 then page2 then page3 after that now i want to go to the page1 without reloading or calling page1Ctrl and page1 template. Example: suppose when i was page1 that time i have worked something like i have selected an ng-grid record which was paging size 3 and i have inputted some fields. After that i go the page3 then i go to the page1 again. Now this time i want to see the page1 what i selected ng grid record and what i inputted. How can i solve this? Thanks.
I want to suggest to use Angular Ui.router
you will have the ability to change the state of routes , for more check the documentation
To persist data when moving away from a controller and then back again, the recommended Angular approach is to use services. See this NG-Conf talk: https://www.youtube.com/watch?v=62RvRQuMVyg.
To persist input fields and paging index when leaving page1Ctrl and then returning, for example, you could create a pagingModelService.
function PagingModelService($rootScope)
{
var pagingModelService = {};
////////////////////
// persisted data //
////////////////////
pagingModelService.pagingIndex;
pagingModelService.field1;
pagingModelService.field2;
////////
//Init//
////////
return(pagingModelService);
}
Then inject the service in the controller, and set the $scope values to the service:
function Page1Ctrl($scope, pagingModelServiceModel)
{
///////////////////////////////////////////////////
//set local $scope variables to persisted service//
///////////////////////////////////////////////////
$scope.pageIndex = pagingModelService.pagingIndex;
$scope.field1 = pagingModelService.field1;
$scope.field2 = pagingModelService.field2;
}
Also, you can look into angular-local-storage for persisting data: https://github.com/grevory/angular-local-storage
Related
I have done some research but couldn't find a definitive answer. I have main application area where I load different screens. From one screen I want to open a page that would cover the whole screen. So, navigating to 'viewreport' does exactly that. And when I click on Browser's Back button or have my own Back button on the whole screen page I want to get back to the previous state without reloading its template and controller. Another words, I want to see all selections I have done prior opening the whole screen page. Here is my state configuration:
$stateProvider
.state('body', {
url: '/',
abstract: true,
template: '<div ui-view />'
})
.state('viewreport', {
url: 'viewreport',
templateUrl: 'wholescreen.html',
controller: 'wholescreenController'
});
I am loading different modules into the main 'body' state which might look like this:
function ($stateProvider) {
$stateProvider.state('body.htmlreports', {
templateUrl: function ($stateParams) {
return 'htmlReports.html';
},
controller: 'htmlReportsController',
url: 'htmlreports',
}).state('body.htmlreports.reportarea', {
templateUrl: 'htmlReportParams.html',
controller: 'htmlReportParamsController',
});
I am navigating to viewreport state from htmlReportParamsController controler. The new page then opens into the whole screen. That part works fine. But navigating back to htmlreports when clicking on the Browser's Back button will reload 'body.htmlreports' state. Is there a way of getting back to it without reloading its template?
Update. Why I think it's not a duplicate.
I tried what's suggested in it before posting. This: $state.transitionTo('yourState', params, {notify: false});
still reloads 'yourState'. Also the use case in the provided link is not exactly as mine. Because the OP uses edit mode for already loaded view while I am loading a new view over the the whole screen.
Thanks
Use
$window.history.back();
Add $window in dependency injections of your controller. This will refresh your page and wont reload data we selected.
Please maintain states like this
function ($stateProvider) {
$stateProvider.state('body.htmlreports', {
templateUrl: function ($stateParams) {
return 'htmlReports.html';
},
controller: 'htmlReportsController',
url: 'htmlreports',
}).state('body.htmlreports.reportarea', {
templateUrl: 'htmlReportParams.html',
controller: 'htmlReportParamsController',
}).state('body.htmlreports.reportarea.viewreport', {
url: 'viewreport'
});
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 debated a while on this but I got a Plunk that reproduce it.
I have a state "Contact" that get loaded by default. with $state.transitionTo
Inside that state I have some views, they all get loaded and everything work.
If I click to change the state to "Home" by default or by "ui-sref" and in the "Home" state/template I have ui-sref="contacts". When we click back to set the state to contacts it should work, but all the sub views are now not being called properly.
It seems that when ui-sref call the state this one behave differently that when it is loaded by default.
Why $state.transitionTo(''); seems to work differently than ui-sref.
<script>
var myapp = angular.module('myapp', ["ui.router"])
myapp.config(function($stateProvider, $urlRouterProvider){
// For any unmatched url, send to /
$urlRouterProvider.otherwise("/")
$stateProvider
.state('home', {
templateUrl: 'home.html',
controller: function($scope){
}
})
.state('contacts', {
templateUrl: 'contacts.html',
controller: function($scope){
}
})
.state('contacts.list', {
views:{
"":{
template: '<h1>Contact.List Working wi no Data defined.</h1>'
},
"stateSubView":{
template: '<h2>StateSubView Working</h2>'
},
"absolute#":{
template: '<h2>Absolute item</h2>'
}
}
});
});
myapp.controller('MainCtrl', function ($state) {
$state.transitionTo('contacts.list');
})
Q2:
Why is the Absolute tag that is under contact work when I add the view in the Index, but is not working when it is inside the contact.html file. Absolute reference work only with the Index and not if called everywhere?
"absolute#":{
template: '<h2>Absolute item</h2>'
}
I saw that in index.html you have an empty ui-view tag. What do you expect to go there? I think you can not do this. The router just doesn't know with which state (home or contacts) it should replace. Apparently it picks the second one (contacts). I'd suggest to put url: '/' in the home state and you'll see the difference.
This is for sure one issue.
Other than that:
You can't simply access views from contacts.list in contacts afaik.
The empty ui-view work as a wild card and can be use to switch across multiple route even if we have nested element. But if we have a nested view contact.list it can only be access if we put the whole path in ui-sref="contacts.list" because the list child of contact cannot be access only by using ui-sref="contacts"
I have multiple routes which serves different pages like so:
$routeProvider.
when('/routeone', {
templateUrl: '/routes/one',
resolve: {}
})
.when('/routetwo', {
templateUrl: '/routes/two',
controller: 'CampaignController',
resolve: {
}
})
.when('/routethree', {
templateUrl: '/routes/three',
resolve: {}
});
Each route page has different model fields but uses one single $scope variable i.e. $scope.template so in one route/template it is:
<span>{{template.var1}}</span>
on other it is
<span>{{template.var2}}</span>
I am fetching route specific data and storing it in $scope.template, but the issue is even when it is assigned it is not showing it on UI fields which are bound.. initially my $scope.template is set to empty string.
If i set all the fields that are used in all the route template like
$scope.template = { var1 = 'var1', var2='var2'}
it works which i don't want to do but if i set it to empty and fetch route specific on route change it doesn't.. can someone plz help..
here is the plnkr
I think you need this
https://docs.angularjs.org/api/ngRoute/service/$routeParams
I am using angular router, and I have a route similar to the one below
angular.module("manageAbcApp", ["myApp", "ngRoute"])
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/list', {
templateUrl: '/Scripts/app/views/abc/AbcList.htm',
controller: 'ListAbcController'
})
.when('/view/:id', {
templateUrl: '/Scripts/app/views/abc/AbcDashboard.htm',
controller: 'DashboardAbcController'
})
// more...
.otherwise({
redirectTo: '/list'
});
}]);
So as you can see there are 2 routes one for listing and other for dashboard of the item selected for the listing.
In the listing route a list view is selected and shown where I show a grid with some data, one of the column in this grid is the name column which is clickable and on click of it i change the route to href="#/view/{row.Id}".
This works fine.
But, How do I also pass some additional paramters to the DashboardAbcController like the name or any other details ?
Edit: I figured out I could use a service common to both these controller and on ng-click update some model in the service. But I do not want to use ng-click coz if I do then I ll lose the option to allow user to open my link in new tab, copy paste, share etc...
What about something like: Demo
.when('/list', {
templateUrl: '/Scripts/app/views/abc/AbcList.htm',
controller: 'ListAbcController'
})
.when('/view/:id/:name/:other/:details', {
templateUrl: '/Scripts/app/views/abc/AbcDashboard.htm',
controller: 'DashboardAbcController'
})
And, you could create a link like:
Home
Note: That you can pass other data as route params that you don't want to fix into the routes.
either use $rootscope to assign values ex. $rootscope.name = 'name' or use get parameter
.when('/view/:id?name=&id=', {
templateUrl: '/Scripts/app/views/abc/AbcDashboard.htm',
controller: 'DashboardAbcController'
})