Why can't I use multiple selection with listbox in zk framework? - zk

I followed zk demo to create listbox with multiple selection.
Here is my zul file:
<window title="demo"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns="http://www.zkoss.org/2005/zul"
apply="com.viettel.voffice.controller.ListboxController">
<listbox id="lb" model="${$composer.list}" multiple="true" checkmark="true" mold="paging" pageSize="10">
<listhead>
<listheader label="STT"/>
<listheader label="Name"/>
</listhead>
<template name="model">
<listitem>
<listcell label="${forEachStatus.index}"/>
<listcell label="${each}"/>
</listitem>
</template>
</listbox>
Controller:
public class ListboxController extends SelectorComposer<Component> {
#Wire
private Listbox lb;
private ListModelList list;
#Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
List listData = new BigList(1000);
list = new ListModelList(listData);
lb.setModel(list);
lb.renderAll();
lb.setMultiple(true);
}
#Override
public ComponentInfo doBeforeCompose(Page page, Component parent, ComponentInfo compInfo) {
return super.doBeforeCompose(page, parent, compInfo);
}
public ListModelList getList() {
return list;
}
BigList.java:
public class BigList extends AbstractList<Integer> {
private int size;
public BigList(int sz) {
if (sz < 0) {
throw new IllegalArgumentException("Negative not allowed: " + sz);
}
size = sz;
}
public int size() {
return size;
}
public Integer get(int j) {
return Integer.valueOf(j);
}
}
And here is what zk display:
https://farm4.staticflickr.com/3919/15032438702_fb403efc70_o.png
Why doesn't listbox display multiple selection?
I have just solved it. Just add this line:
model.setMultiple(true);
:D

You made little mistake you have to add this in afterCompose() method
list.setMultiple(true);

Related

From an select item in the list, create another listbox ZK

I had a headache with this. I want to choose a book from the 1st list and with that book create a second list to be able to show the details of the book (title, number of pages)
Here is the code:
public class Book {
private int numBook;
private String nameBook;
private String author;
public Book(int numBook, String nameBook, String author) {
super();
this.numBook = numBook;
this.nameBook = nameBook;
this.author = author;
}
public int getNumBook() {
return numBook;
}
public void setNumBook(int numBook) {
this.numBook = numBook;
}
public String getNameBook() {
return nameBook;
}
public void setNameBook(String nameBook) {
this.nameBook = nameBook;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
Class BookData: Load the info in array
public class BookData {
private List<Book> books = new ArrayList<Book>();
public BookData() {
loadBooks();
}
public List<Book> getBooks() {
return books;
}
public void setBooks(List<Book> books) {
this.books = books;
}
public void loadBooks() {
Book b;
for(int i = 0; i<4;i++){
b = new Book(i+1, "Libro "+i+1, "Author "+i+1);
books.add(b);
}
}
}
Class BookViewModel: ViewModel of Listbox
public class BookViewModel {
private static Book selectedBook;
private List<Book> booksData = new ArrayList<Book>(new BookData().getBooks()); // Armo los libros
public List<Book> getBooksData() {
return booksData;
}
public void setBooksData(List<Book> booksData) {
this.booksData = booksData;
}
//Getters and Setter the SelectedCar
#NotifyChange("selectedBook")
public Book getSelectedBook() {
if(selectedBook!=null) {
//setSelectedBook(selectedBook);
new DetailData(selectedBook);
//new ArrayList<>(new DetailData().getDetailsFilterByBook());
//Then here pass the Book Selected
}
return selectedBook;
}
public void setSelectedBook(Book selectedBook) {
this.selectedBook = selectedBook;
}
}
Class Detail: Detail Model of the choose Book
public class Detail {
private int idBook;
private String title;
private int numPages;
public Detail(int idBook, String title, int numPages) {
this.idBook = idBook;
this.title = title;
this.numPages = numPages;
}
public int getIdBook() {
return idBook;
}
public void setIdBook(int idBook) {
this.idBook = idBook;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getNumPages() {
return numPages;
}
public void setNumPages(int numPages) {
this.numPages = numPages;
}
#Override
public String toString() {
return "Detail [idBook=" + idBook + ", title=" + title + ", numPages=" + numPages + "]";
}
}
Class DetailData: Load the data in array
//Clase que se ecarga de manejar la data
public class DetailData {
private List<Detail> details = loadAllDetails();
private List<Detail> detailsFilterByBook;
private static Book bookSelected;
/*public DetailData(){
//Previously all the data is loaded
System.out.println(bookSelected);
detailsFilterByBook = new ArrayList<>();
filterDetailsByBook();
}*/
public void setBookSelected(Book bookSelected){
this.bookSelected = bookSelected;
}
public DetailData(){
this(bookSelected);
}
public DetailData(Book b){
bookSelected = b;
System.out.println(bookSelected);
detailsFilterByBook = new ArrayList<>();
filterDetailsByBook();
}
public List<Detail> loadAllDetails(){
List tmp = new ArrayList<Detail>();
//Libro 1
Detail d1b1 = new Detail(1, "Preview", 15);
Detail d2b1 = new Detail(1, "Inicio", 10);
Detail d3b1 = new Detail(1, "Zk Bind", 50);
//Libro 2
Detail d1b2 = new Detail(2, "Introduccion", 15);
Detail d2b2 = new Detail(2, "JAVA", 100);
Detail d3b2 = new Detail(2, "CSS", 25);
//Libro 3
Detail d1b3 = new Detail(3, "HTML", 35);
Detail d2b3 = new Detail(3, "Javascript", 40);
Detail d3b3 = new Detail(3, "Ajax", 25);
//Libro 4
Detail d1b4 = new Detail(4, "Android", 100);
Detail d2b4 = new Detail(4, "IOS", 100);
tmp.add(d1b1);
tmp.add(d2b1);
tmp.add(d3b1);
tmp.add(d1b2);
tmp.add(d2b2);
tmp.add(d3b2);
tmp.add(d1b3);
tmp.add(d2b3);
tmp.add(d3b3);
tmp.add(d1b4);
tmp.add(d2b4);
return tmp;
}
private void filterDetailsByBook() {
for(Detail d:details){
if(d.getIdBook() == bookSelected.getNumBook())
detailsFilterByBook.add(d);
}
print();
}
public void print(){
System.out.println("Imprimiendo detalles del libro escogido");
for(Detail d: detailsFilterByBook){
System.out.println(d);
}
}
public List<Detail> getDetails() {
return details;
}
public void setDetails(List<Detail> details) {
this.details = details;
}
public List<Detail> getDetailsFilterByBook() {
return detailsFilterByBook;
}
public void setDetailsFilterByBook(List<Detail> detailsFilterByBook) {
this.detailsFilterByBook = detailsFilterByBook;
}
}
Class: DetailViewModel:ViewModel of the second ListBox
public class DetailViewModel {
private List<Detail> detailsData = new ArrayList<>();
#NotifyChange("detailsData")
public void refreshList(){
System.out.println("REFRESH");
detailsData = new ArrayList<>(new DetailData().getDetailsFilterByBook());
}
public List<Detail> getDetailsData() {
return detailsData;
}
#NotifyChange("detailsData")
public void setDetailsData(List<Detail> detailsData) {
this.detailsData = detailsData;
}
}
Here is the zul file
<window title="" border="none" height="100%" apply="org.zkoss.bind.BindComposer" viewmodel="#id('vm') #init('book.BookViewModel')">
<listbox model="#bind(vm.booksData)" selecteditem="#bind(vm.selectedBook)" emptymessage="No car found in the result">
<listhead>
<listheader label="Num Libro"/>
<listheader label="Libro"/>
<listheader label="Autor"/>
</listhead>
<template name="model" var="book">
<listitem>
<listcell label="#bind(book.numBook)"/>
<listcell label="#bind(book.nameBook)"/>
<listcell label="#bind(book.author)"/>
</listitem>
</template>
</listbox>
<separator height="100px"/>
<window title="" border="none" height="100%" apply="org.zkoss.bind.BindComposer"
viewModel="#id('vm') #init('detail.DetailViewModel')">
<listbox model="#bind(vm.detailsData)" emptyMessage="No existen datos que presentar">
<listhead>
<listheader label="Num Capitulos"/>
<listheader label="Titulo del Cap"/>
</listhead>
<template name="model" var="detail">
<listitem>
<listcell label="#bind(detail.idBook)"/>
<listcell label="#bind(detail.title)"/>
<listcell label="#bind(detail.numPages)"/>
</listitem>
</template>
</listbox>
</window>
</window>
I try in the second listbox (At begin have to be empty), show the details of the book everytime when a book in the 1st listbox is selected. I get the correct info. When I choose a book, I get the correct details of that book, but my second listbox does'nt show anything. I will apreciate all the help. PD: Sorry for the english
Oke, there are more points to say on this code then you imagine.
Never use static for a user/session variable.
In your VM you have the following code :
private static Book selectedBook;
Imagine that I select Book 1 and you select 2 seconds later Book 2.
Because it's static, I'm also having Book 2 selected, while mine view isn't aware of it.
This means the GUI and server side are out of sync => never a good thing.
If you could be able to sync the view with the selected item, this means that you select book 2 for me and I'll be searching the number of the Ghost Busters.
With ZK, always use ListModel interface to give collections to GUI.
While returning List<Book> works pretty good, you need to understand the consequences of this action.
A List or Grid expect an implementation of ListModel and if you don't give it, there will be one created every time you notify the list of a change.
While this is a nice to have feature it also removes the intelligence of a listmodel and the GUI rendering will be a lot more.
An example is always more clear :
We have a Collection of 9 items and we will append 1 to it.
Adding 1 Object to the List and notifying it implies that all the content rendered of the Listbox will be removed and then adding all the content again to the Listbox.
This means that we are removing and adding 9 lines who aren't changed.
Adding 1 Object to a ListModel, even without notifying the ListModel of a change will result in an action where there is only 1 item appended to the Listbox. This is the intelligence of a ListModel => adding and removing items will be persisted to the GUI without overhead.
So your code should be looking like this :
private Book selectedBook;
private final ListModelList<Book> booksData = new ListModelList<Book>(new BookData().getBooks()); // Armo los libros
Why not working to the interface and why final?
So I just told you about the interface ListModel and yet, I'm setting an implementation of ListModel as code, even while we learn to work against interfaces.
The simple reason is that ListModel doesn't have methods for appending and removing items while the implementation do have it.
So I make a decision to work against that object in stead of casting it when I need the methods.
Remember, the global getter for the booksData can look like this :
public ListModel<Book> getBooksData() {
return booksData;
}
So here we hide the implementation of ListModelList to the outside.
The reason for final is that you will forcing yourself or other people who are going through the code to use the clear() method in stead of making a new ListModelList.
It's just not needed to create a new instance of it.
Using 2 viewmodel's
Your making yourself difficult of using 2 VM's.
But while it's sometimes a good idea to do this I'll be helping you to get your problem solved.
Your first problem is one of a naming kind.
Viewmodel 1 => called vm in the zul.
Viewmodel 2 => called vm in the zul.
You see it coming? who will listen when I cry to vm?
let's call the viewmodel of the details detailVM
viewModel="#id('detailVM') #init('detail.DetailViewModel')"
The second problem is that your detail viewmodel doesn't have any clue of the first listbox.
What do I want to say is that your second viewmodel should be holding the correct info of the selected item of the first listbox.
Zul code should be looking like this :
<window title="" border="none" height="100%" apply="org.zkoss.bind.BindComposer" viewmodel="#id('vm') #init('book.BookViewModel')">
<div apply="org.zkoss.bind.BindComposer"
viewModel="#id('detailVM') #init('detail.DetailViewModel')">
<listbox model="#init(vm.booksData)" selecteditem="#bind(detailVM.selectedBook)" emptymessage="No book found in the result">
<listhead>
<listheader label="Num Libro"/>
<listheader label="Libro"/>
<listheader label="Autor"/>
</listhead>
<template name="model" var="book">
<listitem>
<listcell label="#load(book.numBook)"/>
<listcell label="#load(book.nameBook)"/>
<listcell label="#load(book.author)"/>
</listitem>
</template>
</listbox>
<separator height="100px"/>
<listbox model="#init(detailVM.detailsData)" emptyMessage="No existen datos que presentar">
<listhead>
<listheader label="Num Capitulos"/>
<listheader label="Titulo del Cap"/>
</listhead>
<template name="model" var="detail">
<listitem>
<listcell label="#load(detail.idBook)"/>
<listcell label="#load(detail.title)"/>
<listcell label="#load(detail.numPages)"/>
</listitem>
</template>
</listbox>
</div>
</window>
So I set you up with the correct zul, and now it's up to you to modify the viewmodels.
Remember that I set selectedBook in detailVM so now it's not needed in the first viewmodel.
I don't write everything for you, otherwise you wouldn't learn from it.
Some small things left to say.
You see I change the listbox model to #init and not #bind.
A model is always read only, so please NEVER NEVER NEVER use #bind.
#load is the highest annotation you could use, and this is only the case when you will create a new instance for the ListModel, witch is hardly needed.
Labels, are also not updatable in your GUI.
Again #bind is over the top, #load should be used in normal situations (when the value can change, so most commonly) or #init when the value will never change, but if you use #load I'll be happy already.
Hope this could set you to the right direction.
If you have any other question, just comment below.

How to remove elements from GXT HtmlLayoutContainer

I have the following Widget that uses GXT HtmlLayoutContainer:
public class MyWidget implements IsWidget {
public interface MyWidgetLayout extends XTemplates {
#XTemplate(source = "my/stuff/resources/MyWidget.html")
SafeHtml getTemplate(List<MyData> myData);
}
public static final MyWidgetLayout LAYOUT = GWT.create(MyWidgetLayout .class);
private final List<MyData> myData;
private HtmlLayoutContainer container;
public TaskRegulationsContainer(List<MyData> myData) {
this.myData = myData;
}
#Override
public Widget asWidget() {
if (container == null) {
container = new HtmlLayoutContainer(LAYOUT.getTemplate(regulations, postfix));
if (null != regulations) {
for (MyData d : myData) {
MyOtherWidget w = new MyOtherWidget(d);
container.add(w, new AbstractHtmlLayoutContainer.HtmlData(".my-data-" + myData.getUniqueId()));
}
}
}
return container;
}
public void handleRemovedData(MyData removedData) {
// How can I remove the widget corresponding to removedData
// with the selector my-data-{uniqueId}?
}
}
with the following template:
<style>
</style>
<div>
<span>My Data:</span>
<div>
<tpl for="myData">
<div class="my-data-{uniqueId}"></div>
</tpl>
</div>
</div>
How can I remove individual myData list items from the UI after the template is rendered?
You can iterate over the children of the container, check if the class attribute contains "my-data-" + uniqueId and delete it.
Something like this should work:
public void handleRemovedData(MyData removedData) {
for (int i = 0; i < container.getChildCount(); i++) {
node = pParent.getChild(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node.cast();
if (element.getClassName().contains("my-data-" + removedData.getUniqueId())) {
container.removeChild(element);
}
}
}
}
Hope that helps.

How to filter one combobox value based on another combobox value in zk?

I have a list with two Combo boxes. I have some values in Combo box 1 and Combo box 2. While choose item in Combo box 1, the values will be filtered in Combo box 2 and rendered in UI.
Please someone help with this.
There is a nice example on zk fiddle in MVVM on how you could do this.
You can find it here.
If link dies, here is the code :
Zul :
<zk>
<window border="normal" title="Dependent components" apply="org.zkoss.bind.BindComposer"
viewModel="#id('vm') #init('pkg$.DependencyViewModel')">
<checkbox checked="#bind(vm.infoFromComboboxesRequired)" label="require comboboxes ?"
onCheck="#command('flagChecked')"/>
<combobox model="#load(vm.comboModel1)" visible="#load(vm.infoFromComboboxesRequired)"
selectedItem="#bind(vm.comboValue1)" onSelect="#command('combo1Selected')">
<template name="model">
<comboitem label="#load(each)" value="#load(each)"/>
</template>
</combobox>
<combobox model="#load(vm.comboModel2)" visible="#load(vm.infoFromComboboxesRequired)"
selectedItem="#bind(vm.comboValue2)" onSelect="#command('combo2Selected')">
<template name="model">
<comboitem label="#load(each)" value="#load(each)"/>
</template>
</combobox>
</window>
</zk>
Viewmodel:
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.Init;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.ListModel;
import org.zkoss.zul.ListModelList;
public class DependencyViewModel {
boolean infoFromComboboxesRequired = false;
ListModelList<String> comboModel1;
ListModelList<String> comboModel2;
String comboValue1;
String comboValue2;
#Init
public void init() {
comboModel1 = new ListModelList<String>();
comboModel2 = new ListModelList<String>();
}
#Command("flagChecked")
#NotifyChange({"comboModel1", "comboModel2"})
public void onFlagChecked() {
comboModel1.clear();
comboModel2.clear();
comboValue1 = null;
}
#Command("combo1Selected")
#NotifyChange("comboModel2")
public void onCombo1Selected() {
comboModel2.clear();
}
#Command("combo2Selected")
#NotifyChange("comboModel2")
public void onCombo2Selected() {
Clients.showNotification("selected combo 2 : " + comboValue2);
}
public ListModel<String> getComboModel1() {
if(infoFromComboboxesRequired) {
comboModel1.add("aaaa");
comboModel1.add("bbbb");
comboModel1.add("cccc");
comboModel1.add("dddd");
comboModel1.add("eeee");
}
return comboModel1;
}
public ListModel<String> getComboModel2() {
if(infoFromComboboxesRequired && comboValue1 != null) {
comboModel2.add(this.comboValue1 + "1111");
comboModel2.add(this.comboValue1 + "2222");
comboModel2.add(this.comboValue1 + "3333");
comboModel2.add(this.comboValue1 + "4444");
comboModel2.add(this.comboValue1 + "5555");
}
return comboModel2;
}
public boolean isInfoFromComboboxesRequired() {
return infoFromComboboxesRequired;
}
public void setInfoFromComboboxesRequired(boolean infoFromComboboxesRequired) {
this.infoFromComboboxesRequired = infoFromComboboxesRequired;
}
public String getComboValue1() {
return comboValue1;
}
public void setComboValue1(String comboValue1) {
this.comboValue1 = comboValue1;
}
public String getComboValue2() {
return comboValue2;
}
public void setComboValue2(String comboValue2) {
this.comboValue2 = comboValue2;
}
}

How to add form elements in gwt-bootstrap3

I am trying to add some elements in gwt-bootstrap3 modal [link], I am using UI-binder to generate the screen but nothing is appear.
my ui binder class
<?xml version="1.0" encoding="UTF-8"?>
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui' xmlns:b='urn:import:org.gwtbootstrap3.client.ui'
xmlns:res="urn:with:com.db.cary.client.resources.CSSResources">
<ui:with type="com.db.cary.client.resources.CSSResources" field="res">
</ui:with>
<b:Modal closable="true" fade="true" dataBackdrop="TRUE" dataKeyboard="true">
<b:ModalBody>
<b:Form type="HORIZONTAL">
<b:FieldSet>
<b:Legend>Please enter the book detail</b:Legend>
<b:FormGroup>
<b:FormLabel for="bookTitle" addStyleNames="col-lg-2">Title</b:FormLabel>
<g:FlowPanel addStyleNames="col-lg-10">
<b:TextBox placeholder="Enter book Title" ui:field="titleTextBox" />
</g:FlowPanel>
</b:FormGroup>
<b:FormGroup>
<b:FormLabel for="bookAuthor" addStyleNames="col-lg-2">Author</b:FormLabel>
<g:FlowPanel addStyleNames="col-lg-10">
<b:ListBox ui:field="authorListBox" />
<b:Button ui:field="newAuthorButton" type="LINK" size="EXTRA_SMALL">New author</b:Button>
</g:FlowPanel>
<g:FlowPanel addStyleNames="col-lg-offset-2 col-lg-10">
<b:TextBox ui:field="authorTextBox" placeholder="enter slash (/) separated list of authors"></b:TextBox>
</g:FlowPanel>
</b:FormGroup>
<b:FormGroup>
<b:FormLabel for="bookCategory" addStyleNames="col-lg-2">Category</b:FormLabel>
<g:FlowPanel addStyleNames="col-lg-10">
<b:ListBox ui:field="categoryListBox" />
<b:Button ui:field="newCategoryButton" type="LINK" size="EXTRA_SMALL">New Category</b:Button>
</g:FlowPanel>
<g:FlowPanel addStyleNames="col-lg-offset-2 col-lg-10">
<b:TextBox ui:field="categoryTextBox" placeholder="enter category"></b:TextBox>
</g:FlowPanel>
</b:FormGroup>
</b:FieldSet>
</b:Form>
</b:ModalBody>
<b:ModalFooter>
<b:Button type="PRIMARY" ui:field='submitButton'>Submit</b:Button>
<b:Button ui:field='cancelButton'>Cancel</b:Button>
</b:ModalFooter>
</b:Modal>
</ui:UiBinder>
and my view class
public class AddBook extends Modal {
interface CheckOutPopUpBinder extends UiBinder<Widget, AddBook> {
}
private static final CheckOutPopUpBinder binder = GWT.create(CheckOutPopUpBinder.class);
private final AuthorAndCategoryServiceAsync authorService = GWT.create(AuthorAndCategoryService.class);
private final LibraryServiceAsync libraryServiceAsync = GWT.create(LibraryService.class);
#UiField
TextBox titleTextBox;
#UiField
ListBox authorListBox;
#UiField
TextBox authorTextBox;
#UiField
ListBox categoryListBox;
#UiField
Button submitButton;
#UiField
Button cancelButton;
#UiField
Button newAuthorButton;
#UiField
Button newCategoryButton;
#UiField
TextBox categoryTextBox;
public AddBook(String title) {
binder.createAndBindUi(this);
setTitle(title);
initializeAuthorListBox();
initializeCategoryListBox();
}
private void initializeCategoryListBox() {
authorService.getCategories(null, new AsyncCallback<List<CategoryDTO>>() {
#Override
public void onFailure(Throwable arg0) {
Window.alert("unable to fetch category list");
}
#Override
public void onSuccess(List<CategoryDTO> arg0) {
for (CategoryDTO category : arg0)
categoryListBox.addItem(category.getCategoryName());
}
});
categoryListBox.setMultipleSelect(false);
categoryTextBox.setVisible(false);
}
private void initializeAuthorListBox() {
authorService.getAuthors(null, new AsyncCallback<List<AuthorDTO>>() {
#Override
public void onSuccess(List<AuthorDTO> arg0) {
for (AuthorDTO author : arg0) {
authorListBox.addItem(author.getAuthorName());
}
}
#Override
public void onFailure(Throwable arg0) {
Window.alert("Unable to fetch the list of authors");
}
});
authorListBox.setMultipleSelect(true);
authorTextBox.setVisible(false);
}
#UiHandler("cancelButton")
public void cancelAction(ClickEvent e) {
AddBook.this.hide();
}
#UiHandler("submitButton")
public void submitAction(ClickEvent e) {
AddBookDTO bookDTO = new AddBookDTO();
String bookTitle = titleTextBox.getText();
String bookCategory = categoryListBox.getSelectedValue() == null ? categoryTextBox.getText() : categoryListBox.getSelectedValue();
List<String> authorsList = new ArrayList<String>();
for (int i = 0; i < authorListBox.getItemCount(); i++) {
if (authorListBox.isItemSelected(i)) {
authorsList.add(authorListBox.getItemText(i));
}
}
if (null != authorTextBox.getText() && authorTextBox.getText().trim().length() > 0) {
String[] values = authorTextBox.getText().split("/");
for (String str : values) {
authorsList.add(str);
}
}
if (bookTitle == null || bookTitle.length() <= 0) {
Window.alert("Please enter a valid book title");
return;
} else if (bookCategory == null || bookCategory.length() <= 0) {
Window.alert("Please enter a valid book category");
return;
} else if (authorsList == null || authorsList.size() == 0) {
Window.alert("Please enter valid authors");
return;
}
bookDTO.setBookTitle(bookTitle);
bookDTO.setCategroyName(bookCategory);
bookDTO.setAuthors(authorsList);
libraryServiceAsync.addBook(bookDTO, new AsyncCallback<Boolean>() {
#Override
public void onFailure(Throwable arg0) {
Window.alert("There is some issue with database while adding book, Please contact your admin");
}
#Override
public void onSuccess(Boolean arg0) {
Window.alert("Book is successfully added !!!");
}
});
this.hide();
}
#UiHandler("newAuthorButton")
public void addAuthor(ClickEvent e) {
authorTextBox.setVisible(true);
}
#UiHandler("newCategoryButton")
public void addCategory(ClickEvent e) {
categoryTextBox.setVisible(true);
}
}
I am not sure, What is wrong but only header is appearing in the modal.
You are calling AddBook.this.show(); - this shows the Modal that is the base of this AddBook instance, not the instance defined in your UiBinder template. When you call setTitle(title); you are setting the header/title on this instance - this is why all you see is the header and not the rest of the modal. You should assign an ui:field to your Modal defined in your UiBinder template and show/hide it.
Also AddBook shouldn't be extending Modal - it shouldn't extend any widget class at all :) Normally, UiBinder classes are extending Composite - because your UiBinder template is composed of a variety of widgets and Composite is used to bring them together without exposing any of their APIs: you call initWidget with the result of binder.createAndBindUi(this).
But if you are creating a widget whose "main" widget is Modal, like here, you should just call binder.createAndBindUi(this) and ignore the Widget that is returned (just like you are doing now). This is because Modal attaches itself to the DOM, bypassing any GWT mechanism (actually, it conflicts with it).

CellList backed with ListDataProvider does not get redrawn on list change

I'm working on a project with GWT 2.1 and mvp4g. In a view, I'm using
a CellList backed with a ListDataProvider. If I pass a List with data to the constructor
when instantiating the ListDataProvider, the CellList shows this data.
The problem is that afterthat, the CellList never gets redrawn
whenever I change the list within the ListDataProvider. I don't know what I am
doing wrong or if I missing something.
Here is the code:
The UIBinder xml file:
<g:DockLayoutPanel unit="PX">
<g:west size="300">
<g:VerticalPanel styleName='{style.leftPanel}' spacing="8">
<g:Label>Expositores</g:Label>
<g:ScrollPanel addStyleNames='{style.exhibitorList}' width="250px" height="600px">
<c:CellList ui:field="exhibitorList" />
</g:ScrollPanel>
<g:Button ui:field="editExhibitorButton" addStyleNames='{style.button}'>Editar</g:Button>
</g:VerticalPanel>
</g:west>
...
The View class:
public class ExhibitorsAdminView extends Composite implements
ExhibitorsAdminPresenter.IExhibitorsAdminView {
interface Binder extends UiBinder<Widget, ExhibitorsAdminView> {}
private static final Binder binder = GWT.create( Binder.class );
private static class ExhibitorCell extends AbstractCell<Exhibitor> {
#Override
public void render(Cell.Context context, Exhibitor exhibitor,
SafeHtmlBuilder sb) {
if (exhibitor != null) {
sb.appendEscaped(exhibitor.getName());
}
}
}
private ListDataProvider<Exhibitor> exhibitorsDataProvider;
private SingleSelectionModel<Exhibitor> exhibitorsSelectionModel;
#UiField( provided = true )
CellList<Exhibitor> exhibitorList;
#UiField
Button editExhibitorButton;
// #UiField(provided = true)
// CellTable<Object> moduleList = new CellTable<Object>();
public ExhibitorsAdminView() {
exhibitorsSelectionModel = new
SingleSelectionModel<Exhibitor>(Exhibitor.KEY_PROVIDER);
exhibitorList = new CellList<Exhibitor>(new ExhibitorCell(),
Exhibitor.KEY_PROVIDER);
exhibitorList.setSelectionModel(exhibitorsSelectionModel);
exhibitorsDataProvider = new
ListDataProvider<Exhibitor>(getExhibitors());
exhibitorsDataProvider.addDataDisplay(exhibitorList);
exhibitorList.setPageSize(exhibitorsDataProvider.getList().size());
initWidget( binder.createAndBindUi( this ) );
}
public SingleSelectionModel<Exhibitor> getExhibitorsSelectionModel()
{
return exhibitorsSelectionModel;
}
public ListDataProvider<Exhibitor> getExhibitorsDataProvider() {
return exhibitorsDataProvider;
}
private List<Exhibitor> getExhibitors() {
List<Exhibitor> exhibitors = new ArrayList<Exhibitor>();
for (int i = 0; i < 10; i++) {
exhibitors.add(new Exhibitor(i, "aaaaaaaaaaaaaaa"));
}
return exhibitors;
}
public HasClickHandlers getEditExhibitorButton() {
return editExhibitorButton;
}
}
The presenter class:
#Presenter(view = ExhibitorsAdminView.class)
public class ExhibitorsAdminPresenter extends
BasePresenter<ExhibitorsAdminPresenter.IExhibitorsAdminView,
ExhibitorsEventBus> {
public interface IExhibitorsAdminView {
SingleSelectionModel<Exhibitor> getExhibitorsSelectionModel();
ListDataProvider<Exhibitor> getExhibitorsDataProvider();
HasClickHandlers getEditExhibitorButton();
}
private DispatchAsync dispatch = null;
#Inject
public ExhibitorsAdminPresenter(final DispatchAsync dispatch) {
this.dispatch = dispatch;
}
#Override
public void bind() {
getView().getExhibitorsSelectionModel().addSelectionChangeHandler(
new SelectionChangeEvent.Handler() {
public void onSelectionChange(SelectionChangeEvent event) {
Exhibitor selected =
getView().getExhibitorsSelectionModel().getSelectedObject();
if (selected != null) {
Window.alert("You selected: " + selected.getName());
}
}
});
getView().getEditExhibitorButton().addClickHandler(
new ClickHandler() {
public void onClick(ClickEvent event) {
}
});
}
public void onGoToExhibitorsAdmin() {
}
public void onLoadExhibitors() {
dispatch.execute(new GetExhibitors(), new
AsyncCallback<GetExhibitorsResult>() {
public void onSuccess(GetExhibitorsResult result) {
getView().getExhibitorsDataProvider().setList(
result.getExhibitors());
getView().getExhibitorsDataProvider().refresh();
}
public void onFailure(Throwable caught) {
GWT.log("error executing command ", caught);
}
});
}
}
Thanks.
I solved it. I'm sorry, it was an issue related with mvp4g. I was doing something wrong that was causing to have to different instances of the view where the CellList was placed. The update operations I was doing on the list of the ListDataProvider were being done on the view instance that wasn't being shown.
You have to manipulate the list by getting it first of your provider like provider.getList().add(...). See How to add or remove a single element from/to CellList? for a minimal example.
Just call exhibitorsDataProvider.refresh() after all operations with underlying list.