How to make search result like Google in JSF? - jsf

So, I want to display search result as I type the keyword and change the color of the search result text in JSF like when you use Google to search.
Search example (WhatsApp)
I've done the keyup part but still wonder how to apply highlight text using javascript in JSF.
Here is my xhtml code
<h:form>
<h:outputLabel value="Keyword "/>
<h:inputText id="key" value="#{bookList.keyword}" style="height: 22px">
<f:ajax event="keyup" render="search"/>
</h:inputText>
<h:commandButton value="SEARCH" action="index" styleClass="buttonSearch"/>
</h:form>
<br/>
<h:dataTable value="#{bookList.books}" var="book" id="search"
class="book-table"
headerClass="book-table-header">
<h:column>
#{book.title}
</h:column>
<h:column>
#{book.author}
</h:column>
</h:dataTable>
and this is my java code...
Constructor
public class Book {
private String title;
private String author;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Book(String title, String author){
this.title = title;
this.author = author;
}
}
Data
#ManagedBean
#RequestScoped
public class BookList {
private String keyword = "";
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
private List<Book> books = new ArrayList<Book>(
Arrays.asList(
new Book("My First Learn to Write Workbook", "Crystal Radke"),
new Book("Where the Crawdads Sing", "Delia Owens"),
new Book("Little Fires Everywhere: A Novel", "Celeste Ng"),
new Book("Fortitude: American Resilience in the Era", "Dan Crenshaw"),
new Book("Arguing the Socialists", "Glenn Beck"),
new Book("Hidden Valley Road: Inside the Mind of an American Family", "Robert Kolker")
)
);
public List<Book> getBooks() {
if (keyword.equals("")) {
return books;
} else {
List<Book> listSearch = new ArrayList<Book>();
for(Book book:books){
if(book.getAuthor().toLowerCase().contains(keyword.toLowerCase())
|| book.getTitle().toLowerCase().contains(keyword.toLowerCase())){
listSearch.add(book);
}
}
return listSearch;
}
}
}
Sorry, if my question isn't nice.

Related

Display table titles from nested list shows to much

I'm writing a blog, and I want to display from database dataTable with 2 columns, in one column I would like to have post title, and in other I want post content, but when I try to implement that in my page, the only result I get is that in post title column is displayed all post titles for every row. I would like to ask you, how could I achieve my goal.
Now i have
title1 title2 ... | content1
title1 title2 ... | content2
etc
but I would like to have
title 1| content1 <br>
title2 | content2 <br>
Here is my index.xhtml code to display dataTable
<h:dataTable value="#{postView.postList}"
var="k"
styleClass="table"
headerClass="tableHeader"
rowClasses="tableContent"
>
<h:column>
<h:dataTable value="#{postView.postList}" var="t">
<h:column>
#{t.title}
</h:column>
</h:dataTable>
</h:column>
<h:column>
#{k.postContent}
</h:column>
</h:dataTable>
Here is my controller
package ManagePost;
import Entities.Post;
import FacadeDAO.PostFacade;
import FacadeDAO.UserFacade;
import java.io.Serializable;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
#Named
#ViewScoped
public class PostView implements Serializable {
#Inject
private PostFacade postDAO;
private List<Post> postList;
private String title;
private String content;
public PostView() {
}
public List<Post> getPostList() {
return postList;
}
public void setPostList(List<Post> postList) {
this.postList = postList;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
#PostConstruct
public void init() {
postList = postDAO.showAll();
}
public String validate() {
Post post = postDAO.checkIfExist(title);
if (post == null) {
Post newPost = new Post();
newPost.setTitle(title);
newPost.setPostContent(content);
try {
postDAO.add(newPost);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return "loginPage";
} else {
return null;
}
}
}
And the last, PostDao
public List<Post> showAll() {
List<Post> postList = new ArrayList<>();
List<Post> result = getEntityManager().createNamedQuery("Post.findAll", Post.class).getResultList();
postList.addAll(result);
return postList;
}
You are displaying all the titles in an embedded datatable. You should remove the nested datatable tag:
<h:dataTable value="#{postView.postList}"
var="k"
styleClass="table"
headerClass="tableHeader"
rowClasses="tableContent"
>
<h:column>
#{k.title}
</h:column>
<h:column>
#{k.postContent}
</h:column>
</h:dataTable>

Using P:CommandButton in PrimeFaces

Originally I have this form for user input and do a search.
<h:form id="wordForm">
<h:panelGrid columns="4">
<h:inputText id="word" "
value="#{wordController.word}" />
<h:message for="word" />
<h:commandButton id="search" value="search"
action="#{wordController.search}" />
</h:panelGrid>
</h:form>
Now I want to use PrimeFaces for autocomplete feature, and this is my new form with Autocomplete. How can I replace the new form with the above form?
<h:form>
<p:growl id="msgs" showDetail="true" />
<h:panelGrid columns="2" cellpadding="5">
<p:autoComplete id="wordForm" value="#{autoCompleteView.query}"
completeMethod="#{autoCompleteView.completeQuery}" var="query"
itemLabel="#{query.displayName}" itemValue="#{query}"
converter="queryConverter" forceSelection="true" />
<p:commandButton value="search" oncomplete="PF('dlg').show()" **action="#{wordController.search}"** />
</h:panelGrid>
</h:form>
More specifically, I think I still need to somehow use "action="#{wordController.search}" in P:CommandAction button so that I don't need to change anything else in backend. But How do I pass the query parameter to the "wordController.word" variable? Because now "action="#autoCompleteView.query" takes the user input.
How can I modify this without significant change to current bean code? Do I have to unify the original search bean WordController with the new AutocompleteView bean? because now the user input is accepted into AutoCompleteView bean.
AutoCompleteView.java
#ManagedBean
public class AutoCompleteView {
private Query query;
#ManagedProperty("#{queryService}")
private QueryService service;
private List<Query> selectedQueries;
public List<Query> completeQuery(String query) {
System.out.println(query);
List<Query> allQueries = service.getQueries();
List<Query> filteredQueries = new ArrayList<Query>();
for (int i = 0; i < allQueries.size(); i++) {
Query skin = allQueries.get(i);
if(skin.getName().toLowerCase().contains(query)) {
filteredQueries.add(skin);
}
}
return filteredQueries;
}
public void onItemSelect(SelectEvent event) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Item Selected", event.getObject().toString()));
}
public Query getQuery() {
return query;
}
public void setQuery(Query query) {
this.query = query;
}
public void setService(QueryService service) {
this.service = service;
}
public List<Query> getSelectedQueries() {
return selectedQueries;
}
public void setSelectedQueries(List<Query> selectedQueries) {
this.selectedQueries = selectedQueries;
}
}
Edited per suggestion:
#Named
#RequestScoped
public class WordController {
private String word;
// For AutoComplete suggestions
private Query selectedQuery;
#Inject
private QueryService service;
#Inject
private Word wordObject;
public void search() {
if (word != null && !word.isEmpty()) {
wordObject.searchWord(word);;
...
}else {
System.out.println("Query can't be null!");
}
}
public List<Query> completeQuery(String query) {
List<Query> allQueries = service.getQueries();
List<Query> filteredQueries = new ArrayList<Query>();
for (int i = 0; i < allQueries.size(); i++) {
Query skin = allQueries.get(i);
if(skin.getName().toLowerCase().contains(query)) {
filteredQueries.add(skin);
}
}
return filteredQueries;
}
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
public Query getSelectedQuery() {
return selectedQuery;
}
public void setSelectedQuery(Query selectedQuery) {
this.selectedQuery = selectedQuery;
}
}
Question: Originally, my 'word' is filled through an "h:inputText" in JSF view and search() is called in JSF:
<h:commandButton id="search" value="Search!" action="#{wordController.search}" />
Now, how do I get "selectedQuery" from completeQuery() method, and then use it to fill "word" and then call search() method?

Unable to find matching navigation case with from-view-id '/index.xhtml' for action : JSF

I am getting the following error :
Unable to find matching navigation case with from-view-id '/index.xhtml' for action '#{medcontroller.getMedGeneric}' with outcome 'javax.faces.model.ListDataModel#7a652236'
I am new to jsf and I'm really clueless about solving this error. I have a ManagedBean with the following code:
MedController.java
#ManagedBean(name = "medcontroller")
#SessionScoped
public class MedController implements Serializable {
int startId;
String gName;
int endId;
DataModel medNames;
//DataModel medGeneric;
MedicineHelper helper;
private int recordCount = 1000;
private int pageSize = 10;
private Medicine current;
private int selectedItemIndex;
public MedController() {
helper = new MedicineHelper();
startId = 1;
endId = 10;
}
public MedController(int startId, int endId) {
helper = new MedicineHelper();
this.startId = startId;
this.endId = endId;
}
public Medicine getSelected() {
if (current == null) {
current = new Medicine();
selectedItemIndex = -1;
}
return current;
}
public DataModel getMedNames() {
if (medNames == null) {
medNames = new ListDataModel(helper.getMedNames(startId, endId));
}
return medNames;
}
public String getgName()
{
return gName;
}
public void setgName(String gName)
{
this.gName = gName;
}
public DataModel getMedGeneric() {
if (medNames == null) {
medNames= new ListDataModel(helper.getMedGeneric(gName));
}
return medNames;
}
void recreateModel() {
medNames = null;
}
public boolean isHasNextPage() {
if (endId + pageSize <= recordCount) {
return true;
}
return false;
}
public boolean isHasPreviousPage() {
if (startId-pageSize > 0) {
return true;
}
return false;
}
public String next() {
startId = endId+1;
endId = endId + pageSize;
recreateModel();
return "index";
}
public String previous() {
startId = startId - pageSize;
endId = endId - pageSize;
recreateModel();
return "index";
}
public int getPageSize() {
return pageSize;
}
public String prepareView(){
current = (Medicine) getMedNames().getRowData();
return "browse";
}
public String prepareList(){
recreateModel();
return "index";
}
}
And here is my JSF file
index.xhtml
<ui:define name="body">
<h:form styleClass="jsfcrud_list_form">
<h:commandLink action="#{medcontroller.previous}" value="Previous #{medcontroller.pageSize}" rendered="#{medcontroller.hasPreviousPage}"/>
<h:commandLink action="#{medcontroller.next}" value="Next #{medcontroller.pageSize}" rendered="#{medcontroller.hasNextPage}"/>
<h:dataTable value="#{medcontroller.medNames}" var="item" border="1" cellpadding="15" cellspacing="10" rowClasses="jsfcrud_odd_row,jsfcrud_even_row" rules="all" style="border:solid 1px">
<h:column>
<f:facet name="header">
<h:outputText value="BrandName"/>
</f:facet>
<h:outputText value="#{item.brandName}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Generic"/>
</f:facet>
<h:outputText value="#{item.generic}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value=" "/>
</f:facet>
<h:commandLink action="#{medcontroller.prepareView}" value="View"/>
</h:column>
</h:dataTable>
<h:inputText value="#{medcontroller.gName}" />
<h:commandButton value="Submit" action="#{medcontroller.getMedGeneric}" />
</h:form>
</ui:define>
Please help me solve the error.
Also, I do not have a faces-config.xml file. I am using netbeans ide 7.1.2 web application with jsf and hibernate framework.
Thank you in advance.
The <h:commandButton action> must point to a method which invokes some business logic and returns either void or a String representing the target page you'd like to (re)display. However you returned a whole ListDataModel which isn't making any sense to JSF navigation handler and hence this error.
Something like this should do:
public String getMedGeneric(){
// Do your business logic here.
return "someViewId";
}
This will navigate to someViewId.xhtml. However, if you intend to stick on the same view, just let it return void (or null) and it will redisplay the same view.
public void getMedGeneric(){
// Do your business logic here.
}
By the way, it's really a poor naming convention to prefix action method names with get. This is confusing and makes your code not self-documenting. Rather name it loadMedGeneric() or so. I'm merely guessing as you didn't tell anywhere about the concrete functional requirement, what exactly that button should be doing.
getMedGeneric should return java.lang.String which represent navigation to another page described in faces-config.xml. In your case it return some model so it will not work unfortunatell. Let try to put getMedGeneric() action to actionListener and then in action put navigation String. i.e:
action="navString" actionListener="#{medcontroller.getMedGeneric}"
you should try just
actionListener="#{medcontroller.getMedGeneric}"

JSF display database records on datatable

I've been searching here for hour now and unfortunately I can't how to display database records to datatable, I'm newbie to JSF and I don't know much on JSF right now but I'm building a simple crud application I already know how to create, delete records using JSF but I'm having problem displaying this records to my datatable. I tried creating arraylist, I tried creating another class for this, To make it more clear here is my code:
This is my index.jsf:
<?xml version='1.0' encoding='windows-1252'?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html">
<html xmlns="http://www.w3.org/1999/xhtml">
<h:head></h:head>
<h:body>
Username:
<h:outputText value="#{ backing_index.userName }" id="Username">
<p>
</p>
<p>
</p>
<p>
</p>
</h:outputText>
<p>
RoleI.D:
<h:outputText value="#{backing_index.roleId}" id="RoleID"/>
</p>
Role Description:
<h:outputText value="#{backing_index.roleDesc}" id="Description"/>
<h:dataTable value="#{ backing_index.tableRs }" var="user" rules="rows" cellpadding="7">
<f:facet name="header"></f:facet>
<f:facet name="footer"></f:facet>
<h:column>
<f:facet name="header">ID</f:facet>
#{ user.tableId }
</h:column>
<h:column>
<f:facet name="header">First Name</f:facet>
#{ user.tableFirstName }
</h:column>
<h:column>
<f:facet name="header">Middle Name</f:facet>
#{ user.tableMiddleName }
</h:column>
<h:column>
<f:facet name="header">Last Name</f:facet>
#{ user.tableLastName }
</h:column>
<h:column>
<f:facet name="header">Delete</f:facet>
<h:commandButton action="#{ backing_index.deleteAction }" value="Remove this">
<f:param value="Remove" name="delete" />
</h:commandButton>
</h:column>
</h:dataTable>
</h:body>
</html>
<!--oracle-jdev-comment:auto-binding-backing-bean-name:backing_index-->
</f:view>
Here is my code for the bean:
package view.backing;
import javax.faces.component.html.HtmlOutputText;
import javax.faces.bean.*;
import javax.faces.context.*;
import javax.annotation.*;
import javax.faces.*;
import java.sql.*;
import java.util.*;
#RequestScoped
public class Index {
private Connection con;
private ResultSet rs;
private String userName;
private String roleId;
private String roleDesc;
//Variable of Data Table
private TableUser[] tableRs;
//End of Variable
//Start of getter and setter for Data table
public void setTableRs(Index.TableUser[] tableRs) {
this.tableRs = tableRs;
}
public Index.TableUser[] getTableRs() {
return tableRs;
}
//End of getter and setter
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserName() {
return userName;
}
public void setRoleId(String roleId) {
this.roleId = roleId;
}
public String getRoleId() {
return roleId;
}
public void setRoleDesc(String roleDesc) {
this.roleDesc = roleDesc;
}
public String getRoleDesc() {
return roleDesc;
}
#PostConstruct
public void init()throws SQLException, ClassNotFoundException{
Class.forName("oracle.jdbc.driver.OracleDriver");
con = DriverManager.getConnection("jdbc:oracle:thin:#localhost/XE", "JEROME", "perbert101");
displayUserInfo();
displayTableRecords();
}
private void displayUserInfo()throws SQLException{
FacesContext context = FacesContext.getCurrentInstance();
userName = (String)context.getExternalContext().getSessionMap().get("userName");
roleId = (String)context.getExternalContext().getSessionMap().get("roleId");
Statement state = con.createStatement();
state.executeQuery("SELECT * FROM ROLES WHERE ID = 2");
rs = state.getResultSet();
while(rs.next()){
roleDesc = rs.getString(3);
}
}
private void displayTableRecords()throws SQLException{
String query = "SELECT * FROM USERS";
PreparedStatement state = con.prepareStatement(query);
state.execute();
rs = state.getResultSet();
while(rs.next()){
tableRs = new TableUser[]{new TableUser(rs.getLong(1), rs.getString(2), rs.getString(7), rs.getString(5))};
}
}
//Table Records Store
public static class TableUser{
long tableId;
String tableFirstName;
String tableMiddleName;
String tableLastName;
public TableUser(long tableId, String tableFirstName, String tableMiddleName, String tableLastName){
this.tableId = tableId;
this.tableFirstName = tableFirstName;
this.tableMiddleName = tableMiddleName;
this.tableLastName = tableLastName;
}
public void setTableId(long tableId) {
this.tableId = tableId;
}
public long getTableId() {
return tableId;
}
public void setTableFirstName(String tableFirstName) {
this.tableFirstName = tableFirstName;
}
public String getTableFirstName() {
return tableFirstName;
}
public void setTableMiddleName(String tableMiddleName) {
this.tableMiddleName = tableMiddleName;
}
public String getTableMiddleName() {
return tableMiddleName;
}
public void setTableLastName(String tableLastName) {
this.tableLastName = tableLastName;
}
public String getTableLastName() {
return tableLastName;
}
}
}
I don't have any error or something and it display only the last records in the database. Guys if you know the easiest ways can you teach me how to do it, and I always go for a nice clean, short code. your help is really much appreciated :)
There is a bug in your displayTableRecords() method. Within while loop you instantiate new TableUser array for each iteration. Actually what you should do is add TableUser object one by one to existing array.
Use ArrayList inseadof array.
private List<TableUser> tableRs = new ArrayList<TableUser>();
public List<TableUser> getTableRs() {
return tableRs;
}
public void setTableRs(List<TableUser> tableRs) {
this.tableRs = tableRs;
}
private void displayTableRecords() {
String query = "SELECT * FROM USERS";
PreparedStatement state = con.prepareStatement(query);
state.execute();
rs = state.getResultSet();
while (rs.next()) {
tableRs.add(new TableUser(rs.getLong(1),
rs.getString(2), rs.getString(7), rs.getString(5)));
}
}

DataModel must implement org.primefaces.model.SelectableDataModel when selection is enabled.

I'm trying to create a DataTable with Multiple Row Selection but i'm getting an error here's the link of the tutorial http://www.primefaces.org/showcase/ui/datatableRowSelectionMultiple.jsf :
Here's my xhtml:
<p:dataTable border="1" value="#{projectAdminisrationMB.projectNoUsersList}"
var="userObj"
selection="#
{projectAdminisrationMB.selectedUsers}"
selectionMode="multiple" rowIndexVar="rowIndex"binding="#{table2}">
<p:column id="column3">
<f:facet name="header">
<h:outputText value=" user "></h:outputText>
</f:facet>
<h:outputText value="#{userObj.name}"/>
/
<h:outputText value="#{userObj.lastName}"></h:outputText>
<h:outputText value="#{userObj.firstName}"></h:outputText>
</p:column>
<f:facet name="footer">
<p:commandButton id="addProjectUser" value=" Add " onclick="dlg1.show()" />
<p:commandButton id="deleteProjectUser" value=" Delete " />
</f:facet>
</p:dataTable>
Managed Bean :
#ManagedBean
#SessionScoped
public class ProjectAdminisrationMB implements Serializable {
private static final long serialVersionUID = 1L;
private String projectName;
private List <User> projectUsersList;
private List<User> projectNoUsersList;
private List<User> selectedUsers;
private String projectAdmin;
public ProjectAdminisrationMB() {
super();
AdministrationProjectFinal administrationProjectFinal =new
AdministrationProjectFinal();
this.projectUsersList=administrationProjectFinal.getUserList();
this.projectNoUsersList=administrationProjectFinal.getNotUserList();
}
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public List<User> getProjectUsersList() {
return projectUsersList;
}
public void setProjectUsersList(List<User> projectUsersList) {
this.projectUsersList = projectUsersList;
}
public String getProjectAdmin() {
return projectAdmin;
}
public void setProjectAdmin(String projectAdmin) {
this.projectAdmin = projectAdmin;
}
public List<User> getProjectNoUsersList() {
return projectNoUsersList;
}
public void setProjectNoUsersList(List<User> projectNoUsersList) {
this.projectNoUsersList = projectNoUsersList;
}
public List<User> getSelectedUsers() {
return selectedUsers;
}
public void setSelectedUsers(List<User> selectedUsers) {
this.selectedUsers = selectedUsers;
}
}
i'm getting this error:
javax.faces.FacesException: DataModel must implement
org.primefaces.model.SelectableDataModel when selection is enabled.....
just add this attribute rowKey to the datatable tag :
<p:dataTable border="1" value="#{projectAdminisrationMB.projectNoUsersList}"
var="userObj"
rowKey="#{userObj.name}"selection="#{projectAdminisrationMB.selectedUsers}"
selectionMode="multiple" rowIndexVar="rowIndex"
binding="#{table2}">
You can get this error if you try to add a new item to the underlying list and forget to assign a value to that new item's rowKey.
Alternatively to rowKey you can wrap your data in a custom model which really implements org.primefaces.model.SelectableDataModel. This is helpful if
all of your your classes have the same kind of #Id (e.g. a long) and can implement the same interface (e.g. EjbWithId)
you want to add additional functionalities to your data which are not domain specific and don't belong e.g. User.
The interface may be something like this:
public interface EjbWithId
{
public long getId();
public void setId(long id);
}
Then a generic implementation of SelectableDataModel for all your classes can be used:
public class PrimefacesEjbIdDataModel <T extends EjbWithId>
extends ListDataModel<T> implements SelectableDataModel<T>
{
public PrimefacesEjbIdDataModel(List<T> data)
{
super(data);
}
#Override public T getRowData(String rowKey)
{
List<T> list = (List<T>) getWrappedData();
for(T ejb : list)
{
if(ejb.getId()==(new Integer(rowKey))){return ejb;}
}
return null;
}
#Override public Object getRowKey(T item) {return item.getId();}
}
In your #ManagedBean:
private PrimefacesEjbIdDataModel<User> dmUser; //+getter
dmUser = new PrimefacesEjbIdDataModel<User>(administrationProjectFinal.getUserList());
first check whether you've added
rowKey="#{userObj.id}"
then you need to have the data table List set in filteredValue attribute of your data table in xhtml, instead of value.

Resources