How to get userid in angular view from Spring Boot REST Controller - angularjs

In my application, I am using Spring Security for authentication using database. Part of redirection strategy is to if user is ADMIN, redirect user to ADMIN(HOME) page, if user is USER, redirect that user to USER page.
When a user with role USER logs in, he sees USER page which is like below:
<html ng-app="benefitApp">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Benefit Application</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="/css/bootstrap.css" />
<script src="https://code.angularjs.org/1.6.1/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular-route.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular-resource.js"></script>
<script type="text/javascript" src="./js/app.js"></script>
</head>
<body ng-controller="UserCtrl">
<p>Hello <p th:text="${name}"></p></p>
<div>
<ul class="menu">
<li><a href='userProfile({{userid}})'>userprofile</a></li>
</ul>
<div ng-view="ng-view"></div>
</div>
</body>
</html>
I am trying to pass logged in user's id to this page from REST controller like this :
#RequestMapping(value = "/user", method = RequestMethod.GET)
public String userpage(Model model) {
LOGGER.info(" Enter >> userpage() ");
Authentication auth = SecurityContextHolder.getContext()
.getAuthentication();
String name = auth.getName();
User user = userManager.findUserByEmail(name);
model.addAttribute("name", name);
model.addAttribute("userid", user.getId());
return "user";
}
But I am not getting any userid in user.html page. What am I missing here?

You are using angularjs data-binding expression to bind userid to function:
<li><a href='userProfile({{userid}})'>userprofile</a></li>
which is wrong way.
Since you are using Thymeleaf, I would suggest you to use expression like this to bind link for user profile : th:href="#{${link}}"
# prefix is used to specify a link and $ prefix is used to bind your model value and then create a link with th:href like this:
<li><a th:href="#{'#/user/profile/' + ${userid}}">userprofile</a></li>
Or you can initialize a variable with ng-init like this:
<div ng-init="userId = ${userid}"></div>
And use it like this:
<li><a ng-href="#/user/profile/{{userId}}">userprofile</a></li>

Related

Validate Gmail account and retrieve basic profile info

Is there a way to validate account existence and retrieve basic gmail account info such as name and photo url using only email ?
Previously it was possible to get account photoUrl using the following endpoint:
http://picasaweb.google.com/data/entry/api/user/<hereYourUserIdOrYourEmail>?alt=json
but it was shut down.
You can't access that information with the gmail-api. If you are the admin of a g suite domain, you could use the directory API to obtain that info.
If the application is not intended for a specific domain, you can implement google oauth2 with JavaScript in the front-end, the user would have to authenticate and this way you'll be able to access the basic information. You need to create a project in cloud.google.com and get credentials (a clientID is needed in the code). More explanation here:
https://developers.google.com/identity/sign-in/web/sign-in
Implementation example (only clientID missing):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="google-signin-client_id" content="#clientId">
<title>Oauth2 web</title>
<!-- Google library -->
<script src="https://apis.google.com/js/platform.js" async defer></script>
<!-- Jquery library to print the information easier -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<!-- Bootstrap library for the button style-->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<div id="profileinfo">
</div>
<div class="g-signin2" data-onsuccess="onSignIn"></div>
<script>
function onSignIn(googleUser) {
var profile = googleUser.getBasicProfile();
console.log('ID: ' + profile.getId()); // Do not send to your backend! Use an ID token instead.
console.log('Name: ' + profile.getName());
console.log('Image URL: ' + profile.getImageUrl());
console.log('Email: ' + profile.getEmail()); // This is null if the 'email' scope is not present.
$("#profileinfo").append("<h2>Sup " + profile.getName() + ", welcome home my friend</h2>");
$("#profileinfo").append("<img style='width:250px;height:250px' src='" + profile.getImageUrl() + "'><br><br>");
$("#profileinfo").append("<p>Your email is: " + profile.getEmail() + "</p>");
}
</script>
<button type="button" class="btn btn-danger" onclick="signOut();">Sign out</button>
<script>
function signOut() {
var auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(function () {
console.log('User signed out.');
$("#profileinfo").empty();
$("#profileinfo").append("<h2>Goodbye old friend</h2>");
});
}
</script>
</body>
</html>

Open a new Site in angular

I had a Single Page Application developed in angular-js and i need to open a printside under a new url. At present, printtext.html loads its content but on the inside of the index.html. What i want is to load the content of the printtext.html alone without any Content from the index.html. Basically if i click on the link in my index.html i just want to see in the browser the text printtext. And not something like Some headertext which is curretnly the case. Is that possible or do i break the SPA rules? My Main goal is to create a Printsite where i just see the content without any header or footer information. Or should i user ng-hide for this?
I am not including the logic here, but if required will provide.
Index.html
<!DOCTYPE html>
<html ng-app="myapp">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<title>Myapp</title>
<script src="libs/js/angular.js"></script>
<script src="libs/js/angular-route.js"></script>
<script src="js/app.js"></script>
</head>
<body>
<h1> Some headertext </h1>
<ng-view></ng-view>
</body>
app.js
var app = angular.module('myapp', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/text', {
templateUrl: "template/text.html"
})
.when('/print', { //actually the parameter is /print/:object but i left the logic out here
templateUrl: "Print/printtext.html"
})
}])
text.html
<p> Some text </p>
<a ng-href="#!/print">Print </a> <!-- The right link would be something like #!/print/marc -->
printtext.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html ng-app="myapp">
<head><title>
Printview
</title>
<script src="../libs/js/angular.js"></script>
<script src="../libs/js/angular-route.js"></script>
<script src="../js/app.js"></script>
<body>
<p>printtext</p>
</body>
</html>
You directly use target = "_blank" in your anchor tag.
<p> Some text </p>
<a ng-href="#!/print" target="_blank">Print </a> <!-- The right link would be something like #!/print/marc -->
Otherwise, you can create a dynamically custom directive in angular.
custom directive generally uses to set target according to a dynamic condition.
<p> Some text </p>
<a ng-href="#!/print" ng-attr-target="_blank">Print </a> <!-- The right link would be something like #!/print/marc -->
<a ng-attr-target="_blank">
...
</a>
ng-attr-xyz lets you dynamically create #xyz, and if the value is undefined no attribute is created.

SpringBoot + Angular ng-view Issues

I'm new to Angular and I'm kind of learning js as I go, but I'm trying to run Angular on the front end with Spring Boot. By default Spring renders my index.html page normally, but I'm getting a 404 not found error when I try to go to the /login page. I've tried just about every url combination I can think of for the template url, but no luck. Because I'm new at Angular, I cannot determine if this is a Spring config issue or something simpler.
Angular controller app.js:
var wishingWell = angular.module('wishingWell', [ 'ngRoute' ]);
wishingWell.config(function($routeProvider, $httpProvider) {
$routeProvider.when('/', {
templateUrl : 'static/home.html',
controller : 'home'
}).when('/login', {
templateUrl : 'static/login.html',
controller : 'navigation'
}).otherwise('/');
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
});
wishingWell.controller('home', function($scope, $http) {
$http.get('/resource/').success(function(data) {
$scope.greeting = data;
})
});
wishingWell.controller('navigation', function() {});
index.html:
<!doctype html>
<html ng-app="wishingWell">
<head>
<meta charset="UTF-8"/>
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"/>
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
<link rel="stylesheet" href="/css/normalize.css"/>
<link rel="stylesheet" href="/css/main.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-route.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.js" integrity="sha256-16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA=" crossorigin="anonymous"></script>
<script src="/javascript/Angular/app.js"></script>
<title>Wishing Well</title>
</head>
<body ng-controller="home">
<nav class="nav">
<ul class="navback">
<li>
<a class="active" href="/">The Well</a>
</li>
<li>
<a href="/profile" >Profile</a>
</li>
<li>
Sign Up
</li>
<li>
Log In
</li>
<li>
Sign Out
</li>
</ul>
</nav>
<div ng-view></div>
</body>
</html>
folder structure:
Any ideas?
It has nothing to do with Spring as clicking on login link is getting rendered on client side and not on server side (not an ajax call or page submit).
I can see few issues here:
-> In index.html link for angular-route is incorrect
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-route.js"></script>
it should be
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-route.js"></script>
you forgot https:
-> You need to use #/login in anchor tag, else your page will be redirected to .login that doesn't exists
Log In
->index.html and login.html are in same directory, so in app.js template url should be login.html and not static/login.html
You can see it working here
https://plnkr.co/edit/YpAm5FVG2ME7s3EeAigY?p=preview
Note: I have moved index.html outside static folder to make it work with plunker and updated app.js path in index.html accordingly.
If it still doesnt work, press f12 (if using chrome) an post console output.
The root cause (#coder response found the surface level errors) of why these pages wouldn't load was that Spring security was blocking the file paths. I added the templates into the ant matchers and it works. This documentation is where I found this; something easily skipped over when going through it: https://spring.io/guides/tutorials/spring-security-and-angular-js/
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/index.html", "/sign-up.html","/login.html", "/").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable();
}

angular js , spring MVC angular JS code is not working in spring

snippet of my spring MVC is
#RequestMapping(value = "/list2", method = RequestMethod.GET,headers="Accept=*/*",produces = "application/json")
public ResponseEntity<List<Employe>> listAllUsers() {
List<Employe> users = dataService.getList();
if(users.isEmpty()){
return new ResponseEntity<List<Employe>>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<List<Employe>>(users, HttpStatus.OK);
}
my angular js controller is like below
'use strict';
var app = angular.module('app',[]);
app.controller('EmpController', function($scope, httpq) {
httpq.get('http://localhost:8080/SpringHibernate/list2')
.then(function(data) {
$scope.users = data;
})
.catch(function(data, status) {
console.error('Gists error', response.status, response.data);
})
.finally(function() {
console.log("finally finished gists");
});
});
my index.jsp is
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head ng-app="app" >
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859- 1">
<title>SpringHibernate</title>
</head>
<body >
<h1>Welcome to Spring Hibernate Project!!!</h1>
Please Click this Link To Proceed
Please Click this Link To Proceed
<div ng-controller="EmpController">
<!--Body content-->
<input ng-model="query"> Type to Search</input>
<ul>
<li ng-repeat="user in users | filter:query | orderBy:orderProp">
<p>{{user.firstName}}
<p>{{user.lastName}}
<p>{{user.email}}
<p>{{user.phone}}
</li>
</ul>
</div>
<script src="<c:url value="/resources/js/angular.min.js" />" type="text/javascript"></script>
<script src="<c:url value="/resources/js/app.js" />" type="text/javascript"></script>
</body>
</html>
after launching the code i am neither getting any log in my browser it looks like angular is not executing at all. please let me know what other details would be required. I have used the same URL in Postman it successfully generates the JSON response.
You put the ng-app attribute on the <head> element. So, only the head is handled by angular. The rest is purely static html, that angular doesn't care about.
Put in on <html> or on <body>.
Note that the error would be much easier to spot, by yourself, if your html code was correctly indented.

Alternative to using ng-init in 'view'?

I am trying to create a 'like' function for my app. I want to be able to set the value of a dynamically generated number as the 'like count'. The problem comes in using 'ng-init', as the documentation says this is a bad way to do it!
How do you set the value in the 'controller' rather than the 'view'?
Here is what I have so far:
<!doctype html>
<html ng-app="plunker" >
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<article ng-repeat="feed in feeds">
<h3>{{feed.createdby}}</h3>
<p>{{feed.content}}</p>
<button ng-click="likeClicked($index)">{{isLiked[$index]|liked}}</button>
<span ng-init="likeCount=feed.likes.length">{{likeCount}}</span>
</article>
</body>
</html>
Thanks,
JP
Just change
`<span ng-init="likeCount=feed.likes.length">{{likeCount}}</span>`
per
`<span>{{feed.likes.length}}</span>`.
If you still need the count in the controller for some other reason (which I can't see), create a controller, let's assume FeedCtrl, and add it to your article:
<article ng-repeat="feed in feeds" ng-controller="FeedCtrl">
...
<span>{{likeCount}}</span>
</article>
And your FeedCtrl would be:
function FeedCtrl($scope) {
$scope.$watch('feed.likes.length', function(newValue) {
$scope.likeCount = newValue;
});
}
Yet another approach would be create a function to resolve you the value:
<article ng-repeat="feed in feeds" ng-controller="FeedCtrl">
...
<span>{{likeCount()}}</span>
</article>
function FeedCtrl($scope) {
$scope.likeCount = function() {
return $feed && $feed.likes ? $feed.likes.length : undefined;
};
}
If your feeds object/array is long, it's better to use ng-bind for performance reasons.
<span ng-bind="likeCount"></span>
rather than
{{likeCount}}

Resources