angular ui-router reload one of resolves - angularjs

I'm developing a web application based on angular.js ui-router. I have a page where a lot of info is loading (news, products etc.). This info initializes through state resolves.
$stateProvider
.state("cabinet", {
url: "/cabinet",
template: "app/views/cabinet/index.html",
resolve: {
news: ["NewsService", function (newsSvc) {
return newsSvc.getList();
}],
user: ["UserProfileService", function (userSvc) {
return userSvc.me();
}],
services: ["ServiceService", function (serviceSvc) {
return serviceSvc.getList();
}],
products: ["ProductService", function (productSvc) {
return productSvc.getList();
}],
templates: ["TemplateService", function (templateSvc) {
return templateSvc.getList();
}]
})
.state("cabinet.profile", {
url: "/cabinet/profile",
template: "app/views/profile/index.html"
})
...
Can I reload only of on resolves of state "cabinet" when I move from another page? For example, I come back from "cabinet.profile" to "cabinet" and I want to reload not all resolves, but only "user". Is it possible? Google tells me nothing about this.
$state.go("cabinet", {}, {reload: true}) - reload all resolves.

Related

angularjs 1.x - stateProvider ignoring url property

I have an application with a main state and a child state. I do have the url property set but it seems angular it is ignoring it, but it is not ignoring the optional parameter at the end, which is correctly populated. Please see below code snippet. (to be honest, this application always worked but after an update in the Siemens product this particular feature is not behaving correctly, but at the end of the day this is an angular app, so I am not sure how they could have changed globally this behavior if you have an idea I will be very happy to check that). thanks
this is the main page:
function config($stateProvider) {
var item = {
name: "Carriers",
//ShippingAndReceiving is ignored, but /:direction is correclty attached to the URL
url: '/ShippingAndReceiving/:direction',
views: {
'Canvas#': {
templateUrl: folder + '/carrierOverview.html',
controller: 'CarrierOverviewController',
controllerAs: 'vm'
}
},
data: {
title: 'Vehicles'
},
params: {
reload: null,
carrier: null,
direction: null,
arriving: null
}
};
$stateProvider.state(item);
}
this is the child page:
function config($stateProvider) {
var item = {
name: 'Carriers.Details',
url: '/RegisterVehicle',
};
$stateProvider.state(item);
}
both the pages load correctly and everything works properly, but the URL does not change, it is constantly "Carriers" for both pages.
I do not have any extra unnecessary $state.go anywhere.
this is the call to browse to the page:
$state.go('Carriers.Details');

passing parameter to Angular application state

I have made yoman angular fullstack app setup.
I am making use of ui.router in application.
I have defined state parameters as
.state('tour', {
url: '/tour',
templateUrl: 'app/tour/tour.html',
controller: 'tourCtrl',
params : {tourName: null, },
})
I am able to pass parameter to this state within application.
when my application goes to external link.
I want to get back to one of the state of my angular application with some parameter. so how can i do that??
Please Help me to do that .. Thanks
you can pass parameters and maintain states using stateParams, and then maintaining them in the URL. For your understanding, I have added a plunk:
http://plnkr.co/edit/SDOcGS?p=preview
Observe the console whenever you navigate to Route1 tab, and then observe the code:
.state('route1', {
url: "/route1/:place",
params: {
place: null
},
views: {
"viewA": {
template: "route1.viewA"
},
"viewB": {
template: "route1.viewB"
}
},
resolve :{
place: function($stateParams){
console.log($stateParams);
console.log("url", window.location);
return $stateParams.place;
}
}
})
Try this on localhost. It would work the same way on localhost, or any place where its hosted.

state loading issue (javascript loads before templateUrl)

I am using angularJS to load forms and having 2 issues
JS files loads before templateUrl
When I move to new View then JavaScript functions in old views are also accessible.
Please have a look at attached code:
.state('index.categdashboard', {
url: "/categdashboard",
templateUrl: "views/categdashboard.html",
data: { pageTitle: 'Category wise Headcount - Dashboard' },
controller: 'getCategoryWiseSummary',
resolve: {
loadPlugin: function ($ocLazyLoad) {
return $ocLazyLoad.load([
{
files: [
// Row 1
'js/categdashboard/categdashboard.js',
],
cache: false
}
]);
}
}
})
I have tried
$(document).ready(function () {
but it also did not worked
I declared a new controller in my new view and called the JavaScript functions from it.
angular
.controller('MainDashboardCtrl', MainDashboardCtrl)
function MainDashboardCtrl(){
// Called functions here
}
<div ng-controller="MainDashboardCtrl as MDCtrl">
</div>

UI-Router - Change $state without rerender/reload of the page

I've been looking at these pages (1, 2, 3). I basically want to change my $state, but I don't want the page to reload.
I am currently in the page /schedules/2/4/2014, and I want to go into edit mode when I click a button and have the URL become /schedules/2/4/2014/edit.
My edit state is simply $scope.isEdit = true, so there is no point of reloading the whole page. However, I do want the $state and/or url to change so that if the user refreshses the page, it starts in the edit mode.
What can I do?
For this problem, you can just create a child state that has neither templateUrl nor controller, and advance between states normally:
// UPDATED
$stateProvider
.state('schedules', {
url: "/schedules/:day/:month/:year",
templateUrl: 'schedules.html',
abstract: true, // make this abstract
controller: function($scope, $state, $stateParams) {
$scope.schedDate = moment($stateParams.year + '-' +
$stateParams.month + '-' +
$stateParams.day);
$scope.isEdit = false;
$scope.gotoEdit = function() {
$scope.isEdit = true;
$state.go('schedules.edit');
};
$scope.gotoView = function() {
$scope.isEdit = false;
$state.go('schedules.view');
};
},
resolve: {...}
})
.state('schedules.view', { // added view mode
url: "/view"
})
.state('schedules.edit', { // both children share controller above
url: "/edit"
});
An important concept here is that, in ui-router, when the application is in a particular state—when a state is "active"—all of its ancestor states are implicitly active as well.
So, in this case,
when your application advances from view mode to edit mode, its parent state schedules (along with its templateUrl, controller and even resolve) will still be retained.
since ancestor states are implicitly activated, even if the child state is being refreshed (or loaded directly from a bookmark), the page will still render correctly.
REF: https://github.com/angular-ui/ui-router/wiki/Quick-Reference#statetransitiontoto-toparams--options
$state.transitionTo('yourState', params, {notify: false});
Adding my answer because I think it's different enough from the accepted answer and may be useful to others:
I had two states, begin and view, with a bunch of optional parameters being synced with the URL for view, like so:
$stateProvider
.state('begin',
{
url: '/',
template: '<app-element></app-element>'
})
.state('view',
{
url: '/View?param1&param2&...&paramN',
template: '<app-element></app-element>'
params: {
param1: {
value: null,
squash: true
},
...
}
});
The link function for <app-element> would run any time I tried to sync the parameters using $state.go. Using {notify: false, reload: false} did not work for me. The link function still ran each time. I'm on 0.2 so dynamic isn't an available param option, either. I followed #b0nyb0y's suggestion and turned it into a parent/child relationship, which worked:
$stateProvider
.state('app',
{
url: '/',
template: '<app-element></app-element>'
})
.state('app.view',
{
url: 'View?param1&param2&...&paramN',
params: {
param1: {
value: null,
squash: true
},
...
}
});

AngularJS UI Router - change url without reloading state

Currently our project is using default $routeProvider, and I am using this "hack", to change url without reloading page:
services.service('$locationEx', ['$location', '$route', '$rootScope', function($location, $route, $rootScope) {
$location.skipReload = function () {
var lastRoute = $route.current;
var un = $rootScope.$on('$locationChangeSuccess', function () {
$route.current = lastRoute;
un();
});
return $location;
};
return $location;
}]);
and in controller
$locationEx.skipReload().path("/category/" + $scope.model.id).replace();
I am thinking of replacing routeProvider with ui-router for nesting routes, but cant find this in ui-router.
Is it possible - do the same with angular-ui-router?
Why do I need this?
Let me explain with an example :
Route for creating new category is /category/new
after clicking on SAVE I show success-alert and I want to change route /category/new to /caterogy/23 (23 - is id of new item stored in db)
Simply you can use $state.transitionTo instead of $state.go . $state.go calls $state.transitionTo internally but automatically sets options to { location: true, inherit: true, relative: $state.$current, notify: true } . You can call $state.transitionTo and set notify: false . For example:
$state.go('.detail', {id: newId})
can be replaced by
$state.transitionTo('.detail', {id: newId}, {
location: true,
inherit: true,
relative: $state.$current,
notify: false
})
Edit: As suggested by fracz it can simply be:
$state.go('.detail', {id: newId}, {notify: false})
Ok, solved :)
Angular UI Router has this new method, $urlRouterProvider.deferIntercept()
https://github.com/angular-ui/ui-router/issues/64
basically it comes down to this:
angular.module('myApp', [ui.router])
.config(['$urlRouterProvider', function ($urlRouterProvider) {
$urlRouterProvider.deferIntercept();
}])
// then define the interception
.run(['$rootScope', '$urlRouter', '$location', '$state', function ($rootScope, $urlRouter, $location, $state) {
$rootScope.$on('$locationChangeSuccess', function(e, newUrl, oldUrl) {
// Prevent $urlRouter's default handler from firing
e.preventDefault();
/**
* provide conditions on when to
* sync change in $location.path() with state reload.
* I use $location and $state as examples, but
* You can do any logic
* before syncing OR stop syncing all together.
*/
if ($state.current.name !== 'main.exampleState' || newUrl === 'http://some.url' || oldUrl !=='https://another.url') {
// your stuff
$urlRouter.sync();
} else {
// don't sync
}
});
// Configures $urlRouter's listener *after* your custom listener
$urlRouter.listen();
}]);
I think this method is currently only included in the master version of angular ui router, the one with optional parameters (which are nice too, btw). It needs to be cloned and built from source with
grunt build
The docs are accessible from the source as well, through
grunt ngdocs
(they get built into the /site directory) // more info in README.MD
There seems to be another way to do this, by dynamic parameters (which I haven't used).
Many credits to nateabele.
As a sidenote, here are optional parameters in Angular UI Router's $stateProvider, which I used in combination with the above:
angular.module('myApp').config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('main.doorsList', {
url: 'doors',
controller: DoorsListCtrl,
resolve: DoorsListCtrl.resolve,
templateUrl: '/modules/doors/doors-list.html'
})
.state('main.doorsSingle', {
url: 'doors/:doorsSingle/:doorsDetail',
params: {
// as of today, it was unclear how to define a required parameter (more below)
doorsSingle: {value: null},
doorsDetail: {value: null}
},
controller: DoorsSingleCtrl,
resolve: DoorsSingleCtrl.resolve,
templateUrl: '/modules/doors/doors-single.html'
});
}]);
what that does is it allows to resolve a state, even if one of the params is missing.
SEO is one purpose, readability another.
In the example above, I wanted doorsSingle to be a required parameter. It is not clear how to define those. It works ok with multiple optional parameters though, so not really a problem. The discussion is here https://github.com/angular-ui/ui-router/pull/1032#issuecomment-49196090
After spending a lot of time with this issue, Here is what I got working
$state.go('stateName',params,{
// prevent the events onStart and onSuccess from firing
notify:false,
// prevent reload of the current state
reload:false,
// replace the last record when changing the params so you don't hit the back button and get old params
location:'replace',
// inherit the current params on the url
inherit:true
});
Calling
$state.go($state.current, {myParam: newValue}, {notify: false});
will still reload the controller, meaning you will lose state data.
To avoid it, simply declare the parameter as dynamic:
$stateProvider.state({
name: 'myState',
url: '/my_state?myParam',
params: {
myParam: {
dynamic: true, // <----------
}
},
...
});
Then you don't even need the notify, just calling
$state.go($state.current, {myParam: newValue})
suffices. Neato!
From the documentation:
When dynamic is true, changes to the parameter value will
not cause the state to be entered/exited. The resolves will not be
re-fetched, nor will views be reloaded.
This can be useful to build
UI where the component updates itself when the param values change.
This setup solved following issues for me:
The training controller is not called twice when updating the url from .../ to .../123
The training controller is not getting invoked again when navigating to another state
State configuration
state('training', {
abstract: true,
url: '/training',
templateUrl: 'partials/training.html',
controller: 'TrainingController'
}).
state('training.edit', {
url: '/:trainingId'
}).
state('training.new', {
url: '/{trainingId}',
// Optional Parameter
params: {
trainingId: null
}
})
Invoking the states (from any other controller)
$scope.editTraining = function (training) {
$state.go('training.edit', { trainingId: training.id });
};
$scope.newTraining = function () {
$state.go('training.new', { });
};
Training Controller
var newTraining;
if (!!!$state.params.trainingId) {
// new
newTraining = // create new training ...
// Update the URL without reloading the controller
$state.go('training.edit',
{
trainingId : newTraining.id
},
{
location: 'replace', // update url and replace
inherit: false,
notify: false
});
} else {
// edit
// load existing training ...
}
If you need only change url but prevent change state:
Change location with (add .replace if you want to replace in history):
this.$location.path([Your path]).replace();
Prevent redirect to your state:
$transitions.onBefore({}, function($transition$) {
if ($transition$.$to().name === '[state name]') {
return false;
}
});
i did this but long ago in version: v0.2.10 of UI-router like something like this::
$stateProvider
.state(
'home', {
url: '/home',
views: {
'': {
templateUrl: Url.resolveTemplateUrl('shared/partial/main.html'),
controller: 'mainCtrl'
},
}
})
.state('home.login', {
url: '/login',
templateUrl: Url.resolveTemplateUrl('authentication/partial/login.html'),
controller: 'authenticationCtrl'
})
.state('home.logout', {
url: '/logout/:state',
controller: 'authenticationCtrl'
})
.state('home.reservationChart', {
url: '/reservations/?vw',
views: {
'': {
templateUrl: Url.resolveTemplateUrl('reservationChart/partial/reservationChartContainer.html'),
controller: 'reservationChartCtrl',
reloadOnSearch: false
},
'viewVoucher#home.reservationChart': {
templateUrl: Url.resolveTemplateUrl('voucher/partial/viewVoucherContainer.html'),
controller: 'viewVoucherCtrl',
reloadOnSearch: false
},
'addEditVoucher#home.reservationChart': {
templateUrl: Url.resolveTemplateUrl('voucher/partial/voucherContainer.html'),
controller: 'voucherCtrl',
reloadOnSearch: false
}
},
reloadOnSearch: false
})
Try something like this
$state.go($state.$current.name, {... $state.params, 'key': newValue}, {notify: false})
In Angular 2, the accepted answer from RezKesh translates to the following:
this.uiRouter.stateService.go(
"home.myRouteState",
{
"param1": this.myParam1,
"param2": this.myParam2
},
{ notify: false }
);
Assuming you have injected UIRouter into your component's constructor as follows:
constructor(
private uiRouter: UIRouter
) { }
I don't think you need ui-router at all for this. The documentation available for the $location service says in the first paragraph, "...changes to $location are reflected into the browser address bar." It continues on later to say, "What does it not do? It does not cause a full page reload when the browser URL is changed."
So, with that in mind, why not simply change the $location.path (as the method is both a getter and setter) with something like the following:
var newPath = IdFromService;
$location.path(newPath);
The documentation notes that the path should always begin with a forward slash, but this will add it if it's missing.

Resources