that's my code:
<listbox id="boxFirma" multiple="true"
visible="#load(vm.opzioneSelezionata eq 'firma' ? 'true' : 'false')"
checkmark="true" width="400px" height="200px"
model="#bind(vm.opzioniFirma)"
selectedItems="#bind(vm.pickedItemSet)">
<template name="model" var="item"
status="s">
<listitem selected="#bind(item.preSelected)">
<listcell label="#bind(item.valore)" />
</listitem>
</template>
</listbox> <button label="Salva" style="margin-top:10px" disabled="#load(empty vm.pickedUser)"
onClick="#command('salvaPersonalizzazioneUtente')" />
The problem is when I push the button Salva, I get on the vm.pickedItemSet only the item that the user has just chosen, but nothing about the preselected items -> 'listitem selected="#bind(item.preSelected)" ' . So if there were 2 items preselected and one clicked by the user on the view model, I get just the one clicked, whereas I want all three. How do I fix this?
I think that your problem is behind the use of "preselected" property of your domain object. Without your View Model it's hard to understand what you are trying to achieve.
Hovewer, let me try to address you:
fill the set (pickedItemset) in the init method, and let zk handle that set.
remove " selected="#bind(item.preSelected)" " from you template. If you like
checkboxes, add "checkmark=true" as a listbox property
(http://books.zkoss.org/wiki/ZK_Component_Reference/Data/Listbox#Multiple_Selection).
As an example, try this View Model ( "SignOption" is a bean with a single member valore). The "Salva" button will print out the set of selected list items.
// a bunch of imports
public class MultiSelectionVM {
private String opzioneSelezionata = "firma";
private Set<SignOption> opzioniFirma = new HashSet<SignOption>();
private Set<SignOption> pickedItemSet = new HashSet<SignOption>();
private boolean pickedUser = true;
#Init
public void init(){
SignOption opt1 = new SignOption();
opt1.setValore("opt1");
SignOption opt2 = new SignOption();
opt2.setValore("opt2");
SignOption opt3 = new SignOption();
opt3.setValore("opt3");
//Init list model
opzioniFirma.add(opt1);
opzioniFirma.add(opt2);
opzioniFirma.add(opt3);
//Init selected Items
pickedItemSet.add(opt2);
}
#Command
public void salvaPersonalizzazioneUtente(){
System.out.println(pickedItemSet);
}
//Getters and setter for all members
}
Hope this helps!
Related
I have a list shown in my view which is populated from my database and it uses pagination. Works fine so far. What I want to do now is to give the user the possibility to jump to a specific page via input into a text field.
My controller method would look like this, as my imagination goes:
#Controller
public class OrderController {
private static final int INITIAL_PAGE_SIZE = 15;
private int currentPage = 1;
#Autowired
private OrderService service;
#GetMapping("/dispo/orderViewList/{pageNumber}")
private String showSpecifiedPage(#RequestParam("pageNumber") Integer page, Model model) {
Page<LoadOrders> pagedList = service.findAll(page -1, INITIAL_PAGE_SIZE);
List<LoadOrder> orderList = service.createLoadOrderPage(pagedList);
model.addAttribute("page", orderList);
model.addAttribute("currentPage", page);
model.addAttribute("totalPages", pagedList.getTotalPages());
return "/dispo/orderViewList";
}
My idea is now since I have a model attribute named "page" to change this attribute to the page number I'd like to show and send this as a get request to the controller method. And this is the code for the view:
<form action="#" th:action="#{/dispo/orderViewList/{page}}" method="get">
Direkt zu Seite: <input type="text" th:field ="*{page}" size ="4"> <input type="submit">
</form>
The result is just what I wanted and looks like this:
But the controller is never called. In fact the controller for the standard list is called:
#GetMapping("/dispo/orderViewList")
private String showOrderList(#RequestParam("page") Optional<Integer> page, Model model) {
page.ifPresent(p -> currentPage = p);
Page<LoadOrders> pagedList = service.findAll(currentPage - 1, INITIAL_PAGE_SIZE);
List<LoadOrder> orderList = service.createLoadOrderPage(pagedList);
model.addAttribute("page", orderList);
model.addAttribute("currentPage", currentPage);
model.addAttribute("totalPages", pagedList.getTotalPages());
return "/dispo/orderViewList";
}
So what can I do to tell the controller to use the method with the page parameter?
I have created a page that passes a value to a new page that will allow users to update the data. When the users selects the record to be updated the edit form opens but the data is not visible. If the value is changed and the edit button clicked it will update the value, but it is never visible. How can I show the data that is to be edited?
View Model
namespace QiApp.ViewModels
{
public class EditTodayCasesViewModel
{
private SxCaseDataService _sxCaseDataService = new SxCaseDataService();
public SxCase SelectedSxCase { get; set; }
public ICommand EditSxCaseCommand => new Command(async () =>
{
await _sxCaseDataService.PutSxCase(SelectedSxCase.SxCaseId, SelectedSxCase);
});
}
}
Edit Page xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewModels="clr-namespace:QiApp.ViewModels;assembly=QiApp.UWP"
x:Class="QiApp.Views.EditTodayCasePage">
<ContentPage.BindingContext>
<viewModels:EditTodayCasesViewModel/>
</ContentPage.BindingContext>
<StackLayout>
<Label Text="Surgery Case"/>
<Label Text="{Binding SelectedSxCase.SxCaseId}"/>
<Entry Text="{Binding SelectedSxCase.Record}"/>
<Switch IsToggled="{Binding SelectedSxCase.Complete}"/>
<Button Text="Edit Surgery Case"
Command="{Binding EditSxCaseCommand}"/>
</StackLayout>
</ContentPage>
Code behind
namespace QiApp.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class EditTodayCasePage : ContentPage
{
public EditTodayCasePage(SxCase sxCase)
{
InitializeComponent();
var editTodayCasesViewModel = BindingContext as EditTodayCasesViewModel;
editTodayCasesViewModel.SelectedSxCase = sxCase;
}
}
}
Everything is alright except that your view gets bound to a view model which stays silent if properties are changed. Your view cannot get any information on when it should update itself and hence the UI as soon as the property SelectedSxCase gets changed.
Thankfully this can be done very easily by simply implementing the common interface INotifyPropertyChanged and extending your bound properties with a code line raising the event the interface provides.
Basically it goes like this ...
private SxCase _case;
public SxCase SelectedSxCase
{
get => _case;
set
{
_case = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedSxCase)));
}
}
... but there are several implementations to do that more elegant like using the CallerMemberName or even weaving the getter and setter automatically with Fody.
I am totally new in ZK. I need to create N combobox with their labels dynamically and populate them. I already populate a combobox with its id, but as there can be many combobox I should not know their ids, so It does not solve my problem.
I need to add N combobox, their labels and populate them dynamically. Is there any way to create that group of combobox and set them dynamically? Any ideas?
The code bellow works to populate the combo already knowing its fixed id.
//In this example I assume I have a label and a combobox. But could have 0 to N of them.
private Label lblComboMetadatos;
private Combobox cmbMetadatos;
//THEN
if (cmbMetadatos.getItemCount() == 0) {
lblComboMetadatos.setValue(trdMetaTipoDocumental.getNombreMetadato()); //Here I set the name of label but I should really can not know how many of them could be. There may exist 0..N
for (TrdMetadato trdMetaDato: trdMetaTipoDocumental.getTrdMetadatos()) {
String enumValores = trdMetaDato.getValoresEnumerado(); //Here I set the values of a combobox but I can not know how many of them could be. There may exist 0..N
cmbMetadatos.appendItem(enumValores]);
}
}
<zk>
<window id="idWindow" title="nameWindow" apply="controller.java" border="normal" closable="true" sizable="true" maximizable="true" maximized="true" height="85%" width="150%" style="overflow:auto;">
<!-- CONTINUES -->
<groupbox>
<hlayout>
<label id="lblComboMetadatos" />
<combobox id="cmbMetadatos"></combobox>
</hlayout>
</groupbox>
<!-- CONTINUES -->
</window>
</zk>
This question is very similar to your last question. You should wire the parent container (hlayout in this case) to your controller and then create the components there.
#Wire
private Component container; // your hlayout
#Override // This method should be specified by a composer super class
public void doAfterCompose(Component comp) throws Exception
for (<count an index or loop over data>) {
hlayout.appendChild(new Label("Hello World");
Combobox cb = new Combobox();
// append Comboitems
cb.addEventListener(Events.ON_SELECT, ...);
hlayout.appendChild(cb);
}
}
If you used MVVM, you could use children binding to create the components in zul.
I am able to bind SelectedItem if Selection Mode is single but if it is set to multiple then how do you bind it?
Here is what I tried for Single Selection Mode
<sync:SfDataGrid Grid.Row="1" AutoGenerateColumns="False" AllowSorting="True"
AllowGroupExpandCollapse="True" AutoExpandGroups="True"
SelectionMode="Multiple" ColumnSizer="Star"
ItemsSource="{Binding LstItems}"
SelectedItem="{Binding Path=SelectedItem, Mode=TwoWay}"
>
<sync:SfDataGrid.Columns>
<sync:GridTextColumn HeaderText="Name" MappingName="Name" />
<sync:GridTextColumn HeaderText="MRP" MappingName="MRP"/>
<sync:GridTextColumn HeaderText="Category" MappingName="Category" Width="0"/>
</sync:SfDataGrid.Columns>
<sync:SfDataGrid.GroupColumnDescriptions>
<sync:GroupColumnDescription ColumnName="Category"/>
</sync:SfDataGrid.GroupColumnDescriptions>
</sync:SfDataGrid>
In the above xaml, selection mode is set to multiple but I am unable to get the SelectedItems in xaml as mentioned here
https://help.syncfusion.com/xamarin/sfdatagrid/selection
In SfDataGrid, it is not possible to bind the SfDataGrid.SelectedItems property to the view model as like SelectedItem property since we can only get the selected items in SfDataGrid. Hence, you will not be able to bind the values in XAML for SelectedItems property.
However, you can achieve your requirement by writing behavior for SfDataGrid which will not affect the MVVM pattern. Please refer the below code snippet.
<sfGrid:SfDataGrid x:Name="dataGrid"
AutoGenerateColumns="True"
ItemsSource="{Binding OrdersInfo}"
SelectionMode="Multiple">
<b:Interaction.Behaviors>
<b:BehaviorCollection>
<b:EventToCommand Command="{Binding SelectionCommand}"
CommandParameter="{x:Reference Name=dataGrid}"
EventName="SelectionChanged" />
</b:BehaviorCollection>
</b:Interaction.Behaviors>
</sfGrid:SfDataGrid>
// In ViewModel.cs
public ViewModel()
{
selectionCommand = new Command<SfDataGrid>(onSelectionChanged);
selectedItems = new ObservableCollection<object>();
}
private Command<SfDataGrid> selectionCommand;
public Command<SfDataGrid> SelectionCommand
{
get { return selectionCommand; }
set { selectionCommand = value; }
}
private ObservableCollection<object> selectedItems;
public ObservableCollection<object> SelectedItems
{
get { return selectedItems; }
set { selectedItems = value; }
}
private void onSelectionChanged(SfDataGrid obj)
{
//you can get the selected items in the datagrid
selectedItems = obj.SelectedItems;
}
Also, we have prepared a sample for your reference and you can download the same from the below link.
Sample link: http://www.syncfusion.com/downloads/support/directtrac/168321/ze/DataGridDemo352928928
Regards,
Divakar.
I have two ViewModels in my MVVM app. the one is bind to main window and another to popup window which appears after click on the button. in the popup window I need binding to the selected entity from main window. how can I access this entity in MainViewModel from PopupViewModel?
ZK has the concept of the event queue and global commands for communication between multiple ViewModels so we can use that to pass the current selected entity to the ViewModel of a popup window.
Using this zk mvvm demo page:
(see docs)
I added to the listbox a global command which fires out the current selected reminder of the main ViewModel which needs to be shown by a popup window:
<listbox id="list" multiple="true" rows="6"
model="#load(vm.reminders)"
selectedItem="#bind(vm.selectedReminder)"
onSelect="#global-command('refresh', reminder=vm.selectedReminder)">
Then I added to the bottom of the page a popup window with a second ViewModel:
<window id="info" visible="false" width="120px" border="normal" position="parent"
apply="org.zkoss.bind.BindComposer"
viewModel="#id('vm') #init('org.zkforge.zktodo2.ui.ViewModelPopup')"
>
You have selected <label value="#load(vm.currentReminder.name)"/>
</window>
<button label="More info" onClick="info.doPopup()"/>
</zk>
The pop up Viewmodel has a method which accepts the global command which takes the entity as a parameter:
public class ViewModelPopup {
protected Reminder currentReminder = new Reminder();
public Reminder getCurrentReminder() {
return currentReminder;
}
public void setCurrentReminder(Reminder currentReminder) {
this.currentReminder = currentReminder;
}
#GlobalCommand #NotifyChange("currentReminder")
public void refresh(#BindingParam("reminder") Reminder reminder ){
this.setCurrentReminder(reminder);
return;
}
}
So now whenever you select an item in the listbox the refresh method is fired on the popup ViewModel passing into it data taken from the main ViewModel. Whenever you hit the "More info" button at the bottom of the page to show the popup window it displays the name of the current selected entity.
The documentation which I followed to do this is at:
(docs1)
(docs2)
The instructions to run that sample app are on the readme at (Docs3)
Do you have a list of entities in your mainwindow? if that is the case, from the view model of your main window you need to put your selected entity in a map and pass it as a param for createComponents just like this:
//In the view Model of the main window
Map arg = new HashMap();
arg.put("selectedEntity", SelectedEntity);
Executions.createComponents("/myPopup.zul", null, arg);
Now in the popup view model, you simply retrieve the value of your Entity in the Init method:
//PopupView model
#Init
public void init(#ExecutionArgParam("selectedEntity") SelectedEntity newEntity) {
entity = newEntity;
}
you can notice that the string in ExecutionArgParam is the key you put in the map.