$location.path causes a full page refresh - angularjs

I have a page with a link. If the user clicks on the link a popup will display, using ng-show. This is the ng-click:
<div class="adItem" ng-click="showArticleMethod(tiki._id, tiki.tikiTitle)" ng-repeat="tiki in tikis track by tiki._id">
On click a showArticleMethod gets called in the controller:
$scope.showArticleMethod = function(tikiID, article){
var title = $filter("underscoreString")(article)
$location.path(tikiID + "/" + title)
$scope.showArticle = tikiID
}
The method also changes the url to: index.html#/1/title using $location.url().
Since i want people to be able to directly link to the article i have set up this route:
$routProvider.when("/", {
templateUrl: "partials/promise.html",
controller:"tiki.controllers.promise",
reloadOnSearch:false
}).when("/:id/:title/", {
templateUrl:"partials/promise.html",
controller:"tiki.controllers.promise",
reloadOnSearch:false
}
Everything works fine except the animation (opacity:0 to opacity:1) that is set on the popup does not work.
My guess is that the url is not just changed but also reloaded so i tried adding 'reloadOnSearch:false' but that doesn't have any effect.
How can i change the url without reloading the url and keeping the css animation?
This is my full controller:
/* Controllers */
angular.module('tiki.controllers').controller("tiki.controllers.promise", ["$scope", "tikiDB", "$routeParams", "$filter", "$location", function($scope, tikiDB, $routeParams, $filter, $location){
$scope.tikis = tikiDB.query()
$scope.location = ""
$scope.showArticleMethod = function(tikiID, article){
var title = $filter("underscoreString")(article)
$location.path(tikiID + "/" + title)
$scope.showArticle = tikiID
}
$scope.hideArticleMethod = function(){
$location.path("")
$scope.showArticle = false
}
if($routeParams){
$scope.showArticle = parseInt($routeParams.id);
}
}])
The variable 'showArticle' is set to 'false' if no article is shown. It is set to the article ID if an article has to be shown. The article is shown in a popup that is activated using a class that is added to the <body> tag.
<body ng-class="{'bodyShowArticle': showArticle}" ng-view="">
If i add a $timeout then the animation works again but does a full page refresh after the timeout:
$timeout(function(){
$location.path(tikiID + "/" + title)
}, 1000)

Related

Updating HTML in Angular is not working

I am still learning angular and in my example projekt I have a problem on updating the view.
Got this in my header ....
<meta charset="UTF-8">
<title>{{ name }}</title>
And this in my body:
<body ng-controller="BodyController as body">
<input type="button" ng-click="changeTitle()" name="changeNameButton" value="change name"/>
This is my head controller:
myApp.controller('HeadController',
['$scope', 'ApplicationService', 'DataService', 'UserService', function ($scope, ApplicationService, DataService, UserService) {
var self = this;
$scope.name = ApplicationService.getTitle();
}]
);
And here is my body controller:
myApp.controller('BodyController', ['$scope', 'ApplicationService', function ($scope, ApplicationService) {
$scope.text = 'Hello, Angular fanatic.';
$scope.changeTitle = function () {
console.log('change the title');
ApplicationService.setTitle('test');
}
}]);
This is my application service
myApp.service('ApplicationService', ['ConfigurationService', function(ConfigurationService){
this.title = '';
this.setTitle = function (newTitle) {
console.log('new title (setter): ' + this.title);
this.title = newTitle
}
this.getTitle = function () {
if(this.title==''){
this.title = ConfigurationService.title + ' | ' + ConfigurationService.subtitle;
}
console.log('new title (getter): ' + this.title);
return this.title;
}
}]);
So far so good and sorry that I do not use codepen, etc. But it was not working in it, ...
My Problem: It is setting the title on initial load of the website, but not on pressing the button. The new name is set to ApplicationService.title, but header controller does not update it. Whats is wrong in this case? How can I update the title in the view...?
Regards
n00n
see the codepen for it: https://codepen.io/n00n/pen/bqaGKY
What you're doing is the equivalent of the following simple code:
//in the header controller
var name = service.getTitle();
// in the header template
display(name);
// later, in the body
service.setTitle('test');
// in the header template
display(name);
You see that this can't work: the variable name in the header controller has been initialized when the controller was created, and assigning a new value to the title stored in the service can't magically change the value of the name variable in the header controller. What you want is to display the title in the service:
<title>{{ getTitle() }}</title>
$scope.getTitle = function() {
return ApplicationService.getTitle();
};
That didn't work because you're calling getTitle method when title wasn't set. So that's it is referring to older title('undefined'). You can change your binding to
$scope.getTitle = ApplicationService.getTitle;
And then change HTML to
{{getTitle()}}
So title will get fetch from service and updated on the page on each digest cycle.
Other thing which I'd like to mention is, don't use(mix) $scope when you are using controllerAs, so then remove $scope from controller and bind data to below
var vm = this;
vm.getTitle = ApplicationService.getTitle;

angularjs templates not hiding div from route

It's two page user registeration process depending on the role the second page could be different but the first page will always remain the same. what I want I that user can go forward and backwards on both screens with persistent data. I trying a static page at start and then hide it and add the second template from route.
This is my angular app controller.
app.controller('addlandlordController' , function($scope , $http , $route ,API_URL , $routeParams , uploadService ){
$scope.API_URL = API_URL;
$scope.landVisible = true;
$scope.IsVisible = true;
if( $routeParams.test)
{
scope.$apply(function () {
$scope.IsVisible = false;
});
alert( $routeParams.test);
}
$scope.adduser = function($route){
var data = $.param({
fName: $scope.firstName,
lName: $scope.lastName,
role: 'landlord',
email: $scope.email,
linkId: $scope.linkId,
password: $scope.password,
});
var config = {
headers : {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
}
}
$http.post(API_URL + 'user' , data , config)
.then(
function(response){
//$scope.IsVisible = false;
//alert('success');
},
function(response){
// failure callback
alert('fail');
}
);
}
});
I have a div in html like this,.
<div id="content" class="container1" ng-controller='addlandlordController' >
<div ng-show = "IsVisible">
And following is my route in config,.
app.config(function($routeProvider){
$routeProvider.when('/landlord' , {
templateUrl : 'template/addlandlord.html',
controller : 'addlandlordController',
resolve: {
test: function ($route) { $route.current.params.test = true; }
}
})
});
What I want is that when the user click on the following button.
Create an Account</button>
On click that button #/landlord will be added to the url and the route config code will run and add the other template in ng-view which is happening. Now next step is to hide the old div above in such a way that when user go back one sten only the previous code should show and when user goes again into the next screen only the next template should be visible and mean while data should remain same for the both views.
Issues I am facing is
Css is for template view is missing although the css files are already in the commen header. But appears when a place css in the style within template.
if I hide the first div in the response of adduser then if user go back it still hidden. it doesn't appears unless I refresh the page.
But if went to hide it through route config the value turn false but div never hides.
Please check this
scope.$apply(function () {
$scope.IsVisible = false;
});
You are using $apply on scope, but not in $scope.
And $applyAsync is preferable method to trigger digest without risking of error "$digest already in progress"
$applyAsync example:
$element.on('click', ()=>{
$scope.model.testValue = 'I have been updated not from angular circle';
$scope.$applyAsync();
});
Link to the docs
Nice article to read

Having trouble making page change work when set from url

I'm building an app using AngularJS and OData Controller. I created the pagination using Angular-ui.
<div class="table" ng-controller="MyCtrl as ctrl">
<!-- bunch of data to be shown here - The table stuff -->
<uib-pagination class="pagination"
total-items="ctrl.totalItems"
items-per-page="10"
max-size="10"
rotate="false"
boundary-links="true"
ng-model="ctrl.currentPage"
ng-change="ctrl.pageChanged(ctrl.currentPage)">
</uib-pagination>
</div>
This works perfect. What happened was when user goes to the next page, select a table for detail view, then click 'Done' or 'Cancel' or whatever button to get out of the detail view to the table view, the view is set back to first page instead of taking them back to whatever page they were before.
So, what I ended up doing, is creating a state using ui-router.
Here's the ui-router state
.state('Claims', {
url: '/Claims?page',
templateUrl: baseUrl + 'Scripts/App/Views/Template/denied/denied-claims-table.html',
params: {
page: {
value: '0',
squash: true
}
}
})
.state('Detail', {
url: '/Claims?page&id/detail',
templateUrl: baseUrl + 'Scripts/App/Views/Template/denied/denied-claims-details-panel.html',
params: {
page: {
value: '0',
squash: true
},
id: {
value: '0',
squash: true
}
}
})
And here's my controller:
deniedClaimsApp.controller('DeniedClaimsController', [
'$scope',
'$state',
'$stateParams',
'DeniedClaimsService',
'SharedDataService',
function ($scope, $state, $stateParams, DeniedClaimsService, SharedDataService) {
var vm = this;
var claimBK = {};
vm.claims = {};
vm.totalItems;
vm.numPages = 10;
vm.currentPage = parseInt($stateParams.page, 10) || 1;
console.log('Current Page: ' + $stateParams.page);
activate();
SharedDataService.registerObserver(activate);
function activate() {
$scope.$emit('LOAD');
vm.isCollapsed = true;
console.log("Page set to : " + vm.currentPage);
//vm.currentPage = DeniedClaimsService.getCurrentPage();
vm.currentPage = $stateParams.page;
vm.claims = DeniedClaimsService.getClaims(vm.currentPage);
angular.copy(vm.claims, claimBK);
resolve();
$state.go('.', { page: vm.currentPage }, { notify: false });
}
function resolve() {
vm.currentPage = $stateParams.page; //adding this didn't help either
console.log("Resolve: " + vm.currentPage);
vm.claims.$promise.then(function (data) {
vm.totalItems = data.count;
$scope.$emit('UNLOAD');
});
}
vm.pageChanged = function (page) {
/*
This is where page is always 1. For some reason, when the page number is changed from the url, it raises the page change event, but the ng-model in uib-pagination doesn't change to the page set in the url. It always stays 1 and changes the page back to the first page
*/
$scope.$emit('LOAD');
//vm.currentPage = $stateParams.page;
console.log("New page: " + vm.currentPage);
console.log('changing page');
vm.claims = DeniedClaimsService.pageChanged(vm.currentPage);
vm.claims.$promise.then(function (data) {
$scope.$emit('UNLOAD');
});
console.log("Changing State to: " + vm.currentPage);
$state.go('.', { page: vm.currentPage }, { notify: false });
console.log("Changing pagination: " + vm.currentPage);
//vm.currentPage = $stateParams.page;
}
So, the controller is only there to change the page, and a couple other things that is not shown here for brevity. When I change the page using the 'Next' or 'Prev' buttons, the page changes fine. But when I change the page from the url and obtain the page from $stateParams.page, it changes the page back to first page no matter which page I was in. I thought it had something to do with the page change event raised when using ng-change. So, I changed uib-pagination ng-change to ng-click="ctrl.pageChanged(ctrl.currentPage). Doing this did change the page when the page number is set in the url as /Claims?page=5then it'd take me to page 5, but it didn't change the ng-model in uib-pagination. That remained 1 even though the table is displaying data for page 5. So, after changing to page 5 from the url, and if I change the page by clicking 'Next', it would take me to page 2 instead of page 6. What am I doing wrong? Why is that model not changing with the change in value for the same model?

implementing external links to a page with angular-scroll and ng-route

So this is is an angularjs app.
I have implemented this angular-scroll api :https://github.com/oblador/angular-scroll, to show a catalog of products, where the content is loaded from db. this catalog has all the subcategories (with its products) and every subcategory has an anchor identified like: anchor+categoryId.
So from the menu , i click a category and it scroll nicely to the correct section.
The problem arise when I need to create some links from other pages of the site, to go to an specific section category inside the catalog. Because I have ng-route, i need to create a new url to redirect to the catalog, and there capture when the content is loaded to do the scroll to the required category.
BUT I have a directive associated with the route of the catalog, that looks for the partials depending on the domain of the client, so to show the correct template i have to use an $http , get the content and replace it in my directive.
Because that I dont know how i can know when the content of the directive is ready to make the call to the scroll... better show some code here :
this is the route that is receiving the call
$routeProvider.
when('/products/category/:categoryId/page/:page/anchor/:anchorId?', {
template:'<product-display-view></product-display-view>',
controller: 'ProductListCtrl',
access: {
authorizedRoles: [USER_ROLES.all]
},
resolve: {
wait : 'waitForIt',
prefetchDataProducts: ['waitForIt','$route','SearchService',
function(waitForIt,$route,SearchService) {
return waitForIt.then(function() {
return SearchService.getProducts($route.current.params.categoryId,$route.current.params.page);
});
}],
prefetchDataCategories:['waitForIt','CategoryService',
function(waitForIt,CategoryService) {
return waitForIt.then(function() {
return CategoryService.getCategories();
});
}]
}
}).
this is the directive product-display
productDirectives.directive('productDisplayView',['$rootScope','$compile','$http','$templateCache' ,'$document',
function($rootScope,$compile, $http, $templateCache,$document){
return {
restrict: 'E',
link: function (scope, element, attrs) {
var templateUrl = 'users/catwizardAngularCore/app/partials/themes/' + scope.app.theme.themeName + '/partials/product-display.html';
$http.get(templateUrl, {cache: $templateCache})
.success(function (templateContent) {
element.replaceWith($compile(templateContent)(scope));
});
/* this doesn't work because the someElement doesn't exist*/
var newHash = 'anchor' + scope.anchorId;
var someElement = angular.element(document.getElementById(newHash));
angular.element(someElement).ready(function () {
$document.scrollToElement(someElement, 200, 2000);
});
}
}]);
There is a duplicate question with the correct answer, but it has not been accepted yet so I am copying the answer here.
The $anchorScroll has to occur after the page has been rendered,
otherwise the anchor doesn't exist. This can be achieved using
$timeout().
$timeout(function() {
$anchorScroll('myAnchor');
});
Credits to Tony

Angular: how to call a function after changing state

I am building a small message system. I use tabs in my state (inbox, outbox). Also, i want to sent a message when i click a "contact" link. If i click that link, this should happen:
change state to messages state
open other tab, called "newmsg"
At this moment, this is what i have:
<a ng-click="mailContact()">contact</a>
and i my controller:
$scope.mailContact = function() {
$state.go('root.messages');
$scope.openTab('new');
};
Obviously this is not working, because $scope.openTab('new'); will never execute. The state changes to what i want, but the tab is not opened. I do not have a clue of how to get it done.
Ok, stupid thing was i had an init which opened the "inbox"...
Now i wrote a service which does the trick.
app.factory('msgTabService', ['$rootScope', function($rootScope) {
var msgTabService = {};
var tabname = "inbox";
msgTabService.set = function(tab) {
tabname = tab;
};
msgTabService.get = function() {
return tabname;
};
msgTabService.openTab = function(tab) {
if ($rootScope.currenttab !== tab)
{
$rootScope.currenttab = tab;
msgTabService.set(tab);
}
};
return msgTabService;
}]);
The question may be similar to: Save State of Tab content when changing Route with angularjs and BootStrap Tabs

Resources