AngularJS: Update URL without full page load - angularjs

I'm trying to get my app working so that I can update the URL but without re-loading the whole view. I simply want to update the model and change the URL to reflect the new item being displayed.
I'm using this solution to achieve this: http://joelsaupe.com/programming/angularjs-change-path-without-reloading/
But I have a couple of issues with it:
1) The back/forward buttons on the browser no longer work - so I basically need to update the model when the URL changes and not just update the URL when the model changes..?
2) Once I've updated the URL without reloading the page, clicking on further links, such as menu options of the sort 'Books' no longer work. I can only get the navigation to work again by refreshing the page.
Does anyone have a solution to these problems? I would have expected that this sort of behaviour is common in a single page application, so it feels like I'm doing something wrong.
By the way, I'm using the angular-route module, but I'm happy to switch to angular-ui-router module if it makes life easier.
EDIT: Adding current code examples
I currently have something like this in the .config block of my main app module:
$routeProvider
.when('/books', {
title: 'Books',
templateUrl: CONFIG.static_url + '/html/books.html',
controller: 'BooksCtrl',
})
.when('/book/:itemId', {
title: 'Books',
templateUrl: CONFIG.static_url + '/html/books.html',
controller: 'BooksCtrl'
})
.otherwise({
redirectTo: '/books'
});
Then, in the run block, I have the code taken from the linked solution above:
// prevent reloading of view if reload = false
// TODO: fix issue where back button does not reload previous view
// TODO: fix issue where menu links no longer load page after
var original = $location.path;
$location.path = function (path, reload) {
if (reload === false) {
var lastRoute = $route.current,
un = $rootScope.$on('$locationChangeSuccess', function () {
$route.current = lastRoute;
});
}
return original.apply($location, [path]);
};
Finally, when I asynchronously change the model to load in a new item, I update the URL:
// update the url
$location.path('/book/'+id, false);

Related

UI-Router for Angular: Is it possible to update location without reloading the page

I am migrating an app from AngularJs to Angular 7. In the old ui-router I was able to update the location without reloading the state with below code.
this.syncLocation = function (paramObj) {
var params = _.clone($state.params);
params = _.merge(params, paramObj);
$state.transitionTo($state.current.name, params, {
location: true,
notify: false
});
};
However with new Angular & UI-Router I am unable to get this done. Not sure if it is due to Change Detection Strategy or changes to UI-Router itself.
syncLocation(paramObj) {
console.log("syncLocation", paramObj);
let params = _.clone(this.stateService.params);
params = _.merge(params, paramObj);
this.stateService.go(this.stateService.current.name, params, {
reload: false
});
}
I have created plunker to reproduce the problem. The problem is described in the component colors.component.ts link. In this plunker I don't want to reload the page even though I check/uncheck the checkbox.
The idea is that I have a complicated page where I cannot afford to lose the contents by reloading the page but still be able to update the location. It is a simplified page with the problem.
Any help is appreciated.
You can update the url with Location.replaceState()
See: replaceState()
Inject Location with di and use like this:
constructor(private location: Location) {
...
private syncLocation(){
this.location.replaceState(`whatever/state/or/path/you/need`);
}
}
There are other useful methods in Location such as Path you may want to reference.

why do I loose information when I reload an angularJS page

I have an angular/meteor app. I have a route that's a config page and when I go there and enter my configuration and navigate back to the display route, all my configurations are saved. When I refresh the page, they're gone.
service
app.service('Config', function(){
var localEquipment = [];
this.getEquipment = function(){
return localEquipment;
}
this.setEquipment = function(equipment){
localEquipment = equipment
}
})
route
$stateProvider
.state('display', {
url: '/display',
templateUrl: 'display.ng.html',
controller: 'DisplayController',
controllerAs: 'display'
})
.state('config',{
url: '/config',
templateUrl: 'config.ng.html'
});
so i go to config and setEquipment through my Config service and navigate back to display(using a link created in my app), and my localEquipment is set. as soon as I refresh the page, it's set back to []
You aren't using AngularUI Router to its fullest potential. When you start using resolve these types of problems will go away. Bottom line is that you should be resolving Equipment in both config and display states.
I ended up using local storage with an if check to see if it had already been set.

AngularJS reinitialize controller

I have got a controller named newGroupCtrl whose definition is like :
.state('new_group', {
url: '/new_group',
templateUrl: 'templates/new_group.html',
controller: 'newGroupCtrl'
})
.controller('newGroupCtrl', function ($scope, $rootScope,$ionicHistory,$window) {
$rootScope.roomId = $scope.getRoom();
$scope.getRoom = function () {
var date = new Date;
var minutes = date.getMinutes();
var hour = date.getHours();
return 'room_' + hour + '' + minutes;
};
}
I reach this contoller from previous page by :
$window.location.href = ('#/new_group');
That's good until now. $rootScope.roomId variable is initialized in the newGroupCtrl controller properly.
From this new_group page, I navigate to another page. And when I navigate back to this page by calling $window.location.href = ('#/new_group');,
$rootScope.roomId is not initialized again, instead its old value is still there. The state of the newGroupCtrl is preserved.
How can I completely reinitialize newGroupCtrl?
You need to tell state that reload controller each time when URL is getting accessed via browser by just adding adding reload option of state to true like reload: true.
Code
.state('new_group', {
url: '/new_group',
templateUrl: 'templates/new_group.html',
controller: 'newGroupCtrl',
reload: true //will reload controller when state is being access
});
You should use $state.go('new_group') instead of doing $window.location.href = ('#/new_group'); which will ensure that the route changes will recognize by ui-router.
Same SO answer here
Since you are using Ionic Framework (Good Job), you can do this:
.controller('YourCtrl', function($ionicView){
$ionicView.enter(function(){
//code that you want to run, each time the view is active
});
});
Remove the controller from :
.state('new_group', {
url: '/new_group',
templateUrl: 'templates/new_group.html',
})
And add the controller at "new_group.html" page with parent tag of the page like:
<div ng-controller="newGroupCtrl"></div>
Also I found helpful (for Ionic Framework) to use
.state('new_group', {
url: '/new_group',
templateUrl: 'templates/new_group.html',
cache: false
})
Reference to similar question and problems:
Reloading current state - refresh data or in sjm's answer in Reinitialize Controller every time when visiting View - Ionic Framework

$routeProvider does not route after selection from a dropdown array of JSON objects

My first route (after doing some tutorials) has 2 problems. I am trying to insert partials into an ng-view tag in the index.html page. First, $routeProvider sort of works, but the only line that does anything is the .otherwise() expression. Secondly, the controller code to change the page from an ng-dropdown selection changes the URL, but does not change to the new display page. I have to manually click the reload arrow to change the display.
My app config code for routing is:
residenceApp.config(['$translateProvider', '$translatePartialLoaderProvider', '$routeProvider', '$locationProvider',
function ( $translateProvider, $translatePartialLoaderProvider, $routeProvider, $locationProvider ) {
$locationProvider.html5Mode(true);
$routeProvider.when("/index", { templateUrl: "partials/home.html" });
$routeProvider.when("/partials/postApartment4Rent", { templateUrl: "partials/postApartment4Rent.html" });
$routeProvider.otherwise({ templateUrl: "partials/home.html" });
I can get to any partials page I want via the .otherwise() expression, but the others have no effect. The URL shows for partials/postApartment4Rent.html, but the display does not change. I have to manually click on the reload arrow to get the new page.
The partials pages have anchor expressions like the following. With no .html, I get 404 file not found. These act like plain anchors, with no routing going on.
Rent-link
Home
I'm using angular-dropdowns which shows a dropdown menu when its button is clicked. The user selects from the dropdown and that creates a JSON object containing the path addition to the base URL. The controller is below.
residenceApp.controller('PostButtonController', ['$translate', '$scope', 'changePostDdFactory', '$location',
function ( $translate, $scope, ddSelections, $location ){
//get the dropdown array from a factory & display it - it works
$scope.$watch('ddMenuSelected', function( newVal ) {
if (newVal && newVal.text) {
$scope.newPage = "'/" + newVal.val + "'";
alert('newPage is: ' + $scope.newPage ); //newPage is: '/postApartment4Rent'
$location.path($scope.newPage); //URL changes, but no new page unless Reload
}
}, true);
}]);
I have the following HTML5 base in the HTML head.
<base href="http://localhost/angular-oPost/app/">
My HTML for index.html also contains the following anchor just above the div for the dropdown button. Its only purpose is to be a landing spot for $routeProvider. It does not/should not display as a link.
The rest of index.html is a bunch of divs that contain either paras, inputs, or the ng-dropdowns button. I'd be glad to post some if it helps, but it seems pretty normal.
The first problem of only routing off the .otherwise() expression was solved by changing the first .when() expression to
.when("/", { templateUrl: "partials/home.html", controller: "LanguageChoiceController" } )
The second problem of showing the new URL but not loading the page when a user selects from a dropdown was solved with changes in several places. The user click on a JSON object in a dropdown array is outside the $digest cycle. Tutorials and books don't talk about this case, so it took a lot of experimenting. New code in the dropdown controller became, as follows to get the click recognized and actioned:
$scope.$watch('ddMenuSelected', function( newVal ) {
if (newVal && newVal.text) {
$scope.newPage = $timeout( function(){
//fire a click - via code from http://www.nonobtrusive.com/2011/11/29/programatically-fire-crossbrowser-click-event-with-javascript/
function fireClick(node){
if ( document.createEvent ) {
var evt = document.createEvent('MouseEvents');
evt.initEvent('click', true, false);
node.dispatchEvent(evt);
} else if( document.createEventObject ) {
node.fireEvent('onclick') ;
} else if (typeof node.onclick == 'function' ) {
node.onclick();
}
}
var theNode = document.getElementById( newVal.val );
}
fireClick(theNode);
}, 10 )
}, true); //end of $watch
I tried another 'simpler' approach with the code below, but it had no impact
$scope.newPage=function()$timeout(function(){{angular.element(document.getElementById( newVal.val )).triggerHandler('click');}, 10);};
The router code (using 1.3.2 for both angularjs and angular-route) is straightforward, as follows:
.when("/partials/postApartment4Rent", { templateUrl: "partials/postApartment4Rent.html",
controller: "LanguageChoiceController" } )
The anchor statement is below. It worked when placed either in index.html or in one of the partials html fragments. I put it in the partials/home.html fragment
This is odd because it requires "#/" even though I specified HTML5 in the router config statement. However, it would not route unless the "#/" was in the beginning of the href.
In sum, it routes, but does not get the Good Housekeeping award because some of the URLs are messy, and not HTML5. However, it gets the Arts & Crafts award because it routes, and the back and forward browser arrows work even though the browser shows odd/not HTML5 URLs.

AngularJS + Adobe CQ5 - Browser URL does not append hash path but changes the view

I am using combination of AngularJS and Adobe CQ5.
I have implemented routing to load different views. The views are loading perfectly but the URL is not appending the #/path and it shows the base path only, e.g.
localhost:7001/cf#/content/requestpage.html#/
rather than
localhost:7001/cf#/content/requestpage.html#/checkstatus.
Due to this, when I refresh the page it loads the route path (/) template instead of loading the same view again.
I am struggling to resolve this issue. Here's my controller code:
var demoapp=angular.module('demoApp',['ngRoute','ngSanitize']);
demoapp.config(function($routeProvider,$locationProvider) {
// use the HTML5 History API
//$locationProvider.html5mode(false);
$routeProvider
.when('/', {
templateUrl: '/content/index.html?wcmmode=disabled',
controller: 'myfirstcontroller'
})
.when('/checkstatus', {
templateUrl: '/content/housetemplate.html?wcmmode=disabled',
controller: 'houseController'
})
.otherwise({
redirectTo: '/'
});
});
demoapp.controller('houseController', function($scope, $routeParams,$http)
{
//code
});
demoapp.controller('myfirstcontroller', function($scope,$http,$rootScope,$location,$compile)
{
//On Form Submit
$scope.continueForm = function(isValid){
if (isValid)
{
$location.path('/checkstatus');
}
});
});
This is not an issue with CQ5. When you open a page from Siteadmin, by default your page is loaded within contentfinder (/cf#).
Now, contentfinder already has your page URL as the hashvalue. Hence you find that the URL doesn't get updated even though your angular views work correctly.
Try accessing the same page without contentfinder. i.e.,
http://localhost:7001/content/requestpage.html
instead of
http://localhost:7001/cf#/content/requestpage.html
You should find things working as expected.

Resources