Java - Getting null values in object properties when passing "this" - java

I've been working through the book "Play for Java", which is absolutely brilliant. I'm still fairly new to Java but I've been following the examples and I'm a bit stuck on Chapter 3. The code can be found here: Play for Java on GitHub.
The issue is that when I execute boundform.get(), the actual properties of the form don't seem to be making it into the "product" object. I've paused this in Eclipse's debugger and all of the values are correctly set at the line Form<Product> boundForm = productForm.bindFromRequest(); but then they just disappear by the time I get to product.save().
My controller, model, routes, and form are shown below. Please let me know if any additional information is needed.
Products.java (controller)
package controllers;
import models.Product;
import play.data.Form;
import play.mvc.Result;
import play.mvc.Controller;
import views.html.products.*;
import java.util.List;
public class Products extends Controller {
private static final Form<Product> productForm = Form.form(Product.class);
public static Result list() {
List<Product> products = Product.findAll();
return ok(list.render(products));
}
public static Result newProduct() {
return ok(details.render(productForm));
}
public static Result details(String ean) {
return TODO;
}
public static Result save() {
Form<Product> boundForm = productForm.bindFromRequest();
Product product = boundForm.get();
product.save();
return ok(String.format("Saved product %s", product));
}
}
Product.java (model)
package models;
import java.util.ArrayList;
import java.util.List;
public class Product {
public String ean;
public String name;
public String description;
public Product() {
}
public Product(String ean, String name, String description) {
this.ean = ean;
this.name = name;
this.description = description;
}
public String toString() {
return String.format("%s - %s", this.ean, this.name);
}
private static List<Product> products;
static {
products = new ArrayList<Product>();
products.add(new Product("1111111111111", "Paperclips 1",
"Paperclips description 1"));
products.add(new Product("2222222222222", "Paperclips 2",
"Paperclips description "));
products.add(new Product("3333333333333", "Paperclips 3",
"Paperclips description 3"));
products.add(new Product("4444444444444", "Paperclips 4",
"Paperclips description 4"));
products.add(new Product("5555555555555", "Paperclips 5",
"Paperclips description 5"));
}
public static List<Product> findAll() {
return new ArrayList<Product>(products);
}
public static Product findByEan(String ean) {
for (Product candidate : products) {
if (candidate.ean.equals(ean)) {
return candidate;
}
}
return null;
}
public static List<Product> findByName(String term) {
final List<Product> results = new ArrayList<Product>();
for (Product candidate : products) {
if (candidate.name.toLowerCase().contains(term.toLowerCase())) {
results.add(candidate);
}
}
return results;
}
public static boolean remove(Product product) {
return products.remove(product);
}
public void save() {
products.remove(findByEan(this.ean));
products.add(this);
}
}
Routes
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~
# Home page
GET / controllers.Application.index()
GET /products/ controllers.Products.list()
GET /products/new controllers.Products.newProduct()
GET /products/:ean controllers.Products.details(ean: String)
POST /products/ controllers.Products.save()
# Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.at(path="/public", file)
details.scala.html
#(productForm: Form[Product])
#import helper._
#import helper.twitterBootstrap._
#main("Product form") {
<h1>Product form</h1>
#helper.form(action = routes.Products.save()) {
<fieldset>
<legend>Product (#productForm("name").valueOr("New"))</legend>
#helper.inputText(productForm("ean"), '_label -> "EAN")
#helper.inputText(productForm("name"),'_label -> "Name")
#helper.textarea(productForm("description"), '_label -> "Description")
</fieldset>
<input type="submit" class="btn btn-primary" value="Save">
<a class="btn" href="#routes.Application.index()">Cancel</a>
}
}
I'm sure this is something painfully obvious. Thank you so much!

See the documentation's Handling Binding Failure section. Calling .get() on a Form isn't safe, because if there are validation errors it will return null. The preferred way is to check for errors first via hasErrors(), and then handle it from there.
if (boundform.hasErrors()) {
/* There are errors somewhere in the form,
* return it to the view and display them there,
* or do whatever else you need to handle the error.
*/
return badRequest(...);
} else {
// A valid `Product`, proceed as normal.
Product product = boundform.get();
return ok(....);
}

SBT cache issue. I ran activator clean and everything worked.
I started pasting entire files from the GitHub repo to see if I could narrow it down. That led to a new set of errors which brought me to this StackOverflow question which had the SBT cache suggestion in the thread.
I appreciate the suggestion and link to the error methods, LimbSoup. Will definitely be looking into those regardless and am sure I'll probably reference your answer in the future more than once!
Thanks so much, all.

Related

How to read GraphQL query result in Quarkus Application

I am very new to GraphQL and Quarkus. I have managed to run a quarkus application with GraphQL
following this link
I have the following classes:
Hero.java
package org.acme;
import java.util.*;
public class Hero {
public String name;
public String surname;
public Double height;
public Integer mass;
public Boolean darkSide;
public LightSaber lightSaber;
public static List<Integer> episodeIds = new ArrayList<>();
}
Film.java
package org.acme;
import java.time.LocalDate;
public class Film {
public String title;
public Integer episodeID;
public String director;
public LocalDate releaseDate;
}
Main file where I am defining the query:
package org.acme;
import java.util.List;
import javax.inject.Inject;
import org.eclipse.microprofile.graphql.*;
import io.vertx.core.http.impl.ServerWebSocketImpl;
#GraphQLApi
public class FilmResources {
#Inject
GalaxyService service;
#Query("allFilms")
#Description("Get all Films from a galaxy far far away")
public List<Film> getAllFilms() {
return service.getAllFilms();
}
#Query("allHeroes")
#Description("Get all heroes name")
public List<Hero> getAllHeroes()
{
return service.getAllHeroes();
}
#Query("getFilm")
#Description("Get a film by it's id")
public Film getFilm(#Name("filmId") int id)
{
return service.getFilm(id);
}
// #Query("getFilmHeroes")
// #Description("Get heroes by film specified")
public List<Hero> heroes(#Source Film film) {
return service.getHeroesByFilm(film);
}
}
I run the following query on GraphQL Ui http://localhost:8080/q/graphql-ui:
query getFilmHeroes {
getFilm(filmId: 1) {
title
director
releaseDate
episodeID
heroes {
name
height
mass
darkSide
lightSaber
}
}
}
And I get the following json:
{
"data": {
"getFilm": {
"title": "The Empire Strikes Back",
"director": "George Lucas",
"releaseDate": "1980-05-21",
"episodeID": 5,
"heroes": [
{
"name": "Luke",
"height": 1.7,
"mass": 73,
"darkSide": false,
"lightSaber": "GREEN"
},
{
"name": "Leia",
"height": 1.5,
"mass": 51,
"darkSide": false,
"lightSaber": null
},
{
"name": "Darth",
"height": 1.9,
"mass": 89,
"darkSide": true,
"lightSaber": "RED"
}
]
}
}
}
My question where does the result of the query (this json file) is located? How can I read it in my program. Please refer me to some reading material or the steps I need to follow to read this query in my program.
GraphQL Query and result looks like this
Quarkus Setup looks like this
What you've been playing with is the server-side Quarkus extension for GraphQL. But Quarkus also has a client-side extension: quarkus-smallrye-graphql. That offers a library that can call remote (or local...) GraphQL servers and lets you work with the results programmatically. The guide for trying it is at https://quarkus.io/guides/smallrye-graphql-client - give it a try!

Java Tapestry Autocomplete typeahead include ID on listing

I have a textfield which uses autocomplete mixin on tapestry. The mixin is working fine as it is, but I am having a problem with tagging the values of list of names with duplicate values. Now I am wondering if I can somehow pass the id of the data on autocomplete upon selection.
Here is my code for pupulating the list.
List<String> onProvideCompletionsFromUserName(String partial) {
List<String> matches = new ArrayList<String>();
String partialUpper = partial.toUpperCase();
List<User> users = clientFinder.findUsers();
// int i = 0;
for (User user : users){
String name = NameUtil.toName(user.getFirstName(), user.getFamilyName());
if (name.toUpperCase().contains(partialUpper)) {
matches.add(name );
// if (i++ >= 5) {
// break;
// }
}
}
return matches;
}
Is there a way for me to pass the ID with the list like
(List onProvideCompletionsFromUserName)?
Has anyone encountered this problem as well ? Thanks for your response.
The only way I was able to do it was by extending the Autocomplete mixin with my own version, as the configure method in the mixin is marked protected. Here is my class. Note that I am firing my own event. You will have to give your own values for label, value and uid in the providecompletions handler. The zone parameter is the zone you want to update when the user clicks and item in the completion list.
Mixin:
import java.util.ArrayList;
import java.util.List;
import org.apache.tapestry5.BindingConstants;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.annotations.OnEvent;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.json.JSONLiteral;
import org.apache.tapestry5.json.JSONObject;
import org.got5.tapestry5.jquery.mixins.Autocomplete;
public class UserAutocomplete extends Autocomplete {
public static final String CHANGE_EVENT_NAME = "autocompleteUser";
#Inject
private ComponentResources resources;
#Parameter(defaultPrefix=BindingConstants.LITERAL)
private String zone;
#OnEvent(value = "provideCompletions")
public List<JSONObject> autoComplete(String query) {
List<JSONObject> strings = new ArrayList<JSONObject>();
if(query != null) {
for(User u : service.searchUsers(query.trim())) {
JSONObject so = new JSONObject();
String name = u.getName();
so.put("label", name);
so.put("value", name);
so.put("uid", u.getId());
strings.add(so);
}
}
return strings;
}
protected void configure(JSONObject config) {
config.put("url", resources.createEventLink("autocomplete").toURI());
String url = resources.createEventLink(CHANGE_EVENT_NAME).toURI();
config.put("options", new JSONObject().put("select", new JSONLiteral("function(e, d) {var zone = $('#" + zone + "'); if (!zone) { return; } "
+ "zone.tapestryZone('update', {url: '" + url + "'+'/'+d.item.uid});}")));
}
}
Page Template:
<t:textfield value="query" autocomplete="off" t:mixins="UserAutocomplete" t:zone="resultZone" />
Page Class:
...
#InjectComponent
private Zone resultZone;
#OnEvent(value = UserAutocomplete.CHANGE_EVENT_NAME)
void userChange(Integer id) {
User selectedUser = service.findUser(id);
renderer.addRender(resultZone);
}

How to call action after selecting values from dynamically created dropdown list using struts2

Here I have created dynamic dropdown list using this link, but when I select some value from available list it should be called in action class.
The dropdown list which can be seen in the image ,here the values are loaded dynamically from the database and now what I want is when I select any value from that two dropdown list that values (I mean text value) should be sent to the action class and there I will execute one JDBC select query on the basis of this two values and will display in the table shown in the image but everything should be on load.Action should be on selecting values from dropdown list not on any button click .With static values I am able to call value from dropdown list into action class with name attribute.But in this case I cannot :(
I hope I am clear now .
I have tried calling select tag using listkey,name and id but none of them worked .
Below is my JSP code:
<div>
<div class="invoicetext1">Event Name :</div>
<s:select name="dp.eventState"
list="%{state}"
class="billlistbox1"
id="eventName" />
<div>
<s:select name="dp.companyState"
class="billlistbox2"
listKey="companyState"
list="%{status}">
</s:select>
</div>
<div class="invoicetext2">Company Name :</div>
<div class="clear"></div>
</div>
<s:form action="ActionSelect">
<s:submit value=" Click Here"/>
</s:form>
<div>
Action class for loading dynamic dropdown list :
package com.ca.actions;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import com.ca.database.Database;
import com.ca.pojo.Event;
import java.sql.PreparedStatement;
import com.opensymphony.xwork2.ActionSupport;
public class RetrieveEvNaCoNaAction extends ActionSupport {
private static final long serialVersionUID = -5418233715172672477L;
List<Event> dataForBillsJspList;
private List state = new ArrayList();
private List status = new ArrayList();
String eventName;
public String getEventName() {
return eventName;
}
public void setEventName(String eventName) {
this.eventName = eventName;
}
public RetrieveEvNaCoNaAction() {
// TODO Auto-generated constructor stub
}
public List<Event> getDataForBillsJspList() {
return dataForBillsJspList;
}
public void setDataForBillsJspList(List<Event> dataForBillsJspList) {
this.dataForBillsJspList = dataForBillsJspList;
}
public List getStatus() {
return status;
}
public void setStatus(List status) {
try {
Database database = new Database();
Connection con = database.Get_Connection();
PreparedStatement ps = con
.prepareStatement("SELECT EVENT_NAME,COMPANY_NAME,date_format(FROM_DATE,'%d/%m/%Y') as dateAsFrom,date_format(TO_DATE,'%d/%m/%Y') as dateAsTo FROM EVENT");
ResultSet rs = ps.executeQuery();
//dataForBillsJspList = new ArrayList<Event>();
while (rs.next()) {
/*dataForBillsJspList.add(new Event(rs.getString("EVENT_NAME"),
rs.getString("COMPANY_NAME"), rs
.getString("dateAsFrom"), rs
.getString("dateAsTo")));
System.out.println(rs.getString("EVENT_NAME"));*/
status.add(rs.getString("COMPANY_NAME"));
}
System.out.println("Data Collected ...");
}catch(Exception e)
{
e.printStackTrace();
}
}
public List getState() {
return state;
}
#Override
public String execute() throws Exception {
// TODO Auto-generated method stub
setState(this.state);
setStatus(this.status);
return "success";
}
public String showEventDetails(){
System.out.println("Hi.."+eventName);
return SUCCESS;
}
public void setState(List state) {
//implement the application specific logic to
try {
Database database = new Database();
Connection con = database.Get_Connection();
PreparedStatement ps = con
.prepareStatement("SELECT EVENT_ID,EVENT_NAME,COMPANY_NAME,CONTACT_PERSON,CONTACT_NO,EMAIL_ID,EVENT_VENUE,date_format(FROM_DATE,'%d/%m/%Y') as dateAsFrom,date_format(TO_DATE,'%d/%m/%Y') as dateAsTo ,EVENT_TIME FROM EVENT");
ResultSet rs = ps.executeQuery();
dataForBillsJspList = new ArrayList<Event>();
while (rs.next()) {
dataForBillsJspList.add(new Event(rs.getString("EVENT_ID"),rs.getString("EVENT_NAME"),
rs.getString("COMPANY_NAME"),rs.getString("CONTACT_PERSON"),rs.getString("CONTACT_NO"),rs.getString("EMAIL_ID"),rs.getString("EVENT_VENUE"), rs
.getString("dateAsFrom"), rs
.getString("dateAsTo"),rs.getString("EVENT_TIME")));
//System.out.println(rs.getString("EVENT_NAME"));
state.add(rs.getString("EVENT_NAME"));
System.out.println(rs.getString("EVENT_ID"));
}
System.out.println("Data Collected ...");
}catch(Exception e)
{
e.printStackTrace();
}
//Here for displaying the data on UI, we are using few hardcoded values//
}
}
After loading dynamic dropdown list now i am trying to call selected value in action class by S.O.P but it gives null pointer exception. Below is my POJO class:
package com.ca.pojo;
public class Dropdown
{
private String eventState;
private String companyState;
public Dropdown() {
// TODO Auto-generated constructor stub
}
public String getEventState() {
return eventState;
}
public void setEventState(String eventState) {
this.eventState = eventState;
}
public String getCompanyState() {
return companyState;
}
public void setCompanyState(String companyState) {
this.companyState = companyState;
}
}
and below is action class where I am trying to call that selected value by using name attribute :
package com.ca.actions;
import com.ca.pojo.Dropdown;
import com.opensymphony.xwork2.ActionSupport;
public class DropdownAction extends ActionSupport
{
Dropdown dp;
public DropdownAction() {
// TODO Auto-generated constructor stub
}
public Dropdown getDp() {
return dp;
}
public void setDp(Dropdown dp) {
this.dp = dp;
}
#Override
public String execute() throws Exception {
// TODO Auto-generated method stub
System.out.println(dp.getEventState());
return "success";
}
}
struts.xml is properly configured. Now after selecting two values I want to display data in the below table accordingly without any button click but in jsp i have created button just to see whether i am getting the selected value in action class but in actual i want it without any button click.
Well, there is a huge mess here :D
First of all, the NullPointerException is thrown because the values are not sent, and the values are not sent because they're not in the form.
You should enclose them in the form like this for them to be sent to the ActionSelect action:
<s:form action="ActionSelect">
<div class="invoicetext1">Event Name :</div>
<s:select name="dp.eventState"
list="%{state}"
class="billlistbox1"
id="eventName" />
<div>
<s:select name="dp.companyState"
class="billlistbox2"
listKey="companyState"
list="%{status}">
</s:select>
</div>
<div class="invoicetext2">Company Name :</div>
<div class="clear"></div>
</div>
<s:submit value=" Click Here"/>
</s:form>
Solved the mistery, this doesn't solve your problem, though.
You have two main ways to contact actions from a page:
Using a standard submit (as you're doing):
you either submit a form with its content, or call a link by eventually passing parameters in the querystring. This creates a Request, that will contact an action, that will return an entire JSP, that will be loaded in place of the page you're on now.
Using AJAX:
you POST or GET to an action without changing the current page, and the action can return anything, like a JSP snippet, a JSON result, a binary result (through the Struts2 Stream result), etc...
You then can choose what to do with the returned data, for example load it inside a <div> that before was empty, or had different content.
Now your problem is that you're contacting an action that is not the one you're coming from (is not able to re-render the entire JSP you're on) and you're calling it without using AJAX, then whatever the object mapped to the "success" result is (the whole JSP, or a JSP snippet), it will be loaded in place of the JSP you're on, and it will fail.
Since you seem to be quite new to this, I suggest you start with the easy solution (without AJAX), and after being expert with it, the next time try with AJAX.
That said,
avoid putting logic in getters and setters;
avoid calling methods that are not setter as setters (setState, setStatus...);
always make your attributes private;
try giving speaking names to variables: state and status for event states and company states are really confusing; and what about "state" instead of "name" (in jsp and on DB is "name");
consider loading informations like selectbox content in a prepare() method, so they will be available also in case of errors;
you're not closing the connections (and BTW it would be better to use something more evoluted, like Spring JDBC, or better Hibernate, or even better JPA, but for now keep going with the raw queries)
The following is a refactoring of your code to make it achieve the goal. I'll use #Getter and #Setter only for syntactic sugar (they're Lombok annotations, but you keep using your getters and setters, it's just for clarity):
<head>
<script>
$(function(){
$("#event, #company").on('change',function(){
$("#myForm").submit();
});
});
</script>
</head>
<body>
<form id="myForm">
<div>
...
<s:select id="event" name="event" list="events" />
...
<s:select id="company" name="company" list="companies" />
...
</div>
</form>
<div>
...
Table - iterate **dataForBillsJspList** here
...
</div>
</body>
public class RetrieveEvNaCoNaAction extends ActionSupport {
private static final long serialVersionUID = -5418233715172672477L;
#Getter private List<Event> dataForBillsJspList = new ArrayList<Event>();
#Getter private List<String> events = new ArrayList<String>();
#Getter private List<String> companies = new ArrayList<String>();
#Getter #Setter private String event = null;
#Getter #Setter private String company = null;
#Override
public void prepare() throws Exception {
Connection con;
try {
con = new Database().Get_Connection();
// load companies
PreparedStatement ps = con.prepareStatement("SELECT DISTINCT company_name FROM event");
ResultSet rs = ps.executeQuery();
while (rs.next()) { companies.add(rs.getString("company_name")); }
// load events
ps = con.prepareStatement("SELECT DISTINCT event_name FROM event");
rs = ps.executeQuery();
while (rs.next()) { events.add(rs.getString("event_name")); }
} catch(Exception e) {
e.printStackTrace();
} finally {
con.close();
}
}
#Override
public String execute() {
Connection con;
try {
con = new Database().Get_Connection();
// load the table. The first time the table is loaded completely
String sql = "SELECT EVENT_ID, EVENT_NAME, COMPANY_NAME, CONTACT_PERSON, CONTACT_NO, EMAIL_ID, EVENT_VENUE, " +
"date_format(FROM_DATE,'%d/%m/%Y') as dateAsFrom, date_format(TO_DATE,'%d/%m/%Y') as dateAsTo ,EVENT_TIME " +
"FROM event";
String where = "";
// if instead this action has been called from the JSP page,
// the result is filtered on event and company:
if (event!=null && company!=null) {
where = " WHERE event_name = ? AND company_name = ?";
}
// load companies
PreparedStatement ps = con.prepareStatement(sql + where);
if (where.length()>0) {
ps.setString(1,event);
ps.setString(2,company);
}
ResultSet rs = ps.executeQuery();
while (rs.next()) {
dataForBillsJspList.add(new Event(rs.getString("EVENT_ID"),rs.getString("EVENT_NAME"),rs.getString("COMPANY_NAME"),
rs.getString("CONTACT_PERSON"),rs.getString("CONTACT_NO"),rs.getString("EMAIL_ID"),
rs.getString("EVENT_VENUE"), rs.getString("dateAsFrom"), rs.getString("dateAsTo"),
rs.getString("EVENT_TIME")));
}
} catch(Exception e) {
e.printStackTrace();
} finally {
con.close();
}
return SUCCESS;
}
}
It is a kickoff example, but it should work.
The next steps are:
create a POJO with id and description, show the description in the select boxes, but send the id
use header values ("please choose an event"...) and handle in action conditional WHERE (only company, only event, both)
PAGINATION
Good luck
Using Javascript/jQuery you can do this, it depends on what you want to do after reached action class.
If you want to navigate to another page use the code below.
Add onchange event as an attribute to your dropdown,
onchange="customFunction(this.value)"
create customFunction in header part,
function customFunction(selectedValue){
window.location="Action_URL?myValue="+selectedValue;
}
Or if you want to return back the same page use jQuery ajax,
$("#eventName").change(function(e){
var selectedValue = $(this).val();
$.ajax({
type : 'post',
url : 'Action_URL',
data: { myValue: selectedValue},
success : function(data) {
alert(data);
console.log(data);
}
});
});
Hope this helps.

Use a StatelessForm with CheckBox and with data from DB

I want to make a page which displays which Users of my website have the current "Role". Each users have a set of Roles, and a Role is affected to 0 ~ n users.
I'm displaying a basic list with Users's name, and a checkbox for each User. And then a submit button.
When the form is submitted, it will delete the Role from the selected Users.
Most of the time, it's working fine. But there is a problem if the DB' data changed between the page loading and the form submit.
If we are into this situation, it deletes the role from the wrong user!
I've tried different ways, and right now I'm using something like this :
import java.util.LinkedList;
import java.util.List;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.StatelessForm;
import org.apache.wicket.markup.html.list.AbstractItem;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
public class Test extends WebPage {
private static final long serialVersionUID = 1L;
/**
* An item used to link the checkbox to the Database Object
*/
public static class Item {
private boolean selected = false;
private int num;
public Item(final int num) { this.num = num; }
public final boolean isSelected() { return selected; }
public final int getNum() { return num; }
public final void setSelected(boolean selected) { this.selected = selected; }
public final void setNum(int num) { this.num = num; }
}
public Test(final PageParameters params) {
// This list will hold items we display
final List<Item> values = new LinkedList<Item>();
// Our stateless form
final StatelessForm<Void> form = new StatelessForm<Void>("form") {
private static final long serialVersionUID = 1L;
#Override
protected void onSubmit() {
// On submit, we check our items to see which ones are selected
String toDelete = "";
for (final Item it : values) {
if (it.selected) {
toDelete += it.getNum() + ", ";
}
}
System.out.println(toDelete);
}
};
add(form);
form.add(new Button("submit"));
// We retrieve our data from the Database
final List<Integer> things = getFromDatabase();
// We print them
final RepeatingView rp = new RepeatingView("li");
form.add(rp);
for (int num : things) {
final AbstractItem item = new AbstractItem(rp.newChildId());
rp.add(item);
// We create our holder
final Item it = new Item(num);
values.add(it);
item.add(new Label("name", num));
// We use the property of our holder as model
item.add(new CheckBox("checkbox", new PropertyModel<Boolean>(it, "selected")));
}
}
/**
* Simulate a fetch from the database by swapping our data at each requests
*/
public static int num = 0;
private static List<Integer> getFromDatabase() {
final List<Integer> list = new LinkedList<Integer>();
if (num++ %2 == 0) {
list.add(1);
list.add(2);
}
else {
list.add(2);
list.add(1);
}
return list;
}
}
and :
<body>
<form wicket:id="form">
<ul>
<li wicket:id="li">
<span wicket:id="name"></span>
<input type="checkbox" wicket:id="checkbox" />
</li>
</ul>
<input type="submit" valud="submit" wicket:id="submit" />
</form>
</body>
I'm simulating a changing DB by swapping values each time the page is requested.
And what happens is that if I select "1" and press submit, it says that it'll delete "2"!
I understand why, but I've no idea how to fix it.
The best way to fix it would be to have something like this:
<input type="checkbox" name="toDelete[]" value="<the_id>" />
<input type="checkbox" name="toDelete[]" value="<the_id>" />
etc.
But I've no idea how to do it with Wicket, and I can't find anything on the Internet =/
So yeah.. any examples / ideas?

New annoying NPE on Yabe (Creating a custom editor)

I'm winding throught this Yabe tutorial and have been happily get bugs and solving them on my own.... until now.
in
http://localhost:9000/#documentation/guide9
This is the part about customizable edit window..
For whatever reason, when I post a new message, via
http://localhost:9000/admin/new
I receive a null pointer around tags...
In /app/controllers/Admin.java (around line 48)
44: post.content = content;
45: post.tags.clear();
46: }
47: //Set tags list
48: for(String tag : tags.split("\\s+")){
49: if(tag.trim().length() > 0) {
50: post.tags.add(Tag.findOrCreateByName(tag));
51: }
52: }
53: // Validate
54: validation.valid(post);
I looked at Admin.java and Tag.java and compared them line for line with the samples and tests copy. The only difference is an inclusion of validation on aAdmin.java for what I imagine is some test scripts written later down the road..
Any ideas?
here is my admin...
package controllers;
import play.*;
import play.mvc.*;
import java.util.*;
import models.*;
#With(Secure.class)
public class Admin extends Controller {
#Before
static void setConnectedUser() {
if(Security.isConnected()) {
User user = User.find("byEmail", Security.connected()).first();
renderArgs.put("user", user.fullname);
}
}
public static void index() {
List<Post> posts = Post.find("author.email", Security.connected()).fetch();
render(posts);
}
public static void form(Long id) {
if(id != null) {
Post post = Post.findById(id);
render(post);
}
render();
}
public static void save(Long id, String title, String content, String tags) {
Post post;
if(id == null) {
// Create post
User author = User.find("byEmail", Security.connected()).first();
post = new Post(author, title, content);
} else {
// Retrieve post
post = Post.findById(id);
post.title = title;
post.content = content;
post.tags.clear();
}
//Set tags list
for(String tag : tags.split("\\s+")){
if(tag.trim().length() > 0) {
post.tags.add(Tag.findOrCreateByName(tag));
}
}
// Validate
validation.valid(post);
if(validation.hasErrors()) {
render("#form", post);
}
//Save
post.save();
index();
}
}
here is my tag.java
package models;
import java.util.*;
import javax.persistence.*;
import play.db.jpa.*;
import play.data.validation.*;
#Entity
public class Tag extends Model implements Comparable<Tag> {
#Required
public String name;
private Tag(String name) {
this.name = name;
}
public static Tag findOrCreateByName(String name) {
Tag tag = Tag.find("byName", name).first();
if(tag == null) {
tag = new Tag(name);
}
return tag;
}
public static List<Map> getCloud() {
List<Map> result = Tag.find(
"select new map(t.name as tag, count(p.id) as pound) from Post p join p.tags as t group by t.name"
).fetch();
return result;
}
public String toString() {
return name;
}
public int compareTo(Tag otherTag) {
return name.compareTo(otherTag.name);
}
}
In the form that calls the save() method you might be missing an input with name 'tags'. Something like:
<input id="tags" name="tags" type="text" value="" />
In the tutorial there is a template with:
<p>
#{field 'tags'}
<label>Enter some tags:</label>
<input type="text" size="50"
name="${field.name}" value="${post?.tags?.join(' ')}" />
#{/field}
</p>
Check that you have it.

Categories