I stored contextual menus in the array, and i doing the action using callback function. Need to clear the array when routes getting changed.
So it depends if you are using ui-router or ng-router.
In essence you want to bind to the route change event, and these events named differently depending on the router you are using.
For ui-router you could do something like this:
$scope.$on('$stateChangeStart', function() {
$scope.contextMenu.splice(0, $scope.contextMenu.length);
});
Related
How to detect unsaved page changes check while moving another page or tab in angularjs 1.5 application.
One of approach is using directives however how to pass related form named to the directive instead of using hard coded solution?
I tried using the service approach as mentioned below but my nested view controller is not able to access the form name. Iam getting $scope.myForm as undefined.
You can handle page change with the event $locationChangeStart for ng-route or $stateChangeStart for ui-router (perform the logic you want inside):
$scope.$on('$locationChangeStart', function(event) {
if ($scope.myForm.$invalid) {
event.preventDefault();
}
});
To tab change etc, you can disable your tab with something like or watever approach you prefer
ng-disabled="!myForm.$valid"
EDIT
You may look at this post to use a service/factory approach :
https://stackoverflow.com/a/25459689/5138917
The module below seem to work for me
https://github.com/facultymatt/angular-unsavedChanges
Consider a certain route let's say myapp\profile
which has two modes (buyer/seller)
What i would like to achieve is:
keep the same route url for both modes
Alternate the view with different HTML files (lets say buyer.html, seller.html), of course each view has it's view model.
Sharing some logic between the two modes.
I would like to have a controller/logic to each mode
What i already considered:
Thought about using ui-router's sub states, but I dont want to change the url.
Thought about creating this 'profile' route and while navigating to it, figure the mode (buyer/seller), and then $state.go to a new state (but again, i would like to keep same route name at the end so it's not ok)
Ideally thought i could navigate to my shared controller and then render the correct view and controller, but this idea kinda messed up me.
Could you share what is a clean way of doing this?
most use cases
Normally, in order to dynamically select a template for a state, you can use a function:
state = {
.....
templateUrl: function($stateParams){
if ($stateParams.isThis === true)
return 'this.html'
else
return 'that.html'
}
}
but...
Unfortunately you can't pass other injectables to the templateUrl function. UI.Router only passes $stateParams. You don't want to alter the URL in anyway so you can't use this.
when you need to inject more than $stateParams
But you can leverage templateProvider instead. With this feature, you can pass a service to your templateProvider function to determine if your user is a buyer or seller. You'll also want to use UI.Router's $templateFactory service to easily pull and cache your template.
state = {
....
templateProvider: function($templateFactory, profileService){
var url = profileService.isBuyer ? 'buyer.html' : 'seller.html';
return $templateFactory.fromUrl(url);
}
}
Here it is working in your plunkr - http://plnkr.co/edit/0gLBJlQrNPUNtkqWNrZm?p=preview
Docs:
https://github.com/angular-ui/ui-router/wiki#templates
http://angular-ui.github.io/ui-router/site/#/api/ui.router.util.$templateFactory
guys I am working on an angular js app which uses ui-router for deep linking and routing. I want to set up a variable on the $rootScope every time a state is visited/changed. I am able to accomplish that on subsequent state transitions via listening to $stateChangeSuccess but since the app is deep linked, I want to set the same variable when a state is directly hit from the address bar.
When I hit a specific URL from address bar e.g. Home/Summary/Change, $stateChangeSuccess doesn't fire hence I am not able to set the value.
Any suggestions on how I can listen to EACH state visit on my $rootScope.
You may use combination of $locationChangeStart and $route.current:
$rootScope.$on('$locationChangeStart', function (event, next, current) {
if(!$route.current) {
$rootScope.myVar = ...
}
});
I found a work around for this. I was not able to get $stateChangeSuccess on the first visit to a page so on initialization i called the function explicitly.
example code
var handle = function(){
//do something ...
}
$scope.$on('$stateChangeSuccess', handle); // call handle on each state change
handle(); // will only be called on initialization
might not be the cleanest way but it works
In the meantime they have implemented a $urlRouterProvider where you can add a when:
app.config(function($urlRouterProvider){
// when there is an empty route, redirect to /index
$urlRouterProvider.when('', '/index');
// You can also use regex for the match parameter
$urlRouterProvider.when(/aspx/i, '/index');
})
So if you like to have Home/Summary/Change matching a state, you would write something like $urlRouterProvider.when('Home/Summary/Change','myhomestate') then the $stateChangeSuccess should fire correct.
For more details about that provider look at https://github.com/angular-ui/ui-router/wiki/URL-Routing#urlrouterprovider
I'm building a dashboard system in AngularJS and I'm running into an issue with setting the url via $location.path
In our dashboard, we have a bunch of widgets. Each shows a larger maximized view when you click on it. We are trying to setup deep linking to allow users to link to a dashboard with a widget maximized.
Currently, we have 2 routes that look like /dashboard/:dashboardId and /dashboard/:dashboardId/:maximizedWidgetId
When a user maximizes a widget, we update the url using $location.path, but this is causing the view to re-render. Since we have all of the data, we don't want to reload the whole view, we just want to update the URL. Is there a way to set the url without causing the view to re-render?
HTML5Mode is set to true.
In fact, a view will be rendered everytime you change a url. Thats how $routeProvider works in Angular but you can pass maximizeWidgetId as a querystring which does not re-render a view.
App.config(function($routeProvider) {
$routeProvider.when('/dashboard/:dashboardId', {reloadOnSearch: false});
});
When you click a widget to maximize:
Maximum This Widget
or
$location.search('maximizeWidgetId', 1);
The URL in addressbar would change to http://app.com/dashboard/1?maximizeWidgetId=1
You can even watch when search changes in the URL (from one widget to another)
$scope.$on('$routeUpdate', function(scope, next, current) {
// Minimize the current widget and maximize the new one
});
You can set the reloadOnSearch property of $routeProvider to false.
Possible duplicate question : Can you change a path without reloading the controller in AngularJS?
Regards
For those who need change full path() without controllers reload
Here is plugin: https://github.com/anglibs/angular-location-update
Usage:
$location.update_path('/notes/1');
I realize this is an old question, but since it took me a good day and a half to find the answer, so here goes.
You do not need to convert your path into query strings if you use angular-ui-router.
Currently, due to what may be considered as a bug, setting reloadOnSearch: false on a state will result in being able to change the route without reloading the view. The GitHub user lmessinger was even kind enough to provide a demo of it. You can find the link from his comment linked above.
Basically all you need to do is:
Use ui-router instead of ngRoute
In your states, declare the ones you wish with reloadOnSearch: false
In my app, I have an category listing view, from which you can get to another category using a state like this:
$stateProvider.state('articles.list', {
url: '{categorySlug}',
templateUrl: 'partials/article-list.html',
controller: 'ArticleListCtrl',
reloadOnSearch: false
});
That's it. Hope this helps!
We're using Angular UI Router instead of built-in routes for a similar scenario. It doesn't seem to re-instantiate the controller and re-render the entire view.
How I've implemented it:
(my solution mostly for cases when you need to change whole route, not sub-parts)
I have page with menu (menuPage) and data should not be cleaned on navigation (there is a lot of inputs on each page and user will be very very unhappy if data will disappear accidentally).
turn off $routeProvider
in mainPage controller add two divs with custom directive attribute - each directive contains only 'templateUrl' and 'scope: true'
<div ng-show="tab=='tab_name'" data-tab_name-page></div>
mainPage controller contains lines to simulate routing:
if (!$scope.tab && $location.path()) {
$scope.tab = $location.path().substr(1);
}
$scope.setTab = function(tab) {
$scope.tab = tab;
$location.path('/'+tab);
};
That's all. Little bit ugly to have separate directive for each page, but usage of dynamic templateUrl (as function) in directive provokes re-rendering of page (and loosing data of inputs).
If I understood your question right, you want to,
Maximize the widget when the user is on /dashboard/:dashboardId and he maximizes the widget.
You want the user to have the ability to come back to /dashboard/:dashboardId/:maximizedWidgetId and still see the widget maximized.
You can configure only the first route in the routerConfig and use RouteParams to identify if the maximized widget is passed in the params in the controller of this configured route and maximize the one passed as the param. If the user is maximizing it the first time, share the url to this maximized view with the maximizedWidgetId on the UI.
As long as you use $location(which is just a wrapper over native location object) to update the path it will refresh the view.
I have an idea to use
window.history.replaceState('Object', 'Title', '/new-url');
If you do this and a digest cycle happens it will completely mangle things up. However if you set it back to the correct url that angular expects it's ok. So in theory you could store the correct url that angular expects and reset it just before you know a digest fires.
I've not tested this though.
Below code will let you change url without redirection such as: http://localhost/#/691?foo?bar?blabla
for(var i=0;i<=1000;i++) $routeProvider.when('/'+i, {templateUrl: "tabPages/"+i+".html",reloadOnSearch: false});
But when you change to http://localhost/#/692, you will be redirected.
I want to use routes, but I always want to use same template & controller. I have routes like this:
**a/:albumid**
and
**i/:imageid**
In the first case I want to load an array of images and add them to a list. In the second case I want to load a single image and add it to a list.
So the difference is only in data loading. What is the most efficient way to do this?
Also is it possible to animate ng-show? Something like jQuery's slideDown?
Check out this article, it describes a way to do exactly what you want:
http://www.bennadel.com/blog/2420-Mapping-AngularJS-Routes-Onto-URL-Parameters-And-Client-Side-Events.htm
I've used the technique, it works well.
In a nutshell, something like this for routing:
$routeProvider
.when("/a/:album_id", {
action: "album.list"
}).when("/i/:imgid", {
action: "images.load"
})
Then in your controller you can access $route.current.action and do the appropriate thing. The trick is to create a function in you controller that does all the work (the article calls it render()) and then call that function when $routeChangeSuccess fires:
$scope.$on(
"$routeChangeSuccess",
function( $currentRoute, $previousRoute ){
// Update the rendering.
render();
}
);
I created a super simple directive to handle this that allows routes to be have more like Rails or Codeigniter routes where the controller method is in the route definition. The method name is set in the routeProvider.when options and the directive is set in the template for the route.
See: https://stackoverflow.com/a/22714634/250991