Angular change URL on page load - angularjs

I'm creating a schedule for a convention and would like to have the URL change during the convention time. If the user loads the page on Saturday of the con, the URL should change to [URL]?day=saturday.(The URL will also change when the user clicks to view different day)
I'm running into an issue on page load only, where the history.replaceState is causing
angular.js:13920 Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
So I came across a forum that says to use something like
$location.path('/').search('day='+day).replace();
But it comes out as
/#/?day=saturday
I don't want the /# in the URL. So I found forums explaining to use $locationProvider.
I even added in the
app.config(function($locationProvider) {
$locationProvider.html5Mode(true);
})
And it still says $locationProvider is not defined. I don't know what I'm doing wrong or if this is even the right direction to be going in. I just want to change the ?day=day_here when the page loads and when the user clicks to change the day.

Capture the route change on click when routing and replace the url. For the error use and your syntax seems to be right
.config(function($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
})
But if you want to persist the url change you will have to do the changes to url in the routeChange
.run(function($rootScope, $location) {
$rootScope.$on('$routeChangeStart', function(next, current) {
//... you could trigger something here like replacing the actual url ...
//$location.path('/').search('day='+day).replace();
});
})
Alternatively you can also look at https://github.com/angular-ui/ui-router as an alternative and do the changes to $location.url().replace() in onEnter or resolve options of state definition https://github.com/angular-ui/ui-router/wiki
If you want to use ngRouter and still getting the error a plunkr code for demo will surely help debug better.

Related

Get the url that a user is coming from AngularJS

If an user is coming from an specific page i need to do get some values out of a cookie and change what the users sees.
Now, the issue is that i cannot find a way to view what page the user is coming from.
EDIT: This is intended to capture when the users clicks back in a page and save the state of the previous page.
Any ideas?
Thanks in advance
Solved. Every time i load a page i'm saving the url, so when i get to this page i just have to read it to tell. Thanks!
You can use browser history in our javascript or you can write your last page in cookies and get the last link then update it
Using cookies will indeed fix this for you. So when a user goes to a new page - set a cookie like:
app.controller('myController',['$scope', '$location', $cookies], function($scope, $location, $cookies){
if($cookies.get('page') == '/index'){
//do stuff if user came from index
}
$scope.pageChanged = function(value){
$cookies.put('page', value);
$location.path('/index');
}
}
just make sure you use the pageChanged function to set your page every time user changes pages.
Using the $routeProvider you can use the resolve function to detect when a new route has been loaded.
Another way would be to listen for the event $routeChangeSuccessor $routeChangeError and get the information needed from the service $location or $route.
If you want a sample just ask me, I'll try to post one as soon as I have free time.

Code changes not taking effect until refresh/reload is clicked

Any time I make changes to the code in my angularjs site, they do take effect until the user clicks the refresh button. Even if I log out to a page that is not angular then log back in it is the same old code until I click the refresh button. So if someone logs in it is the same as the last time they logged in regardless of changes and I obviously can't expect them to click refresh every time they log in.
So my question is how could I force a refresh of the code. I don't want to use window.reload or anything like that if there is a speacial angular way to accomplish this. I have tried clearing the template cache but it doesn't work. This is what I tried:
.run(function($rootScope, $templateCache) {
$templateCache.removeAll();
$rootScope.$on('$routeChangeStart', function(event, next, current) {
if (typeof(current) !== 'undefined'){
$templateCache.remove(current.templateUrl);
}
});
})
My problem turn out to be the browser caching js files. I didn't think that would be the problem because prior to using angularjs I never had this problem. So to fix the issue I found this: How to force browser to reload cached CSS/JS files? and modified it a little so I didnt have to use all the url rewriting.
I added the php function
function get_version($file){
return filemtime($_SERVER['DOCUMENT_ROOT'] . $file);
}
Then where I link my scripts I use:
<script src="/path/to/script.js?<?php echo get_version('/path/to/script.js');?>"></script>

Updating URL in Angular JS without re-rendering view

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.

Angularjs - using $routing - when I manually put "#/section/ + myId" , it resets my page

So I am trying to implement routing in my app. Here is a sample jsFiddle of what I am trying to do: http://jsfiddle.net/GeorgiAngelov/9yN3Z/114/
So far everything is working fine and as I am moving through the sections, my routing changes and everything is fine.
The problem is the following: when I manually type the section id in my url bar like this my local host : /section/s-3 I get redirected to s-1 and my page refreshes and I loose all of the sections and roots I have added so far. Sometimes it works, and I can switch between sections like that, but sometimes it refreshes, and it happens when I click enter twice.
It's an odd problem and I am not certain on how can I debug it. This is my actuall routing service.
app.config(function ($routeProvider) {
$routeProvider
.when('/', {
redirectTo: '/section/1',
templateUrl: '/tpl.html',
})
.when('/section/:sectionId', {
templateUrl: '/tpl.html',
})
.otherwise({
redirectTo: '/'
});
});
I tested your app on chrome and on firefox. Using chrome, if you select the url and type enter (without changing it) it reloads the page, so hitting enter twice will always refresh the page. Using firefox, this does not happen, so apparently you don't have this problem on FF (although the user can press the refresh button directly).
If you refresh the page, you obviously lose what you have inserted. You need to persist the information you want to preserve between refreshes. If you don't want to send this to your server, an alternative is to use html5 local storage. You can see an example here:
http://todomvc.com/architecture-examples/angularjs/#/
I'we watched your application and from my point of view you're using an odd way to add DOM object to your view, kinda like jquery templating.
Actually each times you click inside a section you're using a different scope and adding a root in a scope it's not visible to the others: instead you should use a service shared between the controllers, this way only the service contains all the sections and all the roots: angularjs services
Later I'will update your jsfiddle, hope this helps for now.

AngularJS Paging with $location.path but no ngView reload

My single page application loads a home page and I want to display a series of ideas. Each of the ideas is displayed in an animated flash container, with animations displayed to cycle between the ideas.
Ideas are loaded using $http:
$scope.flash = new FlashInterface scope:$scope,location:$location
$http.get("/competition.json")
.success (data) ->
$scope.flash._init data
However, to benefit from history navigation and UX I wish to update the address bar to display the correct url for each idea using $location:
$location.path "/i/#{idea.code}"
$scope.$apply()
I am calling $apply here because this event comes from outwith the AngularJS context ie Flash. I would like for the current controller/view to remain and for the view to not reload. This is very bad because reloading the view results in the whole flash object being thrown away and the preloader cycle beginning again.
I've tried listening for $routeChangeStart to do a preventDefault:
$scope.$on "$routeChangeStart", (ev,next,current) ->
ev.preventDefault()
$scope.$on "$routeChangeSuccess", (ev,current) ->
ev.preventDefault()
but to no avail. The whole thing would be hunky dory if I could figure out a way of overriding the view reload when I change the $location.path.
I'm still very much feeling my way around AngularJS so I'd be glad of any pointers on how to structure the app to achieve my goal!
Instead of updating the path, just update query param with a page number.
set your route to ignore query param changes:
....
$routeProvider.when('/foo', {..., reloadOnSearch: false})
....
and in your app update $location with:
...
$location.search('page', pageNumber);
...
From this blog post:
by default all location changes go through the routing process, which
updates the angular view.
There’s a simple way to short-circuit this, however. Angular watches
for a location change (whether it’s accomplished through typing in the
location bar, clicking a link or setting the location through
$location.path()). When it senses this change, it broadcasts an
event, $locationChangeSuccess, and begins the routing process. What
we do is capture the event and reset the route to what it was
previously.
function MyCtrl($route, $scope) {
var lastRoute = $route.current;
$scope.$on('$locationChangeSuccess', function(event) {
$route.current = lastRoute;
});
}
My solution was to use the $routeChangeStart because that gives you the "next" and "last" routes, you can compare them without the need of an extra variable like on $locationChangeSuccess.
The benefit is being able to access the "params" property on both "next" and "last" routes like next.params.yourproperty when you are using the "/property/value" URL style and of course use $location.url or $location.path to change the URL instead of $location.search() that depends on "?property=value" URL style.
In my case I used it not only for that but also to prevent the route to change is the controller did not change:
$scope.$on('$routeChangeStart',function(e,next,last){
if(next.$$route.controller === last.$$route.controller){
e.preventDefault();
$route.current = last.$$route;
//do whatever you want in here!
}
});
Personally I feel like AngularJS should provide a way to control it, right now they assume that whenever you change the browser's location you want to change the route.
You should be loading $location via Dependency Injection and using the following:
$scope.apply(function () {
$location.path("yourPath");
}
Keep in mind that you should not use hashtags(#) while using $location.path. This is for compability for HTML5 mode.
The $locationChangeSuccess event is a bit of a brute force approach, but I found that checking the path allows us to avoid page reloads when the route path template is unchanged, but reloads the page when switching to a different route template:
var lastRoute = $route.current;
$scope.$on('$locationChangeSuccess', function (event) {
if (lastRoute.$$route.originalPath === $route.current.$$route.originalPath) {
$route.current = lastRoute;
}
});
Adding that code to a particular controller makes the reloading more intelligent.
Edit: While this makes it a bit easier, I ultimately didn't like the complexity of the code I was writing to keep friendly looking URL's. In the end, I just switched to a search parameter and angular handles it much better.
I needed to do this but after fussing around trying to get the $locationChange~ events to get it to work I learned that you can actually do this on the route using resolve.
$routeProvider.when(
'/page',
{
templateUrl : 'partial.html',
controller : 'PageCtrl',
resolve : {
load : ['$q', function($q) {
var defer = $q.defer();
if (/*you only changed the idea thingo*/)
//dont reload the view
defer.reject('');
//otherwise, load the view
else
defer.resolve();
return defer.promise;
}]
}
}
);
With AngularJS V1.7.1, $route adds support for the reloadOnUrl configuration option.
If route /foo/:id has reloadOnUrl = false set, then moving from /foo/id1 to /foo/id2 only broadcasts a $routeUpdate event, and does not reload the view and re-instantiate the controller.

Resources