Is there anyway to check when "/" route is called for the first time?
I mean, check when the home page of the app is opened for the first time.
Suppose you have an app that is a Single Page Application, if you want code that runs once, use module.run(): http://docs.angularjs.org/guide/module
angular.module('myModule', []).
run(function($http /*or whatever*/) {
// here goes your code that will only run at module initialization
});
You can use cookies. If user visit your app first time then he have not cookies but next time he will have.
.controller('MainCtrl', function ($scope, $cookies, $cookieStore, $log) {
$scope.showHello = !$cookies.visited;
$cookies.visited = 'yes';
});
view:
<div ng-if"showHello">
Hellow, stranger!
</div>
And don't forget to load ngCookes module
angular.module('App', ['ngCookies']);
Related
I am working on a single page app using angularjs. The app has many navigator pages that run ajax calls.
The problem is that whenever the app launches all ajax code is run for all pages (although pages have not been navigated to yet)
I need a way to run the below only when the navigator page is requested. How can I do that without placing my code in a function and calling the function?
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
$http.get("welcome.htm")
.then(function(response) {
$scope.myWelcome = response.data;
});
});
I'm trying to build my first AngularJS single page application. I copied part of the code below and modified it some. I have a menu bar which calls the Navigate method that I added to the mainController.
When I click on the menu button the expected alert message appears in Navigate, but the alert message in the $routeProvider function only fires when the application starts and it never fires again. I can't find a good explanation of this, but logic says the $routeProvider function should fire when a new $location.path is set in Navigate. Is that wrong? How is this supposed to wire up? Is my nested single page controller causing the menu command to fail?
Also, are there really supposed to be two semicolons at the end or should one of them come after the app.config section?
var app = angular.module('myApp', ['ngRoute']);
app.config(['$routeProvider', function ($routeProvider)
{
alert("$routeProvider " + $routeProvider.path);
$routeProvider
.when('/', {
templateUrl: 'App/Views/Home.html',
controller: 'homeController'
})
.when('/about', {
templateUrl: 'App/Views/About.html',
controller: 'aboutController'
})
.otherwise({
redirectTo: '/'
});
}])
app.controller('mainController', function ($scope)
{
$scope.Title = "Default Title";
$scope.Message = "Default Message";
$scope.Navigate = function (myPath)
{
alert("Navigate " + myPath);
$location.path(myPath);
};
});;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<ul class="MenuBar">
<li class="MenuButton FloatLeft" ng-click="Navigate('/home');">Home</li>
<li class="MenuButton FloatLeft" ng-click="Navigate('/about');">About</li>
<li class="MenuButton FloatLeft" ng-click="Navigate('/about');">Log In</li>
</ul>
You're trying to run an alert whenever the $routeProvider function runs but it doesn't quite work that way. The $routeProvider function just tells Angular "Whenever the location path changes, refer to this JSON object to know what to do next." Then your code providers some JSON attributes to Angular such as templateUrl and controller. Your alert function will only run once because the $routeProvider is just setup code to configure Angular's routes.
To run code after going to another "page", just add the code to the controller.
Code Example:
app.controller('homeController', function($scope, $http) {
alert("I'm running the homeController() function now");
});
Also, I noticed that you didn't inject $location into your controller. Without this, $location will just be an undefined object. Change your controller definition like this:
app.controller('mainController', function ($scope, $location)
{
$scope.Title = "Default Title";
$scope.Message = "Default Message";
$scope.Navigate = function (myPath)
{
alert("Navigate " + myPath);
$location.path(myPath);
};
});
Remember that any Angular object starting with the $ dollar sign ($timeout, $http, $routeProvider, etc) must be injected into your controller.
You have a few issues with the code you're showing. Not enough details to know for sure but here's what's wrong.
First:
A module's config block will only be executed once, at the start. You're not seeing the alert within your config beyond once because it's only ever called once during the bootstrap of your module.
Second:
You need to inject services that your controller depends on.
app.controller('mainController', function ($scope) { });
Note that you're missing the $location service here.
app.controller('mainController', function ($scope, $location) { });
Third:
We can't see some missing pieces to your code to help you out. You're not showing us how mainController is actually hooked up to anything. How myPath is being sent to the Navigation function on your controller, etc.
I found a nested controller that I wasn't using. When I took that out part of the menu worked. I say part because on some links instead of calling the Navigate function I was setting the window.location. That seems to fire the $routeProvider and the view changes like it should. When I change the Navigate function as shown below it works. I think setting $location.path() in the Navigate function should do the same thing, but it's not working for me.
$scope.Navigate = function (myPath)
{
alert("Navigate " + myPath);
//$location.path(myPath);
window.location = '#' + myPath;
};
I have this global set up for my angular App module:
var App = angular.module('App', [], function ($interpolateProvider) {
//$interpolateProvider.startSymbol('<%');
//$interpolateProvider.endSymbol('%>');
});
I include it in all pages with angular stuff.
I then have a controller loaded on a page that requires a service called 'angularFileUpload':
App.controller('FileUploadController', ['$scope', 'FileUploader', function ($scope, FileUploader) {
If i place that service inside the module array, it works fine. Is there a way of just attaching it to this controller instead... this means i do not have to load the script files for every page using this module regardless of if the controllers require the angularfileUpload service or not.
Edit: regarding the last comment
If i declare:
var App = angular.module('App');
How do i then add that service to the module?
Let's say I have 4 routes - 2 require the user to be logged in, 2 do not. My app init looks like:
$routeProvider.when('/open1',{templateUrl:'/open1.html',controller:'Open1'});
$routeProvider.when('/open2',{templateUrl:'/open2.html',controller:'Open2'});
$routeProvider.when('/secure1',{templateUrl:'/secure1.html',controller:'Secure1'});
$routeProvider.when('/secure2',{templateUrl:'/secure2.html',controller:'Secure2'});
Routes /open1 and /open2 are open to all, while routes /secure1 and /secure2 require the user to be logged in and, if not, take some action, e.g. redirect to login or launch a warning. I can determine the user's state by using my Auth service and calling, e.g., Auth.isLogin(). So the result would be:
going to /open1 and /open2 always go to the template and controller declared above
if Auth.isLogin() returns true, /secure1 and /secure2 go to the above-declared template and controller
if Auth.isLogin() returns false, /secure1 and /secure2 take some other action, e.g. $location.path('/login')
I could put logic in the Secure1 and Secure2 controllers that checks, but that is repetitive and mixes up responsibilities, makes them harder to test, etc.
Is there a way that I can use the $routeProvider to declare, "check this route and this route and if not, redirect"? I was thinking of using resolve somehow, but not quite sure how to work it in (docs on resolve are not very clear, and few helpful examples).
EDIT:
based on the answers below, it appears there are three philosophies for doing this:
Using resolve to check logged in and fail the promise, and then catching the $routeChangeError event to redirect http://www.sitepoint.com/implementing-authentication-angular-applications/
Using just $routeChangeStart event to check logged in and redirect http://arthur.gonigberg.com/2013/06/29/angularjs-role-based-auth/
Using just resolve to check logged in and redirect http://midgetontoes.com/blog/2014/08/31/angularjs-check-user-login
The 2nd option is what the two answerers have suggested.
As in my comments above, there are 3 different paths (plus the ability to use a directive if you want to control it from within html templates). I ended up following
https://midgetontoes.com/angularjs-check-user-login/
which essentially is as follows:
$routeProvider.when('/secure', {
templateUrl: '/secure.html',
controller: 'Secure',
resolve:{
loggedIn:onlyLoggedIn
}
});
And then onlyLoggedIn:
var onlyLoggedIn = function ($location,$q,Auth) {
var deferred = $q.defer();
if (Auth.isLogin()) {
deferred.resolve();
} else {
deferred.reject();
$location.url('/login');
}
return deferred.promise;
};
Simple, works like a charm. If I ever need a directive, I will pull this piece into a service.
This blog post deals with user authentication in AngularJS using directives.
The $route service emits $routeChangeStart before a route change.
If you don't use directives, you can catch that event by calling app.run (you can place it after the code where you define the routes [app.config]). For example:
For full disclosure I use ui.router and this is an adapted code from $stateChangeStart I use in my app
var app = angular.module('app');
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/open1',{templateUrl:'/open1.html',controller:'Open1'});
$routeProvider.when('/open2',{templateUrl:'/open2.html',controller:'Open2'});
$routeProvider.when('/secure1',{templateUrl:'/secure1.html',controller:'Secure1'});
$routeProvider.when('/secure2',{templateUrl:'/secure2.html',controller:'Secure2'});
}]);
app.run(['$rootScope', '$location', 'Auth', function($rootScope, $location, Auth) {
$rootScope.$on('$routeChangeStart', function(event, currRoute, prevRoute){
var logged = Auth.isLogin();
//check if the user is going to the login page
// i use ui.route so not exactly sure about this one but you get the picture
var appTo = currRoute.path.indexOf('/secure') !== -1;
if(appTo && !logged) {
event.preventDefault();
$location.path('/login');
}
});
}]);
I had the same problem and I did it this way:
var app = angular.module('myModule',["ui-bootstrap"]);
And then listen for a locationchange in the app (this will also trigger onEnter of a page)
app.run(function ($rootScope, $location, $cookieStore) {
$rootScope.$on("$locationChangeStart", function (event, next, current) {
//Here you can check whatever you want (servercall, cookie...)
});
}
I Hope this helps!
I'm using the boilerplate stack from MEAN.io and finding it quite a good starting point, however I'm having trouble mixing the different routing commands. My app is going to have a simple signin page which is public, everything else is hidden behind that. I can check if the user is authenticated no problem, but I cannot for the life of me get Angular to load the signin page from the server. I already have a signin button on my html page that calls the correct route no problem at all, I just can't do the same thing from code.
The $location.path('/signin'); code doesn't call the server because it leaves the hash in the path
My Angular controller
angular.module('tms.tweets').controller('TweetsController', ['$scope', '$routeParams',
'$location', '$resource', 'Global', 'Tweets', function ($scope, $routeParams, $location,
$resource, Global, Tweets) {
$scope.global = Global;
$scope.find = function() {
if(Global.authenticated){
console.log(Global.authenticated);
Tweets.query(function(tweets) {
console.log("Tweets at Angular Controller: " + tweets.length);
$scope.tweets = tweets;
});
}
else{
console.log("Unauthorized");
$location.path('/signin');
}
};
}]);
Found the answer to my redirect issue, I swapped $location.path for
$window.location.href = '/signin';
For my purposes calling $window.location.href = '/newpath'; from inside my controller was not working.
I've been using the following function if I need to reload within the controller:
$scope.changeRoute = function(url, forceReload) {
$scope = $scope || angular.element(document).scope();
if(forceReload || $scope.$$phase) { // that's right TWO dollar signs: $$phase
window.location = url;
} else {
$location.path(url);
$scope.$apply();
}
};
Then you would call it like this:
$scope.changeRoute('#/newpath');
I will say though that doing this should be avoided, and that adding a run phase to your app's configuration phase should be preferred. You can read more about adding a run phase to your app configuration here: http://www.angularjshub.com/examples/modules/configurationrunphases/