Spring Boot And Thymeleaf remain on the same page on post request is made - spring

I've created an web app that searches for online car ads and populates the page with a few tables after a post request.It looks like this:
After Search:
Every table element has a save button which should save those values to the database but my problem is that the page gets refreshed after submitting a post request. How can I do this without refreshing the page?
Table:
<form th:action="#{/saveAd}" method="POST">
<table class="table table-sm table-hover">
<thead class="thead-dark">
<tr>
<th>Imagine</th>
<th>Titlu Anunt</th>
<!-- <th style="width: 16.66%">Link</th> -->
<th>Pret</th>
<th>Oras</th>
</tr>
</thead>
<tbody id="myTable">
<th:block th:each="element : ${lista}">
<trth:onclick="'javascript:rowClicked(\'' + ${element.url} + '\');'">
<td><img th:src="#{${element.img}}" class="size" /></td>
<td th:text="${element.title}"></td>
<td th:text="${element.pret}"></td>
<td th:text="${element.oras}"></td>
<td><input class="btn btn-danger" type="submit"value="Save"></td>
</tr>
</th:block>
</tbody>
Controller:
#RequestMapping(path = "/saveAd", method = RequestMethod.POST)
public String saveAd(#ModelAttribute("adValue") AdValue adValue) {
System.out.println(adValue.getImg());
System.out.println(adValue.getLink());
System.out.println(adValue.getOras());
System.out.println(adValue.getPret());
System.out.println(adValue.getTitle());
return "home";
}
And also, how could I bind the list to a model object after pressing the save button?

I guess you may like this project. It is similar with what you need :
https://github.com/adinafometescu/tutorials/tree/master/spring-elasticsearch
You can use .bootstrapTable(). It a very method to update dynamically your table.
<table id="car-table" class="table table-striped">
<thead>
<tr>
<th data-field="id">Id</th>
<th data-field="title">Title</th>
<th data-field="price">Price</th>
<th data-field="city">City</th>
<th data-width="10" data-formatter="saveButtonFormatter"/>
</tr>
</thead>
</table>
The beauty is that it will map the data-field to a java object.
js stuff:
function saveButtonFormatter(value, row, index){
var adId = row.id;
return "<button class=\"btn btn-danger \" data-title=\"Save\"
data-toggle=\"modal\" onclick=\"saveAd(\'"+adId+"\')\"
</button>"
}
The function saveAd(adId) will call the rest endpoint and will update the bootstrap table on success.
I see that in your thymeleaf you don't have inputs. I suggest to not post your entire object if you don't need user input, just the id.
// anotate the controller class with #RestController
#Autowired
AdService adService;
#PostMapping(path = "/ad/{id}")
public ResponseEntity<?> saveAd(#PathVariable("id") String id) {
adService.saveAd(id);
return new ResponseEntity<>(HttpStatus.ACCEPTED);
}
P.S : don't write code in Romanian :D

Related

Need to print name instead of id in vue.js frontend and Laravel backend

Here is my CategoryController.php code...
public function name($id) {
$f = Category::findOrFail($id);
$nm = $f->name;
return $nm;
}
Here is my router.
Route::get('/category/{id}', [CategoryController::class, 'name']);
In vue.js I defined this in method,
async getCategoryName($id){
await this.callApi('get','/category/' + $id)
.then(response => {
this.name = response.data.name
return this.name;
});
}
In the table, I need to get category name instead of category id. from URL I get category name but It shows that [object promise]
<table class="_table">
<!-- TABLE TITLE -->
<tr>
<th>ID</th>
<th>Category Name</th>
<th>Name</th>
<th>Created At</th>
<th>Action</th>
</tr>
<!-- TABLE TITLE -->
<!-- ITEMS -->
<tr v-for="(tag, i) in tags" :key="i" if="tags.length">
<td>{{tag.id}}</td>
<td>{{getCategoryName(tag.categoryId)}}</td>
<td class="_table_name">{{tag.name}}</td>
<td>{{tag.created_at}}</td>
<td>
<Button type="info" size="small" #click="showEditModal(tag, i)">Edit</Button>
<Button type="error" size="small" #click="showDeletingModal(tag, i)" :loading="tag.isDeleting">Delete</Button>
</td>
</tr>
</table>
Please help me...
This is the normal behaviour of vue.js, why don't you add the category name in your controller instead of loading it server side, your approach is not good performance wise.
In your controller where you get the view you will have something like: $tags = Tag::all()
You can simply load in each categroy: $tags = Tag::with('category')->get()
In your vue app you can then simply access the name like: tag.category.name

: EL1008E: Property or field 'LEVEL' cannot be found on object of type 'java.util.ArrayList' - maybe not public or not valid?

please assist with the below. I am trying to display an arraylist returned from the controller and display it to an Html table but I get the above error.
here is my controller code:
#GetMapping(value="/chart" )
public List<List<CanvasjsChartData.DataPointModel>> chart(Model modelMap) {
List<List<CanvasjsChartData.DataPointModel>> dataPointsList = canvasjsChartService.getCanvasjsChartData();
modelMap.addAttribute("dataPointsList", dataPointsList);
System.out.println("dataPointsList");
return dataPointsList;
}
and this is the table I want to display my list in
<table class="table" id="dataTable" style="width:100%">
<thead>
<th>Level</th>
<th>Occurences</th>
</thead>
<tbody>
<tr th:each="item :${dataPointsList}">
<td th:text="${item.LEVEL}"> </td>
<td th:text="${item.OCCURENCES}"> </td>
</tr>
</tr>
</tbody>
I know for sure the ArrayList has the data I require as shown below I dont know why its giving me the error
Your debug shows you have an List<List<CanvasjsChartData.DataPointModel>> (two Lists inside of each other) -- when your HTML is expecting List<CanvasjsChartData.DataPointModel>. You should fix that in your controller/model by only returning a single list.
You could also display your HTML like this (where you loop over the 0th element of the outer array):
<tr th:each="item :${dataPointsList[0]}">
<td th:text="${item.LEVEL}" />
<td th:text="${item.OCCURENCES}" />
</tr>

send multiple values from jsp to controller

I am making a spring application where i have a jsp page that has got tables that prints data of object Car like carid, name etc.
Now i have added the feature to edit and delete them, but i have a situation where i need to book them.
I have a row that has car details and a date picker with a book button. My question is-
How can i pass carid with the date selected to a specific controller, though i have done edit and delete function using carid, but now that a separate date has been added, i am confused how do i send the id with date to the controller.
Here is my jsp code, please help. thanks
<c:if test="${!empty listOfAvailableCars}">
<table class="tg">
<tr>
<th width="80">Id</th>
<th width="120">Car Name</th>
<th width="120">Car Model</th>
<th width="120">Car Number</th>
<th width="120">Car Type</th>
<th width="120">AC/ NON AC</th>
<th width="60">Booking Date</th>
</tr>
<c:forEach items="${listOfAvailableCars}" var="availableCars">
<tr>
<td>${availableCars.id}</td>
<td>${availableCars.name}</td>
<td>${availableCars.model}</td>
<td>${availableCars.type}</td>
<td>${availableCars.number}</td>
<td>${availableCars.isAC}</td>
<td><input type="datetime" value="bookingDate"/></td>
<td>Book</td>
</tr>
</c:forEach>
</table>
</c:if>
Here is the controller -
#Controller
public class BookingController {
#Autowired
private CarService carService;
#RequestMapping(value = "/bookCar/{id}")
public String bookCar(#PathVariable("id") int id, Model model) {
carService.bookCar(id);
return "userDashboard";
}
}

Angular 8 Pagination with Data from Database --

I am having a little trouble with this one.
Using the approach discussed in this -- https://jasonwatmore.com/post/2019/06/18/angular-8-simple-pagination-example
Use-case difference is, my data all comes from database. So I have had to use a model class and all. But, due to some problem, I am getting the same data [1st row from db] in all the rows. Let me post the code I used --
ANGULAR
method inside my component to get data from service class
newsTopics: NewsTopic[];
pageOfItems: Array<NewsTopic>;
getAllNewsTopics() {
this.userService.getAllTopics()
.subscribe((data: NewsTopic[]) => {
this.newsTopics = (data as NewsTopic[]).map((x, i) => ({ Id: (i + 1), TopicId: data[0].TopicId, TopicName: data[0].TopicName, TopicInfo: data[0].TopicInfo, IssueStartDate: data[0].IssueStartDate, IssueCloseDate: data[0].IssueCloseDate, NewsCategory_Id: 0 }));
})
}
my model class
export class NewsTopic
{
Id: number;
TopicId: string;
TopicName: string;
TopicInfo: string;
IssueStartDate: Date;
IssueCloseDate: Date;
NewsCategory_Id: number;
}
the method in service class itself
getAllTopics(){
var reqHeader = new HttpHeaders({ 'No-Auth': 'True' });
return this.http.get<NewsTopic[]>(this.rootUrl + '/api/NewsTopic/GetAllNewsTopics', { headers: reqHeader });
}
my html for showing the data and the pagination control
<div class="card-body">
<table class="table table-striped" id="newstopics_tbl">
<thead>
<tr style="background:linear-gradient(50deg, #d9fcfc, #dafbde)">
<th>Topic ID</th>
<th>Topic Name</th>
<th>Topic Info</th>
<th>Start Date</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let nt of pageOfItems">
<td><b>{{nt.TopicId}}</b></td>
<td>{{nt.TopicName}}</td>
<td>{{nt.TopicInfo}}</td>
<td>{{nt.IssueStartDate}}</td>
</tr>
</tbody>
</table>
</div>
<div class="card-footer pb-0 pt-3" style="background:linear-gradient(50deg, #d9fcfc, #dafbde); margin-top:15px">
<jw-pagination [items]="newsTopics" (changePage)="onChangePage($event)"></jw-pagination>
</div>
My guess is, the problem lies in the getAllNewsTopics() method, where I am trying to fill and map the array of objects and assign to the variable. Something wrong there. If you see the original example from the link, they used a .fill(0) also. In my case I tried doing .fill(data[0]) however result is the same, ie. only first record, repeated multiple times.
What is the trick I am missing? Can someone just point me out.
Much needed, Thanks,
EDITS --
These are the changes->
getAllNewsTopics() {
var reqHeader = new HttpHeaders({ 'No-Auth': 'True' });
return this.http.get<NewsTopic[]>(this.rootUrl + '/api/NewsTopic/GetAllNewsTopics', { headers: reqHeader })
.subscribe((data: NewsTopic[]) => {
this.newsTopics = data;
});
}
and
<div class="card-body">
<table class="table table-striped" id="newstopics_tbl">
<thead>
<tr style="background:linear-gradient(50deg, #d9fcfc, #dafbde)">
<th>Topic ID</th>
<th>Topic Name</th>
<th>Topic Info</th>
<th>Start Date</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let nt of pageOfItems" style="cursor:pointer" (click)="NewsArticleAdd(nt)">
<td (click)=""><b>{{nt.TopicId}}</b></td>
<td style="color:mediumvioletred;" (click)="">{{nt.TopicName}}</td>
<td (click)="">{{nt.TopicInfo}}</td>
<td (click)="">{{nt.IssueStartDate}}</td>
</tr>
</tbody>
</table>
</div>
<div class="card-footer pb-0 pt-3" style="background:linear-gradient(50deg, #d9fcfc, #dafbde); margin-top:15px">
<jw-pagination [items]="newsTopics" (changePage)="onChangePage($event)"></jw-pagination>
</div>
That does the trick. Works as expected,

spring mvc mapping - send value between controllers

I have got webapp in spring 3 mvc. The case is that I have index page with url, when user click on them should be display another page with details of choosed information. Now the details page is shown but without any information (on index page is creating model with correct variable but not in details controller - in debug mode).
index controller method:
#RequestMapping(value="/{site}", method = RequestMethod.GET)
public String showDetails(#RequestParam(value = "site", required = true) String site, Model model){
Catalog product = catalogEndpoint.getByTitle(site);
model.addAttribute("product", product);
return "details";
}
index html:
<form action="#" th:object="${product}" method="post" th:action="#{/details}">
<table border="0" width="600" th:each="sb, poz : ${product}" >
<tr >
<td rowspan="3" width="20"><span th:text="${poz.count}"></span></td>
<td>
<a th:href="#{/details/(site=${sb.tytul})}" th:value="${site}"><span th:text="${sb.tytul}"></span></a>
</td>
</tr>
<tr >
<td><span th:text="${sb.adres}"></span></td>
</tr>
<tr>
<td>category:<b><span th:text="${sb.category.name}"></span></b></td>
</tr>
</table>
</form>
details controller method:
#RequestMapping(value = "details/{site}", method = RequestMethod.GET)
public String showHomePage(#PathVariable(value = "site") String site, Model model){
model.addAttribute("product");
return "details";
}
details html:
<form th:object="${product}" method="get" th:action="#{/details}">
<table border="1" width="600" >
<tr >
<td ><span th:text="${tytul}"></span></td>
<td>
<span th:text="${opis}"></span>
</td>
<td><span th:text="${adres}"></span></td>
</tr>
</table>
</form>
I don't have any ideas how to map the details site (I tried a lot of solution but nothing). Thanks for help.
With thymeleaf, using th:object, you need to reference the fields of that object with *{}
<form th:object="${product}" method="get" th:action="#{/details}">
<table border="1" width="600" >
<tr >
<td ><span th:text="*{tytul}"></span></td>
<td>
<span th:text="*{opis}"></span>
</td>
<td><span th:text="*{adres}"></span></td>
</tr>
</table>
</form>
assuming tytul, opis, and adres are fields of product. Unless it's a type, don't forget
Catalog product = catalogEndpoint.getByTitle(site);
model.addAttribute("product", product);
in your details controller method, otherwise you won't have a Catalog model attribute.
inside your details controller where are you setting product object in your model ?
model.addAttribute("product");
is just settingstring object "product", fetch the product object and set it in details controller like you have done in showDetails method
Change
model.addAttribute("product");
To
Catalog product = catalogEndpoint.getByTitle(site);
model.addAttribute("product", product);
in "showPage" method.

Resources