(First time asking a question here) I created a rest api on java that returns all the cars available in the table Cars from my db. I found a way to get one of the cars with an specific Id and can show it on my page, but it can't understand how to show all the cars in the same page. Basically i don't understand how to show the arraylist that I get from my Rest Api and show it. I see the whole array in the console but not on my html. I not asking for the whole architecture of angular, just want to know how to show on my app-component when I click a button all the items that my rest has.
My rest:
#GET
#Produces({ "application/json" })
public List<CarDto> getCars() {
Car macchina;
// CarDao trasform1 = new CarDao();
CarDto trasform2;
// java 8+ lambda function, Stream (per divertimento)
List<Car> listaMac = carDao.getCars();
List<CarDto> listaMacAgg = new ArrayList<>();
for (int i = 0; i < listaMac.size(); i++) {
trasform2 = new CarDto(listaMac.get(i));
listaMacAgg.add(trasform2);
}
return listaMacAgg;
}
The class from my app component that gets the response from my rest:
import { Component } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'rest agency test';
caid: string = "";
response: any;
response2:any;
constructor(private http: HttpClient){}
ngOnInit(){
}
search(){
this.http.get('http://localhost:8080/rest_agency/rest/hello/'+this.caid)
.subscribe((response) => {
this.response = response;
console.log(this.response);
})
}
allCars(){
this.http.get('http://localhost:8080/rest_agency/rest/hello')
.subscribe((response2) => {
this.response = response2;
console.log(this.response);
})
}
}
my app.component.html
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<p><button (click)="allCars()"> All Cars</button></p>
<p>Search id:<input type="text" [(ngModel)]="caid">
<button (click)="search()">Search</button></p>
<div *ngIf="response2">
<table>
<ul class="heroes">
<tr>
<td>ID</td>
<td>Brand</td>
<td>Color</td>
<td>Year</td>
<td>Price</td>
<td>Sold</td>
</tr>
<tr>
<div *ngFor="let all of response | keyvalue">
<td><li>{{response.caId}}</li></td>
<td><li>{{response?.brand}}</li></td>
<td><li>{{response?.color}}</li></td>
<td><li>{{response?.year}}</li></td>
<td><li>{{response?.price}}</li></td>
<td><li>{{response?.sold}}</li></td>
</div>
</tr>
</ul>
</table>
</div>
<div *ngIf="response"> {{response.caid}}
<table>
<ul class="heroes">
<tr>
<td>ID</td>
<td>Brand</td>
<td>Color</td>
<td>Year</td>
<td>Price</td>
<td>Sold</td>
</tr>
<tr>
<td><li>{{response?.caId}}</li></td>
<td><li>{{response?.brand}}</li></td>
<td><li>{{response?.color}}</li></td>
<td><li>{{response?.year}}</li></td>
<td><li>{{response?.price}}</li></td>
<td><li>{{response?.sold}}</li></td>
</tr>
</ul>
</table>
</div>
</div>
I was expecting the result of all the info of the arraylist that comes from the rest
here is what it shows calling one id : https://imgur.com/FHX4aiO
and here's what happens when call the whole list: https://imgur.com/pdjg4aq)
You say <div *ngIf="response2"> but you never store anything in response2. As a result this block is never shown. Please change to
allCars(){
this.http.get('http://localhost:8080/rest_agency/rest/hello')
.subscribe((response2) => {
this.response2 = response2;
console.log(this.response);
})
}
--
<div *ngIf="response2">
<table>
<ul class="heroes">
<tr>
<td>ID</td>
<td>Brand</td>
<td>Color</td>
<td>Year</td>
<td>Price</td>
<td>Sold</td>
</tr>
<tr>
<div *ngFor="let all of response2 | keyvalue">
<td><li>{{all.caId}}</li></td>
<td><li>{{all.brand}}</li></td>
<td><li>{{all.color}}</li></td>
<td><li>{{all.year}}</li></td>
<td><li>{{all.price}}</li></td>
<td><li>{{all.sold}}</li></td>
</div>
</tr>
</ul>
</table>
</div>
Is the keyvalue really necesary? I highly recommend to type your stuff, avoid any
PS.: Your Lamba function likely looks like this (much shorter)
#GET
#Produces({ "application/json" })
public List<CarDto> getCars() {
return carDao.getCars().stream().map(car => new CarDto(car)).collect(Collectors.toList());
}
Here is error
<div *ngFor="let all of response2 | keyvalue">
change to
<div *ngIf="response">
<table>
<ul class="heroes">
<tr>
<td>ID</td>
<td>Brand</td>
<td>Color</td>
<td>Year</td>
<td>Price</td>
<td>Sold</td>
</tr>
<tr>
<div *ngFor="let respone_one of response | keyvalue">
<td><li>{{respone_one?.caId}}</li></td>
<td><li>{{respone_one?.brand}}</li></td>
<td><li>{{respone_one?.color}}</li></td>
<td><li>{{respone_one?.year}}</li></td>
<td><li>{{respone_one?.price}}</li></td>
<td><li>{{respone_one?.sold}}</li></td>
</div>
</tr>
</ul>
</table>
</div>
Your issue comes from the ngFor let all of response | keyvalue. The values you are looking for are in the all reference, not response.
Try this:
<div *ngFor="let all of response | keyvalue">
<td><li>{{all?.caId}}</li></td>
<td><li>{{all?.brand}}</li></td>
<td><li>{{all?.color}}</li></td>
<td><li>{{all?.year}}</li></td>
<td><li>{{all?.price}}</li></td>
<td><li>{{all?.sold}}</li></td>
</div>
Related
I'm currently developing an online banking application where you can buy stocks. It is being built with spring boot and the front-end is html/css.
I am using the YahooFinance API to get stock quotes but I need to refresh my page to get the live stock quotes, how can I automatically update the page every 30 seconds to get the new prices for each stock?
Also, is there a way I could implement this using Threads?
Banking Controller
#GetMapping("/banking/stocks")
public String stocks(Model model) {
model.addAttribute("stock", new StockDto());
try {
List<Stock> stocks = stockService.getDefaultStocks();
model.addAttribute("stocks", stocks);
} catch (IOException e) {
e.printStackTrace();
}
return "stocks.html";
}
StockServiceImpl:
#Service
public class StockServiceImpl implements StockService {
private String[] startingStocks = { "AAPL", "BABA", "MSFT", "AXP", "BA", "AMD", "TSLA", "MA", "SHOP", "GOOGL",
"KL" };
#Override
public Stock getStock(String stockName) throws IOException {
Stock stock = YahooFinance.get(stockName);
return stock;
}
#Override
public Map<String, Stock> getStock(String[] s) throws IOException {
Map<String, Stock> stocks = YahooFinance.get(s);
return stocks;
}
#Override
public List<Stock> getDefaultStocks() throws IOException {
Map<String, Stock> stocks = YahooFinance.get(startingStocks);
List<Stock> stockList = new ArrayList<Stock>();
for(String s : startingStocks) {
stockList.add(stocks.get(s));
}
return stockList;
}
}
HTML Page For Displaying Stocks:
<main class='main-content bgc-grey-100'>
<div id='mainContent'>
<div class="container-fluid">
<br>
<h4 class="c-grey-900 mT-10 mB-30">Stock Table</h4>
<form action="#" th:object="${stock}" th:action="#{/banking/stock-search}"
method="POST" class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search"
th:field="*{name}" placeholder="Search Stock"
aria-label="Search">
<button class="btn btn-outline-primary my-2 my-sm-0" type="submit">Search</button>
</form>
<br>
<div class="row">
<div class="col-md-12">
<div class="bgc-white bd bdrs-3 p-20 mB-20">
<table id="dataTable" class="table table-striped table-bordered"
cellspacing="0" width="100%">
<thead>
<tr>
<th>Ticker</th>
<th>Trade</th>
<th>Name</th>
<th>Price</th>
<th>(%) Change</th>
<th>Div Yield (%)</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Ticker</th>
<th>Trade</th>
<th>Name</th>
<th>Price</th>
<th>(%) Change</th>
<th>Div Yield (%)</th>
</tr>
</tfoot>
<tbody>
<tr th:each="stock : ${stocks}">
<td th:text="${stock.getSymbol()}"></td>
<td>
<form action="#" th:action="#{/banking/stocks/} + ${stock.symbol}" method="get">
<button class="btn btn-outline-success my-2 my-sm-0" th:id="'table_entry_childs_button_' + ${stock.symbol}" type="submit">
<i>Trade</i>
</button>
</form>
</td>
<td th:text="${stock.getName()}"></td>
<td th:text="${stock.getQuote().getPrice()}"></td>
<td th:class="${stock.getQuote().getChangeInPercent() > 0 ? 'text-success' : 'text-danger'}" th:text="${stock.getQuote().getChangeInPercent() + '%'} "></td>
<td th:if="${stock.getDividend().getAnnualYield() != null}" th:text="${stock.getDividend().getAnnualYield() + '%'}">0.00%</td>
<td th:if="${stock.getDividend().getAnnualYield() == null}" >0.00%</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</main>
You can exploit STOMP protocol and web sockets using spring boot.
For reference:
https://www.baeldung.com/spring-websockets-send-message-to-user
on back end side you can use
#Autowired
SimpMessagingTemplate messagetemplate;
public void somemethod(String strParam){
while (true){
// build string or json whatever you need to send
messagetemplate.convertAndSend("/blabla/blabla",strParam);
Thread.sleep(30*1000);
}
}
on front end side you have to use stomp.js
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.js">
<script type="text/javascript">
function load(){
var stompClient = Stomp.client("ws://localhost:8080/ws");
stompClient.connect({}, function (frame) {
stompClient.subscribe('/blabla/blabla', function (message) {
// do something here
});
});
}
lastly, part of html where you want to call on load
<html>
<body onload="load()">
</body>
</html>
You can create an #Scheduled method that can call this API request every 30 seconds to get data and update your Front-End.
#Scheduled(fixedRate = 30000)
public void updateStocksElement() {
//Call your /banking/stocks rest endpoint
}
https://spring.io/guides/gs/scheduling-tasks/
I am following given link to submit table data to be saved in database
http://viralpatel.net/blogs/spring-mvc-multi-row-submit-java-list/
But the difference between given link and my implementation is that the front-end of link uses JSTL (JSP) while i am using Thymeleaf (HTML)
Below are the files being used
HTML Form :
<form method="POST" th:action="#{/updateAllRules}" th:field="${ruleForm}">
<table>
<thead>
<tr>
<th>S No</th>
<th>Title</th>
<th>Body</th>
</tr>
</thead>
<tbody>
<tr th:each="ruleModel,iteration : ${allRules}">
<td th:text="${ruleModel.id}"></td>
<td><input type="text" th:name="${'rule'+iteration.index+'.title'}" th:value="${ruleModel.title}"></td>
<td><input type="text" th:name="${'rule'+iteration.index+'.body'}" th:value="${ruleModel.body}"></td>
</tr>
</tbody>
</table>
<br>
<input type="submit" value="Update All">
</form>
Model Class :
public class Rule {
private Integer id;
private Date timestamp;
private String title;
private String body;
// constructor and Getter/Setters
}
Form Class :
public class RuleForm {
private List<Rule> rule;
public List<Rule> getRule() {
return rule;
}
public void setRule(List<Rule> rule) {
this.rule = rule;
}
}
Controller Method :
#RequestMapping(value = "/updateAllRules", method = RequestMethod.POST)
public String updateAllRules(#ModelAttribute("ruleForm") RuleForm ruleForm) throws IOException
{
System.out.println(ruleForm); // this prints com.web.model.RuleForm#235f9fcb
System.out.println(ruleForm.getRule()); //this prints null
return "redirect:/admin";
}
Please let me know what i am missing.
UPDATE 1:
Made changes as suggested. My new HTML form is as below
<form method="POST" th:action="#{/updateAllRules}" th:object="${ruleForm}">
<table>
<thead>
<tr>
<th>S No</th>
<th>Title</th>
<th>Body</th>
</tr>
</thead>
<tbody>
<tr th:each="rule,iteration : ${ruleForm}">
<td th:field="*{rule[__${iteration.index}__].id}"></td>
<td><input type="text" th:field="*{rule[__${iteration.index}__].title}"></td>
<td><input type="text" th:field="*{rule[__${iteration.index}__].body}"></td>
</tr>
</tbody>
</table>
<br>
<input type="submit" value="Update All">
</form>
On making these changes following exception is being received when the page loads.
org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'rule' cannot be found on object of type 'java.util.ArrayList' - maybe not public?
Please see that i am sending original list in model attribute "ruleForm" on page load. Once page loads the data and user make changes , i want to POST complete table back to controller.
Forms should have a th:object, rather than a th:field:
<form method="POST" th:action="#{/updateAllRules}" th:object="${ruleForm}">
Instead of using th:name and th:value, you should instead be using th:field which does both of those for you. Fields also should be specified using the *{...} syntax, which assumes the th:object automatically.
<input type="text" th:field="*{rule[__${iteration.index}__].title}" />
Everything else looks correct to me.
I have got a html page (with Thymeleaf):
<form action="#" th:action="#{/changeme}">
<fieldset>
<table style="width: 500px">
<tr th:each="esfield : ${esfields}">
<td>
<div>
<div class="checkbox">
<input type="checkbox" name="optionsMulti"
th:text="${esfield}" />
</div>
</div>
</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td>
<button type="submit"
class="btn btn-xs btn-primary margin10-right paddingNew"
name="save">Calculate!</button>
</td>
<td></td>
</tr>
</table>
</fieldset>
</form>
When I click Calculate! it goes to my controller
#RequestMapping(value = "/changeme", params = { "save" })
public String save(final ModelMap m) {
m.addAttribute("centers", /*params*/);
return "clustering";
}
I would like to get information about checked boxes in my controller?
How can I do that?
Thank you in advance
You have basically two options :
either you use a different name for each checkbox
or you use spring tag <form:checkbox> instead of native <checkbox>
If you don't posted data will not allow you to know exactly what boxes were actually checked (excepted in cases all and none)
With the approach, you should use in your controller a #ModelAttribute annotated object containing a List<Boolean> and spring will automagically populate it with the values of your checkboxes.
#RequestMapping(value = "/changeme", params = { "save" })
public String save(#ModelAttribute BoxesForm form, final ModelMap m) {
// do what you need with form.getCheckboxes() ...
m.addAttribute("centers", /*params*/);
return "clustering";
}
public class BoxesForm {
List<Boolean> checkboxes;
// getter and setter omitted ...
}
Can anyone guide me how can i call a jsp/html page using ajax in play framework?
I want to open a lightbox on click of a button and want to load that with a page containing data from database.
Currently i have just displayed the message using ajax. Below is the method inApplication.java
public static Result index()
{
return ok(index.render("Your new application is ready."));
}
My index.scala.html is:
#(products: List[Products])
#import helper._
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<h1>#products.size() product(s)</h1>
<table border=1>
<tr>
<td>Product Name</td>
<td>Quantity</td>
<td>Price</td>
</tr>
#for(product <- products) {
<tr>
<td>
#product.productname
</td>
<td>
#product.quantity
</td>
<td>
#product.price
</td>
<td id="items">
<input type="button" value="Add Product" name="#routes.Application.user(product.product_id)" id="but"/>
</td>
</tr>
}
</table>
<div class="result1" style="border: 1px solid black; padding: 5px;">not sent yet...</div>
<script type="text/javascript">
jQuery("#items a").click(
function () {
$.get(jQuery(this).attr("href"), function (data) {
$('.result').html(data);
});
return false;
}
)
</script>
You are on the good way.
Create a new action which will return only the html you need in your div (and not the complete html page).
public static Result detail(Integer productId)
{
Product product = .... (productId);
return ok(productDetail.render(product));
}
// with the route of course
productDetail.scala.html
#(product: Product)
My product #product.product_id is beautiful !
....
You must also add a jquery plugin to display your lightbox (there are a thousand...)
Your JsCode will be something like that:
$("#items a").click(function () {
$("#result").load($(this).attr("href"), function() {
displayPopup(); // code this
});
});
(Or maybe a totally different code if the plugin natively handle ajax...)
In resume, there is a lot of work to do, and many ways to do it.
Just try !
I have a problem where in i have to fetch the particular data of row on clicking that particular rows button and have to display that data via ajax on the same page.
Here is the code of index.scala.html:
#(products: List[Products])
#import helper._
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<h1>#products.size() product(s)</h1>
<table border=1>
<tr>
<td>Product Name</td>
<td>Quantity</td>
<td>Price</td>
</tr>
#for(product <- products) {
<tr>
<td>
#product.productname
</td>
<td>
#product.quantity
</td>
<td>
#product.price
</td>
<td>
<input type="button" value="Add Product" name="#routes.Application.user(#product.product_id)" id="but"/>
</td>
</tr>
}
</table>
<div class="result" style="border: 1px solid black; padding: 5px;">not sent yet...</div>
<script type="text/javascript">
jQuery("#but").click(
function () {
$.get(jQuery(this).attr("name"), function (data) {
$('.result').html(data);
});
return false;
}
)
</script>
My Application.java contains the method as shown below:
public static Result user( id){
return ok("Play's controller told that you're about to get data for user no. "+id);
}
The problem i am facing is in the line:
**<input type="button" value="Add Product" name="#routes.Application.user(#product.product_id)" id="but"/>**
Error is: Compilation error
illegal start of simple expression
Can anyone please help to load the dymanic data.
Please remove the second #:
#routes.Application.user(product.product_id)
The second one is not needed, since the first indicates that you're in the templating language.