so here's my problem.
I'm trying to have dynamic data in my header. It's supposed to represent the number of items a user has in his cart.
So here's my header (the header is a fragment that I included in the layout.html) and the data is in the last li
<nav >
<ul>
<li><a th:href="#{/index}" class="">Home</a></li>
<li><a th:href="#{/products/list}" class="">Products</a></li>
<li><a th:href="#{/admin/index}" class="">Admin</a></li>
<li>Account</li>
<li>Contacts</li>
<li><a th:href="#{/login}" class="">Login</a></li>
<li><a th:href="#{/user-page}" class="">User</a></li>
<li>
<p th:text="${cart.id}"></p>
</li>
</ul>
</nav>
But since the header is available on every page of the web app, what should I do (in the controllers) to get this data?
I tried to put the cart data in the IndexController but it doesn't work. I'm not comfortable with Spring and Thymeleaf so I might be doing something wrong or maybe I missed something on data binding. I only have once constraint, I don't want to use Ajax or Jquery. Unless I have no choice but I doubt that. Here's what I tried in the IndexController
#GetMapping({"/", "/index", "/home"})
public String getIndex(Model model) {
this.userCart.setId(5);
this.userCart.setNumberItems(11);
model.addAttribute("cart", userCart);
model.addAttribute("phrase", "Oui oui si si 92izi");
model.addAttribute("nbItems", "10");
return "index";
}
I also tried to make another method mapped to "/" but it causes an error since I can't have to methods mapped to the same url. So what am I supposed to do ?
If you need a model attribute application wide, then you can use an #ControllerAdvice annotated class:
#ControllerAdvice
public class GlobalControllerAdvice {
#ModelAttribute("numberOfItemsInCart")
public int getNumberOfItemsInCart() {
// get the cart and return the number of items
}
}
And use this attribute in your template:
<p th:text="${numberOfItemsInCart}"></p>
The method that is annotated with #ModelAttribute can also declare HttpServletRequest request as a parameter if needed (See https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-arguments for all possible arguments for the method).
See https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-controller-advice for more details about #ControllerAdvice.
Related
I am having some difficulties in calling a method when a button is clicked.
In my Index.JSP
I have the following section of HTML code
<div class="hero-copy">
<h1 class="hero-title mt-0">Deep Algorithm by Sadman Sakib</h1>
<p class="hero-paragraph">A personal portfolio/demonstration of all university and extra-curricular activites, beautifully packaged, in a modern and responsive Spring MVC Web Application</p>
<div class="hero-cta">
<a class="button button-primary" onclick="">View Projects</a>
<div class="lights-toggle">
<input id="lights-toggle" type="checkbox" name="lights-toggle" class="switch" checked="checked" >
<label for="lights-toggle" class="text-xs"><span>Turn me <span class="label-text">dark</span></span></label>
</div>
</div>
</div>
Now "View Projects" is a button which will print "Hello" out in the console, I am not sure what I should be using to call the method in my controller. At the moment I am using onClick but am not sure what I should put as a parameter.
This is my controller class
#Controller
public class HelloController {
#RequestMapping("/projects")
public void add()
{
System.out.println("Hello");
}
}
This is my view, user will click view projects and it will print hello out in the console, how would I go about doing this?
EDIT
When I use a form it works, however when using href it does not link to my controller.
<form action="add">
<input type="submit" class="button button-primary" value="Me">
</form>
<span>View GitHub</span>
<h3>View GitHub</h3>
How can I use href to link back to my controller. Do I need to import some dependencies/taglines
First you must understand what the controller is doing. The controller is mapping the request which have the path /projects, so usually, the url will be something like http://localhost:8080/projects if your app is running on port 8080. Upon calling '/projects' from your browser, the method add() will be executed.
The easiest way to trigger the method add() in the controller is using href in the link.
The code will be as follows:
<a class="button button-primary" href="${pageContext.servletContext.contextPath}/projects">View Projects</a>
If you really want to use the onclick method, then you must create a javascript function and call the url which is mapping to /projects
Update 28/06/20
The code will not work because the method being invoked is returning void. Add #ResponseStatus(value = HttpStatus.OK) on the method then it should work just fine.
#Controller
public class HelloController {
#RequestMapping("/projects")
#ResponseStatus(value = HttpStatus.OK)
public void add()
{
System.out.println("Hello");
}
}
So basically I managed to fix it, I should call my controller using href like this
href="<c:url value="/projects"/>
Cheers to everyone who helped
I am implementing Role based spring security
In this example they have used thymeleaf for frontend purpose, but I am using angular9 with html.
they are using sec:authorize="hasRole('ROLE_ADMIN')" to provide access to the admin,in the same way if I want to provide the same thing in html, for that I have used the following code,
<li *ngFor="let user of users">
{{user.username}} ({{user.firstName}} {{user.lastName}})
- <a sec:authorize="hasRole('ROLE_ADMIN')" (click)="deleteUser(user.userid)" class="text-danger">Delete</a>
</li>
The person logged in is Role_user, eventhough the delete link is visible to the user.
How can I restrict.
Thanks in advance.
use *ngIf directive to show and hide the anchor tag
<li *ngFor="let user of users">
{{user.username}} ({{user.firstName}} {{user.lastName}})
- <a *ngIf="hasRole('ROLE_ADMIN')" (click)="deleteUser(user.userid)" class="text-danger">Delete</a>
</li>
but the hasRole() must return boolean. because *ngIf accepts the boolean
I have a thymeleaf fragment called nav which I include in all front-end pages, it goes like so:
<nav class="navbar navbar-expand-md navbar-dark bg-dark" th:fragment="nav">
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
How to get Java data here ?
</ul>
</div>
</nav>
But what I want to do now is get some data from the database and have that data available in this fragment, which in turn will appear on every page that includes this fragment.
If I want to pass data to a view regularly from a controller, I would use Model and model.addAttribute and return the appropriate view which would contain the relevant model data, but how can I pass data to this fragment?
You can create an interceptor and add model attribute on the postHandle method (which allows you access to the ModelAndView object. The interceptor will have to be on all the controllers that have this fragment.
You can add the relevant model attributes to the session and access them via ${session.attribute}.
Use the #ControllerAdvice annotation in combination with #ModelAttribute to add a model attribute to all controllers.
I am trying to code an HTML form that sends data to a RESTful web service (managed with Spring) using select HTML element.
The REST has to create an object Event on my database.
The problem I find is that the #RequestParam in the REST comes empty even if my options' values are present.
This is my HTML form.
<form name="editForm" role="form" novalidate ng-submit="vm.save()">
<!-- other fields that works correct -->
<div class="form-group">
<label class="control-label" data-translate="businessRequestApp.event.participantsAdd" for="field_attendees">Attendees</label>
<select style="height: 300px;" multiple class="form-control" id="field_attendees" ng-model="vm.event.usersOnIt" ng-options="customUser as customUser.username for customUser in vm.customusers | orderBy:'id' track by customUser.id">
<option value="{{customUser.username}}" name="attendeesToParse"></option>
</select>
</div>
</form>
This is my REST.
#PostMapping("/events")
#Timed
public ResponseEntity<Event> createEvent(#RequestBody Event event, #RequestParam(value="attendeesToParse") List<String> participants) throws URISyntaxException {
//Some code that creates an object "Event" on my database
}
I am trying to fill a field List of String. Due to my business logic I can't insert it into Event's class, so I have to threat it separately.
Note that #RequestBody works correctly, the issue is only with #RequestParam that does not receive anything.
Thanks in advice for your time.
Options elements are never sent. Select's value is sent. Try to move the name="attendeesToParse" to the select itself.
If you need multiple values create a hidden input and store selected options into the field. Use the hidden input name to get values in the controller.
My RequestController:
#Controller
#RequestMapping("/request")
public class RequestsController {
private static final Logger log = LoggerFactory.getLogger(TmtApplication.class);
#Autowired
RequestRepository requestRepository;
#Autowired
UsersRepository usersRepository;
#RequestMapping("/save")
String saveRequest()
{
Request requestObj = new Request(usersRepository.findOne(1L), new Date());
requestObj.setDescription("I got so bored");
requestObj.setStatus(false);
requestObj.setRequestDate(new Date());
requestRepository.save(requestObj);
return "index";
}
}
My button:
<input type="submit" value="Submit Request" style="display: block;">
I'm trying to get my button to fire off this request. What should I add to my HTML to initiate the call for /save?
Update:
Form:
<form action="/request/save" method="post" commandName="requestData">
<input type="text" id="dateInput" value="" style="display: none;"/>
<div style="width: 200px;"><input type="submit" value="Submit Request" style="display: block;">
</div>
</form>
Controller:
#RequestMapping(value = "/save", method = RequestMethod.POST)
String saveRequest(#ModelAttribute("requestData") Request requestData, Map<String, Object> map,
HttpServletRequest request)
{
Request requestObj = new Request(usersRepository.findOne(1L), new Date());
requestObj.setDescription(requestData.getDescription());
requestObj.setStatus(false);
requestObj.setRequestDate(requestData.getRequestDate());
requestRepository.save(requestObj);
return "save";
}
To get this to work using the spring code as-is, you must surround your tag with a form.
<form action="save">
<input type="submit" value="Submit Request" style="display: block;">
</form>
In addition, you must be calling this from the correct URL to get it to work. The form action can be relative to the page you're on, or relative to the root of the URL.
You have two options to hit the RequestMapping, which resolves to:
/request/save
One is to use a relative action. You'll have to serve your HTML up at this url:
{server:port}/request
and then your action should be:
"save"
The second option is to use an absolute path for the form action:
"/request/save"
Which will work from wherever your HTML is served on this server.
Summary
You need to submit something (the form), and tell it where to submit to (action). So you need to sync up your URL's, your form, and the submission endpoint.
Additionally, it is a good idea to specify the request method on your RequestMapping so that you can handle POST/GET separately. According to the Spring Documentation, the default behavior is to map ALL HTTP methods:
The above example does not specify GET vs. PUT, POST, and so forth,
because #RequestMapping maps all HTTP methods by default.
It's a good idea to specify a POST for a form submit.
#RequestMapping(value = "/save", method = RequestMethod.POST)
This is the direction you should go, since a form submit should be a POST action so that the contents of the form go in the request body, and eventually you will want it to take in fields from your form for the POST, and map them to objects in your Controller class.
A few Tips:
Consider using a Templating engine like Thymeleaf (which spring often has in their tutorials), or JSP+taglibs. Thymeleaf is a bit more lightweight, and if you use it, you'll have the benefit of doing things the way Spring has written a lot of their examples. See this tutorial for an example:
Spring Boot: Handling Form Submission
Alternatively if someone is just trying to test a Request Mapping, or you're just trying to verify that your MVC endpoint is doing what you think, it would be a lot simpler to use a tool like Postman (which I highly reccomend) to submit your requests. That would take a few variables out for you so you can focus on what you're trying to develop (A REST API?), rather than the testing setup.