Initialize Input Components

When a user visits this page, we want profile data to be loaded in the form and ready to be modified. Hence, we should initialize those input components in a controller by loading previously-saved data to input components.

To manipulate components, we need to get their object reference by @Wire.

public class ProfileViewController extends SelectorComposer<Component>{

    //wire components
    @Wire
    Label account;
    @Wire
    Textbox fullName;
    @Wire
    Textbox email;
    @Wire
    Datebox birthday;
    @Wire
    Listbox country;
    @Wire
    Textbox bio;

    //services
    AuthenticationService authService = new AuthenticationServiceChapter3Impl();
    UserInfoService userInfoService = new UserInfoServiceChapter3Impl();
    ...
}
  • Line 19: A controller usually calls service classes to perform business operations or get necessary data.

To make sure all components objects are wired, we initialize them in doAfterCompose() since ZK will call this method after it creates all its child components, so that you can manipulate those children safely.

public class ProfileViewController extends SelectorComposer<Component>{

    ...

    @Override
    public void doAfterCompose(Component comp) throws Exception{
        super.doAfterCompose(comp);

        ListModelList<String> countryModel = new ListModelList<String>(CommonInfoService.getCountryList());
        country.setModel(countryModel);

        refreshProfileView();
    }

    ...

    private void refreshProfileView() {
        UserCredential userCredential = authService.getUserCredential();
        User user = userInfoService.findUser(userCredential.getAccount());
        if(user==null){
            //TODO handle un-authenticated access
            return;
        }

        //apply bean value to UI components
        account.setValue(user.getAccount());
        fullName.setValue(user.getFullName());
        email.setValue(user.getEmail());
        birthday.setValue(user.getBirthday());
        bio.setValue(user.getBio());

        ((ListModelList)country.getModel()).addToSelection(user.getCountry());
        ...
    }
}
  • Line 12: Load previously-saved data to input components to initialize UI, so we should call it after initializing country list.
  • Line 26-30: Populate saved user data to components by setValue().
  • Line 32: set the Listbox's selected item with ListModelList.addToSelection().

Populate Country Drop-down List

This form needs a drop-down list that contains a list of countries. When a user visits the page, the data in drop-down list should be ready. To achieve this, we have to initialize a drop-down list in the controller.

By setting <listbox> in "select" mold, We will have a drop-down list instead of a table-like component on the page.

<listbox id="country" mold="select" width="200px">

A component could have multiple different visual appearances. Each appearance is called a "mold". Therefore, you can choose a proper mold according to your visual requirement/page design.

Relationship among a Component, Model, and Template

In ZK, all data components are designed to accept a separate model object that contains data to be rendered, and the component renders the data model upon a template (what you specify inside <template>).

This design keeps each part in its single responsibility, so that increases their reusability and decouples the data from a component's implementation.

Create a Data Model

Just a <listbox> in a zul doesn't provide any country to select. We need create a data model object.

public class ProfileViewController extends SelectorComposer<Component>{
    ...
    @Wire
    Listbox country;

    @Override
    public void doAfterCompose(Component comp) throws Exception{
        super.doAfterCompose(comp);

        ListModelList<String> countryModel = new ListModelList<String>(CommonInfoService.getCountryList());
        country.setModel(countryModel);

        ...
    }

    ...

}
  • Line 10: Create a ListModelList object with a list of String
  • Line 11: Provide prepared data model object to the component by setModel().

Define Listbox Template

The last part is to define a template, so that <listbox> can know how to render its data model. If you don't define it, <listbox> renders the model with a default built-in template.

<listbox id="country" mold="select" width="200px">
    <template name="model">
        <listitem label="${each}" />
    </template>
</listbox>
  • Line 2: The name attribute has to be model which means it's a template for <listbox> model.
  • Line 3: The ${each} is an implicit variable that you can use without declaration inside <template>, and it represents one object of the data model for each iteration when rendering. We use this variable with dot notation at component attributes to reference a data object's property . In our example, we just set it at <listitem>'s label.

Populate Input Components

When a user visits this page, we want profile data to be loaded in the form and ready to be modified. Hence, we should initialize those input components in a controller by loading previously-saved data to input components.

To manipulate components, we need to get their object reference by @Wire.

public class ProfileViewController extends SelectorComposer<Component>{

    //wire components
    @Wire
    Label account;
    @Wire
    Textbox fullName;
    @Wire
    Textbox email;
    @Wire
    Datebox birthday;
    @Wire
    Listbox country;
    @Wire
    Textbox bio;

    //services
    AuthenticationService authService = new AuthenticationServiceChapter3Impl();
    UserInfoService userInfoService = new UserInfoServiceChapter3Impl();
    ...
  • Line 19: A controller usually calls service classes to perform business operations or get necessary data.

To make sure all components objects are wired, we initialize them in doAfterCompose().


public class ProfileViewController extends SelectorComposer<Component>{

    ...

    @Override
    public void doAfterCompose(Component comp) throws Exception{
        super.doAfterCompose(comp);

        ListModelList<String> countryModel = new ListModelList<String>(CommonInfoService.getCountryList());
        country.setModel(countryModel);

        refreshProfileView();
    }

    ...

    private void refreshProfileView() {
        UserCredential userCredential = authService.getUserCredential();
        User user = userInfoService.findUser(userCredential.getAccount());
        if(user==null){
            //TODO handle un-authenticated access
            return;
        }

        //apply bean value to UI components
        account.setValue(user.getAccount());
        fullName.setValue(user.getFullName());
        email.setValue(user.getEmail());
        birthday.setValue(user.getBirthday());
        bio.setValue(user.getBio());

        ((ListModelList)country.getModel()).addToSelection(user.getCountry());
        ...
    }
}
  • Line 13: Load previously-saved data to input components to initialize UI, so we should call it after initializing country list.
  • Line 27-31: Push saved user data to components by setValue().
  • Line 33: Use ListModelList.addToSelection() to set the Listbox's selected item.