angular ng-if keeps refreshing page - angularjs

I have the following divs setup where I switch between a loading div and an angular view. Only the loading div should show up when globalCtx.viewportLoading == true, and only the ng-view should show up when globalCtx.viewportLoading == false:
<div id="viewContainer">
<div class="loader" ng-if="globalCtx.viewportLoading"></div>
<div ng-view ng-if="!globalCtx.viewportLoading"></div>
</div>
The variable globalCtx is defined in an angular service like so:
app.factory("globalCtx", function () {
var service = {
viewportLoading: false
};
return service;
});
On every route, I have a different view and a different angular controller. For each of these views, I show the loading div until the page loads like so:
Generate Request
var req = {
method: 'POST',
url: 'api/v1/work/do-something',
data: request,
headers: {
'Content-Type': "application/json; charset=utf-8"
}
}
Set Loading to True
globalCtx.viewportLoading = true
Make Request, and set viewportLoading to false on reply
$http(req).then(function (resp) {
// ... do something ...
globalCtx.viewportLoading = false
},
function (resp) {
alert('Error fetching data from server!');
});
This works for the first page I run on. Say, the home page. But any page I route to after that, it just keeps refreshing that page. Say, I Go to the home page. It makes one request for data. I then route to page1, and I notice the angular controller for page1 keeps refreshing and is being created over and over again. Why is this? Does it have to do with ng-if?

Please use this code for loading your view
globalCtx.viewportLoading = false;
$scope.$on('$viewContentLoaded', function(){
globalCtx.viewportLoading = true;
});

Related

AngularJS Include Refresh

I have a html page which I am including as follows.
<ng-include src="lowerTabURL"></ng-include>
This page contains a devextreme control which loads a datasource via ajax.
html:
<div class="tab-container" style="height:100%; width:100%">
<div dx-tabs="lowerTabOptions" dx-item-alias="lowerTab">
</div>
</div>
controller:
DemoApp.controller('NavigationController', function DemoController($scope, $templateCache) {
$scope.lowerTabURL = "LowerPanelTest";
$scope.currentSidebarId = 10100;
$scope.lowerTabOptions = {
dataSource: new DevExpress.data.CustomStore({
load: function (loadTabOptions) {
console.log('get tabs');
var d = $.Deferred();
$.ajax({
url: 'GetLowerTabs',
data: { currentSidebarId: $scope.currentSidebarId },
type: 'GET',
success: function (result) { console.log(result); d.resolve(result); }
});
return d.promise();
}
}),
animationEnabled: true,
swipeEnabled: true,
itemTitleTemplate: 'title',
height: '100%'
};
$scope.navBarClicked = function (sidebarId) {
console.log(sidebarId);
$scope.currentSidebarId = sidebarId;
}
});
This works correctly however I have a navbar which when clicked, should change the tab control.
Currently I am changing the sidebarId which gets passed to the ajax call but I need a way to reload the include page so that this is called again. I have tried changing the lowerTabUrl and then changing it back again but this doesnt refresh the page. What is the best way to do this?
It depends on your angular version, you will need to watch after changes of value for param sidebarId, # angular 1 this is achieved by scope.watch
scope.$watch('sidebarId', function(newValue, oldValue) {
// ..call refresh here
});
at angular 1.5 and later you can override ngOnChages
this.$onChanges = function (changesObj) {
if (changesObj.sidebarId) {
// changesObj.sidebarId.currentValue
}
};

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

how to prevent ui-bootstrap pagination control from changing the url route

Within my application I have two views search and masternameserch these views are defined in app.js as:
$stateProvider
.state('search', {
url: '/',
controller: 'searchController',
controllerAs: 'search',
templateUrl: '/app/views/search.html'
})
.state('searchmasterName', {
url: '/searchmastername',
controller: 'searchMasterNameController',
controllerAs: 'masternameSearch',
templateUrl: '/app/views/searchmastername.html'
})
Within my views I have the ui-bootstrap pagination control setup as
<div class="text-center">
<uib-pagination ng-show="masternameSearch.pgTotalItems > 10" total-items="masternameSearch.pgTotalItems" ng-click="masternameSearch.pageChanged(); $event.stopPropagation();" ng-model="masternameSearch.pgCurrentPage" class="pagination-md" max-size="masternameSearch.pgMaxSize" boundary-links="true"></uib-pagination>
</div>
And within the controller I have the pageChanged() function setup as follows:
vm.pageChanged = function () {
var pageRequest = buildMasterNameSearchRequest(); //get cached request
pageRequest.pageFrom = vm.pgCurrentPage; //set page number to request
var currentPath = $state.current.name;
searchService.postSearchRequest(pageRequest).then(renderResults, onError);
$state.go('searchmastername',
{},
{
notify: false,
location: false,
inherit: false,
reload: false
});
$timeout(function () { location.hash = '#top' }, 1000);
}
The question I have is whenever clicking on the pagination control the underlying URL is always the root url. Therefore when I click on a pagination button the search executes but I am navigated back to the default main view which is wrong. As you can see from the code I first tried in the directive itself to change the onchange to an ng-click event and tried to stop propagation to stop the redirect through $event. This did not work. Second thing I tried was to call a state transition / state.go() in the pageChanged() function where I basically reload the view. This however does not work as it throws an error that the state cannot be found. Sadly this actually prevents the page from reloading or navigating to the main page so the error actually makes the page work as the end user might expect, but with errors generated around the missing state I know this isn't right.
Update: The error was generated from a type searchmastername and not searchmasterName.
Making this change fixed the error but still causes the site to redirect to the default view to load.
Can anyone provide an idea or ways to get the pagination control to not cause a navigation event by redirecting me to the default main view when ever clicked?
-cheers
After doing some more studying of this problem I thought the issue could be addressed by listening to the $rootScope for the stateChangeStart event and from there add a preventDefault() function to stop the navigation from occurring in the route which I did.
So the code now looks like this on the pageChanged() function
vm.pageChanged = function () {
var pageRequest = buildMasterNameSearchRequest(); //get cached request
pageRequest.pageFrom = vm.pgCurrentPage; //set page number to request
searchService.postSearchRequest(pageRequest).then(renderResults, onError);
$rootScope.$on('$stateChangeStart',
function(event) {
event.preventDefault();
});
$timeout(function () { location.hash = '#top' }, 1000);
}
While useful, using preventDefault() stops all further interaction with the page. Links would no longer work etc. I thought I had fixed but instead I had just stopped the event so the timeout never got called which was the culprit.
The real issue and I did it to my self was adding the timeout and using the location route #.
$timeout(function () { location.hash = '#top' }, 1000);
Using this function was actually (as designed) changing my route in my URL and navigating me to the main view. I needed to have the ability to scroll to the top so I changed the timeout function to look like this
vm.pageChanged = function () {
vm.showPager = false;
var pageRequest = buildMasterNameSearchRequest(); //get cached request
pageRequest.pageFrom = vm.pgCurrentPage; //set page number to request
searchService.postSearchRequest(pageRequest).then(renderResults, onError);
window.scrollTo(0, 0);
}
Using window.scroll accomplished the same scrolling effect but did not change the route.

Howto submit a form with Angular and displaying results on a different page

I'm trying to submit a form from a HTML page using angular.
My HTML code is:
<form role="search">
<input type="text" ng-model="searchSring">
<button type="submit" ng-click="searchPerson(searchString);">Get it!
</button>
</form>
The searchPerson function is calling some PHP page using Ajax and data is successfully retrieved from it.
What I want is when the user has clicked the Get it! button, he should be routed to another HTML page where I would like to display the results. I've tried using "action=" in the form and even calling window.location once Ajax completed to route to the next page. Every time the result is cleared. I've tried using factory with get/set, but this too clears the data on the second page after the window.location call.
Here's the factory code:
myApp.factory('searchService', function(){
var searchService = {};
var mySearchResult = {};
searchService.set = function(searchResult){
mySearchResult = searchResult;
}
searchService.get = function(text){
return mySearchResult;
}
return searchService;
});
CONTROLLER
myApp.controller('OnlineCVController', function($scope, searchService) {
$scope.searchPerson = function(personString) {
$.ajax({
url: "mySearch.php",
type: 'POST',
data: { Person: personString },
async: false, success: function (result) { searchService.set(result);
console.log(result);
window.location = "search.html";
}, error: function (result) { } });
}
Can anyone guide me further?

$http.get method not working on ng-submit

I want $http.get method to work when a form is submitted.
Here is my code. The object $scope.questions is being set when the method is called but the data doesn't show up in the div. Moreover, when the $http.get method is outside the signIn() function it works just fine.
$scope.signIn = function(data) {
$location.path('/profile');
var url = "database/fetch_data.php?query=";
var query = "Select * from question where userId=2";
url += query;
$http.get(url).success(function(questionData) {
$scope.questions = questionData;
console.log($scope.questions);
});
};
<div>
User Profile
<br/>Question Posted
<br/>
<input ng-model="query.title" id="value" type="text" placeholder="Search by Title..." ">
<div>
<ul>
<li ng-repeat="question in questions | filter: query ">
{{question.title}}
</li>
</ul>
</div>
<br/>
</div>
You need to move your $location.path('/profile') inside your http request. Remember that a http request is async call. You should redirect after getting the data not before.
$scope.signIn = function(data) {
var url = "database/fetch_data.php?query=";
var query = "Select * from question where userId=2";
url += query;
$http.get(url).success(function(questionData) {
$scope.questions = questionData;
console.log($scope.questions);
$location.path('/profile');
});
};
If you're redirecting to another route with a completely separate scope you will lose any scope you're setting in the success handling.
From what I'm reading you're clicking a button to do an action. After that action you're redirecting to another page with a separate controller and trying to persist the data.
Unfortunately, Angular hasn't figured out a great way to do this. The easiest way to persist data through controllers and scope is to create a service that will store it in one controller and grab it in another controller.
For instance:
$scope.signIn = function(data) {
var url = "database/fetch_data.php?query=";
var query = "Select * from question where userId=2";
url += query;
$http.get(url).success(function(questionData) {
$location.path('/profile');
storageService.store("question", questiondata)
});
};
Your new factory to persist data through:
angular.module('moduleName').factory('storageService', [
function () {
return {
store: function (key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
get: function(key) {
return JSON.parse(localStorage.getItem(key));
},
remove: function(key) {
localStorage.removeItem(key);
}
}
}
]);
Other controller to access data:
$scope.question = storageService.get("question");
// remove localstorage after you've grabbed it in the new controller
storageService.remove("question");
An alternative to doing the somewhat 'hacky' way of using localStorage to persist data through controllers is to use ui-router and have a resolve on the route you're redirecting to.
For instance:
$scope.signIn = function(data) {
$state.go('profile');
};
In your route file:
.state('profile', {
url: '/profile'
controller: profileControllerName,
templateUrl: 'profileHtmlTemplate.html',
resolve: {
'questions': [function() {
var url = "database/fetch_data.php?query=";
var query = "Select * from question where userId=2";
url += query;
$http.get(url).success(function(res) {
return res.data;
});
}]
}
}
In your profile controller:
Inject your 'questions' resolve into your controller and assign `$scope.question = questions;
This will make the HTTP call as soon as you click the route, return the data if successful, then render the page. It will NOT render the page if the resolve does not return success. This will ensure your data will be loaded before you load the page that depends on that data.
I would highly recommend using services to hold your HTTP calls for specific parts of your application. If you have a GET questions, POST question, PUT question. I would create a questionService and make all my HTTP methods there so you don't have to clutter your routes. You would only have to call:
.state('profile', {
url: '/profile'
controller: profileControllerName,
templateUrl: 'profileHtmlTemplate.html',
resolve: {
'questions': [function() {
return questionService.getQuestions(id).then(function(res) {
return res.data;
})
}]
}
}

Resources