$watch for location.hash changes - angularjs

In my angular app I am trying to change the location to "#home" when the user enters an invalid route.
Here's a short but complete app demonstrating what I did.
<!DOCTYPE html>
<html>
<head>
<script src="angular.js"></script>
<script>
angular.module('app', [])
.controller('ctrl', function($scope, $location, $window) {
$scope.$watch (function() { return $location.url() }, function(url) {
if (url == '')
$window.location = '#home'
})
})
</script>
</head>
<body ng-app="app" ng-controller="ctrl"></body>
</html>
But when I do this I get an infdig error when the page loads. I don't know whats wrong.
Edit:
I don't want to use routing libraries like "ui-router". so answers like this one that uses the "angular-route" library are not helpful.

You can specify that in app.config block using $routeProvider.
app.config(function ($routeProvider) {
$routeProvider
.when('/home', {
template: 'home.html',
controller: 'homeController'
})
.otherwise('/home');
});
.otherwise method will redirect the application to /home, if user tries to access any invalid path which is not specified in config.
Update:
And, If you don't want to use angular routing library you can use native javascript event hashchange on window to listen for hash change events. and redirect accordingly.
see the below example.
function locationHashChanged() {
if (location.hash !== "#/home") {
console.log('hash is other then #home. will redirect to #home');
console.log('Full path before', document.URL);
window.location.hash = '#/home';
console.log('Full path after', document.URL);
}
}
window.addEventListener('load', locationHashChanged);
window.addEventListener('hashchange', locationHashChanged);
Home
<br/>
Some-Site
<br/>
Other

Related

Angular js controller not working after modularizing app

I'm new to angularjs and followed the tutorial here from w3schools to create my first simple Angularjs app and it worked fine. After going through the official angularjs tutorial I decided to modularize my app but now its not working. Currently I m getting the error
"The controller with the name 'redController' is not registered."
I want to display a message in component 'red' using its controller. I tried altering many parts of the code only to get new errors and it seems I have messed up modularizing :|
I'm using v1.6.9
Here is my directory structure
app/
scripts/
angular.min.js
angular-route.js
blue/
blue.template.html
red/
red.template.html
red.module.js
red.component.js
app.config.js
app.module.js
index.html
and source files :
app.config.js
angular
.module("myApp", [ 'red','ngRoute' ])
.config(function($routeProvider) {
$routeProvider
.when("/red", {
templateUrl : "red/red.template.html",
controller: "redController"
})
.when("/blue", {
templateUrl : "blue/blue.template.html"
});
});
app.module.js
angular.module('myApp', [
'red',
'ngRoute'
]);
index.html
<!DOCTYPE html>
<html>
<script src="scripts/angular.min.js"></script>
<script src="scripts/angular-route.js"></script>
<script src="app.module.js"></script>
<script src="app.config.js"></script>
<script src="red/red.module.js"></script>
<script src="red/red.component.js"></script>
<body ng-app="myApp">
Red
Blue
<div ng-view></div>
<p>Click on the links to navigate "</p>
</body>
</html>
red.template.html
<h1>red</h1>
<p>{{msg}}</p>hell
red.module.js
angular.module('red', [ 'ngRoute' ]);
red.component.js
angular.module('red').component('red',{
templateUrl: 'red/red.template.html',
controller: function redController() {
this.msg = "this is red";
console.log("Hi");
}
});
You are delcaring the module again and again in each .js files, declare only in one .js file and use it in rest of the fields.
change your red.module.js as,
angular.module('red', []);
your app.config.js should be as,
angular
.module("myApp")
.config(function($routeProvider) {
$routeProvider
.when("/red", {
templateUrl : "red/red.template.html",
controller: "redController"
})
.when("/blue", {
templateUrl : "blue/blue.template.html"
});
});
and change the order as follows,
<script src="red/red.module.js"></script>
<script src="app.module.js"></script>
<script src="app.config.js"></script>
<script src="red/red.component.js"></script>
Change red.component.js as follows
angular.module('red')
.component('red',{
templateUrl:
'red/red.template.html',
})
.controller("redController",function($scope)
{
$scope.msg ="This is red";
});
First of all, as #Sajeetharan you're defining the myApp module twice. Inside your app.config.js and also in app.module.js. If you use angular.module with 2 parameters angular.module('app', []) you're setting the module, if you use angular.module('app') it'll work as a getter. So, in your app.config.js you should use the getter to configure your app.
Once you did that, you can configure your route to something like this:
angular.module('myApp').config(function($routeProvider){
$routeProvider.when('/red', { template: '<red></red>'});
})
I would use this approach since you defined the component in another module.
If you still want to use the approach you've implemented to set both the templateUrl and controller in the $routeProvider, you'll have to change your red component declaration to something like this:
angular.module('red')
.component('red', { templateUrl: 'red/red.template.html'})
.controller('redController', function(){
this.msg = 'This is red.';
});
I'vent tested this second approach as for me the first makes more sense.

Google's new reCaptcha breaks angular with ui-router

When I tick the recaptcha box, ui-router seems to break down. All links with ui-sref attributes on the page stops working, but I get no error messages. Please look at this plunker that I've set up. Do you have any idea of what might be the cause?
script.js
var app = angular.module('app', ['ui.router'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/',
templateUrl: 'home.html',
controller: function() {
grecaptcha.render('captcha', {
sitekey: "--sitekey--"
})
}
})
.state('other', {
templateUrl: 'other.html'
});
$urlRouterProvider.otherwise('/');
})
index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#*" data-semver="1.4.0-rc.0" src="https://code.angularjs.org/1.4.0-rc.0/angular.js"></script>
<script data-require="ui-router#*" data-semver="0.2.13" src="//rawgit.com/angular-ui/ui-router/0.2.13/release/angular-ui-router.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
<body>
<ui-view></ui-view>
</body>
home.html
<h1>Home</h1>
<p>Click the re-captcha, then try to change state by clicking the link below.</p>
<p><a ui-sref="other">Go to other state</a></p>
<div id="captcha"></div>
other.html is irrelevant.
UPDATE
I've noticed that the state transition fails only when the target state has a url defined, and I've managed to narrow it down to the following piece of code in the ui-router source (ui-sref directive):
element.bind("click", function(e) {
var button = e.which || e.button;
if ( !(button > 1 || e.ctrlKey || e.metaKey || e.shiftKey || element.attr('target')) ) {
// HACK: This is to allow ng-clicks to be processed before the transition is initiated:
var transition = $timeout(function() {
$state.go(ref.state, params, options);
});
e.preventDefault();
// if the state has no URL, ignore one preventDefault from the <a> directive.
var ignorePreventDefaultCount = isAnchor && !newHref ? 1: 0;
e.preventDefault = function() {
if (ignorePreventDefaultCount-- <= 0)
$timeout.cancel(transition);
};
}
});
As you can see, the e.preventDefault function is being overridden to cancel the timeout that will fire the state change. If you comment out this piece of code in the above binder the state transition works:
//e.preventDefault = function() {
// if (ignorePreventDefaultCount-- <= 0)
// $timeout.cancel(transition);
//};
Normally ui-router calls e.preventDefault() once per click on each anchor link, but when the reCaptcha is ticked it seems to be called twice. I am guessing that this might be connected to the problem, but I'm not 100% sure. Maybe someone with better debugging skills can understand what is happening. Here's a plunker that demonstrated this behaviour.
I've found a simple way to solve the problem with any kind of router on angular. when grecaptha got undefined, it's means that we've in your case a synchronization problem. So in my/ your controller you should load the script by using for example << $.getScript("URL") >>
SO :
In HTML
<div class="g-recaptcha" data-sitekey="YourSiteKey"></div>
And in your Controller :
$.getScript("https://www.google.com/recaptcha/api.js");
Here your let grecaptcha do this work like if you were loading your page for the first time.
I got the same error when using angular routing.
You can solve this problem by placing this code :
in index.html
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit"></script>
in your script.js :
var app = angular.module('app', ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider.state('home',
{
url: '/',
templateUrl: 'home.html',
controller: function() {
function onloadCallback() {
grecaptcha.render('yourHTMLElementId', {
'sitekey' : 'yourSiteKey'
});
}
onloadCallback();
}
})
.state('other', {
templateUrl: 'other.html'
});
$urlRouterProvider.otherwise('/');
})

angular and ui-router example is not working

Hello I'm trying a simple application with Angular and UI-Router...
But for some reason, it's not working at all.
In chrome, there is no error in the console, but there is even no output at all
Maybe some one has some clue on what's happening... I definitely have no idea.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<script src="/Scripts/angular.min.js"></script>
<script src="/Scripts/angular-ui-router.js"></script>
</head>
<body>
<div>
Route 1
<div ui-view="viewSidebar"></div>
<div ui-view="viewContent"></div>
</div>
<script>
var app = angular.module('app', ['ui.router']);
app.config(
['$stateProvider', '$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/media/list');
$stateProvider.state('mediaList', {
views: {
url: "/media/list",
'viewSidebar': {
template: '<p>SideBar</p>',
controller: 'SidebarControllerView'
},
'viewContent': {
template: '<p>Thumb view</p>',
controller: 'MediaControllerView'
}
}
});
}]);
app.controller('MediaControllerView', ['$scope', MediaControllerView]);
app.controller('SidebarControllerView', ['$scope', SidebarControllerView]);
function MediaControllerView($scope) {
$scope.model = 1;
};
function SidebarControllerView($scope) {
$scope.model = 1;
};
</script>
</body>
</html>
There is a working plunker
One important wrong setting is the URL. It does not belong to the view, but to the state:
...
$stateProvider.state('mediaList', {
// url belongs to the state
url: "/media/list",
views: {
// url does not belong to the views
// url: "/media/list",
'viewSidebar': {
template: '<p>SideBar</p>',
controller: 'SidebarControllerView'
},
'viewContent': {
template: '<p>Thumb view</p>',
controller: 'MediaControllerView'
}
}
});
...
Check it here
And also, as DTing spotted we have to provide ng-app:
<html ng-app="app" ng-strict-di>
...
NOTE: ng-strict-di is not a must but... it is a must - to avoid later issues...
if this attribute is present on the app element, the injector will be created in "strict-di" mode. This means that the application will fail to invoke functions which do not use explicit function annotation (and are thus unsuitable for minification), as described in the Dependency Injection guide, and useful debugging info will assist in tracking down the root of these bugs.

How to read url query parameters with AngularJS?

I'd like to get the value of specific url parameters using AngularJS. I then want to assign a specific value to a specific textbox.
An example URL might look like:
http://example.com/?param1=value1
I've seen examples about $location, routing and services. I don't want to do any of that. I just need the value of param1. Any ideas how that can be done?
Here's a corresponding jsfiddle.net with several attempts: http://jsfiddle.net/PT5BG/211/
Using $location is the angular way
$location.search().param1; should give it if html5mode=true
Otherwise you have to use pure javascript. Check this.
How can I get a specific parameter from location.search?
If you are using ngRoute, look for routeParams
If you using ui-Router, look for stateParams
JS way:
var key = 'param1';
var value = window.location.search.substring(window.location.search.indexOf(key)+key.length+1);
Try this.You need to route concept in angular js
<!DOCTYPE html>
<html lang="en">
<head>
<title>AngularJS Routes example</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular-route.min.js"></script>
</head>
<body ng-app="sampleApp">
Route 1 + param<br/>
Route 2 + param<br/>
{{param}}
<div ng-view></div>
<script>
var module = angular.module("sampleApp", ['ngRoute']);
module.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/route1/:param', {
templateUrl: 'your_url1',
controller: 'RouteController'
}).
when('/route2/:param', {
templateUrl: 'your_url2',
controller: 'RouteController'
}).
otherwise({
redirectTo: '/'
});
}]);
module.controller("RouteController", function($scope, $routeParams) {
$scope.param = $routeParams.param;
alert($scope.param);
})
</script>
</body>
</html>
$routeParams allows you dto the value of parameter

Why does this Angular ui router code cause an infinite loop in $digest?

I've boiled the code down as much as I can. Something about nested states and the event handling/broadcasting is causing an infinite loop. In Chrome I can pause it and see that it is looping forever in Angular's $digest function. Any idea why? Is it a bug in my example code, or a bug in Angular, or the UI Router?
<!doctype html>
<html ng-app='bugapp' ng-controller='BugAppCtrl'>
<head>
<script src='//code.jquery.com/jquery-1.10.1.min.js'></script>
<!-- Angular 1.2.11 -->
<script src='//ajax.googleapis.com/ajax/libs/angularjs/1.2.11/angular.js'></script>
<!-- UI router 0.2.8 -->
<script src='//cdn.jsdelivr.net/angular.ui-router/0.2.8/angular-ui-router.js'></script>
<script>
angular.module('bugapp', ['ui.router'])
.run(function ($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
})
.config(function ($locationProvider, $stateProvider, $urlRouterProvider) {
$locationProvider.html5Mode(false);
$stateProvider
.state("root", {
abstract: true,
url: "/servletContext?asUser",
template: '<div ui-view></div>' // ???
})
.state("root.home", {
abstract: true,
url: "/home",
template: "<div ng-if='hasData()' ui-view ></div>"
})
.state("root.home.profile", {
url: "/profile",
template: '<div>whatever</div>'
})
})
.controller('BugAppCtrl', function ($scope, $state, $stateParams, $log, $location) {
$log.log('BugAppCtrl: constructor');
$scope.hasData = function() {
var res = !!$scope.foo;
// $log.log("hasData called, returing " + res + " foo is " + $scope.foo);
return res;
};
$scope.$on('$stateChangeSuccess', function () {
$log.log("State changed! (to " + $state.current.name + ")");
$scope.foo = 'junk';
$scope.$broadcast("resetfoo");
});
$state.go('root.home.profile');
});
</script>
</head>
<body>
<div ui-view></div>
</body>
</html>
I suspect this is a bug in the UI Router, for two reasons:
I tried your code and then tried downgrading the version of UI
Router to 0.2.7. When I used 0.2.7, it worked.
Even if you keep using version 0.2.8 of UI Router, if you perform the state change through $location instead of $state, it works. Here's an example of using $location instead of the $state.go call:
$location.path('/servletContext/home/profile');
Although I use and recommend UI Router (can't do without nested views), if you find in the future that you want to do any sort of intercepting or redirecting when the user tries to go to certain pages, I recommend using $location.path instead of $state, for reasons I described in a blog post
Edit: I haven't tried with parameters before but just tried with the code you posted (I created a 2nd controller and assigned it to your 'root.home.profile' state), and it works. Instructions from UI Router are here. But basically if you set your URL in your state definition the same way you would with UI Router:
url: "/profile/:foo",
then in your $location.path call add the parameter in the path:
$location.path('/servletContext/home/profile/12');
and you can access the 12 in the controller from
$stateParams.foo

Resources