0

Grid jumping to top on change after upgrading from ZK 5.11 to ZK 8.0.1

asked 2016-02-19 16:46:27 +0800

djr gravatar image djr
1

updated 2016-02-22 18:13:00 +0800

I'm working through upgrading our project from ZK 5.11 to ZK 8.0.1. It is mostly going well, and most changes have been minor to get things working. Unfortunately I've run into a significant issue with grids jumpy to top when the model is refreshed. I'm hopping someone can explain why this happens in ZK 8, but does not happen in ZK 5.

In a hopefully simple example, in ZK 5 we build a model from database data, and assign it to a grid. On each row of the grid is a textbox that allows a value to be changed. When you change that value an onChange event causes us to write the value to the database, then reload the data, build a new model and assign it to the grid. (Admittedly not the most efficient approach)

In ZK 5 the grid stays in the same scroll position through all of this. In ZK 8 the grid jumps to the top. I'd like to maintain the ZK 5 behaviour.

Frankly I'm surprised that ZK 5 works as desired. I'm hoping for either a suggestion on how to make ZK 8 behave like ZK 5 did, or an explanation why ZK 5 worked, but ZK 8 won't in this scenario.

Thanks, Derek


Update: This is the closest approximation I can produce to what our legacy code is doing in ZK5. Unfortunately this example doesn't actually mimic the behaviour of our actual code, as this code jumps to the top on refresh where the actual code does not.

There is a lot of stuff here I would do differently, but the task is make it work, not make it perfect. At the bottom, I have what I think is a viable workaround to the problem, but I also recognize it's not an ideal solution.

<window title="Hello World!!" border="normal" width="400px" height="400px" apply="com.test.LetterNewModelCtrl">

<label value="You are using: ${desktop.webApp.version}"/>

<grid id="piLetterGrid" hflex="min" height="300px" width="220px">
    <columns>
        <column width="100px" label="Letter"/>
        <column width="100px" label="Edit" />
    </columns>
    <rows/>
</grid>

</window>


public class LetterNewModelCtrl extends GenericForwardComposer  {

        private static final long serialVersionUID = -5573454291062801636L;

        // To simulate database interaction
        private static ArrayList<Letter> backgroundModel;
        {
            backgroundModel  = new ArrayList<Letter>();
            for(char i = 65;i < (65+26);i++) {
                char[] ca = new char[] {i};
                backgroundModel.add(new Letter(new String(ca)));
            }
        }
        private static void setBackgroundModel(ArrayList<Letter> model) {
            backgroundModel = new ArrayList<Letter>();
            for(Letter l:model) {
                backgroundModel.add(new Letter(l.getLetter()));
            }
        }

        private AnnotateDataBinder binder;

        private UpdateLineListener updateLineListener;
        private ArrayList<Letter> model;

        Grid piLetterGrid;

        public void doAfterCompose(Component comp) throws Exception {
            super.doAfterCompose(comp); 
            binder = new AnnotateDataBinder(comp);

            updateLineListener = new UpdateLineListener();

            onRefresh();
        }

        public void onRefresh() {
            // Load local model with data from simulated database model.
            model = new ArrayList<Letter>();
            for(Letter l:backgroundModel) {
                model.add(l);
            }
            piLetterGrid.setModel(new SimpleListModel(model));      
            piLetterGrid.setRowRenderer(new LetterRowRenderer());
            binder.loadAll();
        }

        class LetterRowRenderer implements RowRenderer {
            public void render(Row row, java.lang.Object obj) {
                Letter letter = (Letter) obj;
                row.setAttribute("letter", obj);
                Cell cell = new Cell();
                Label label = new Label();
                label.setValue(letter.getLetter());
                cell.appendChild(label);
                row.appendChild(cell);

                cell = new Cell();
                Textbox textbox = new Textbox(letter.getLetter());
                textbox.addEventListener(Events.ON_CHANGE, updateLineListener);
                textbox.setAttribute("letter", letter);
                textbox.setWidth("50px");
                cell.appendChild(textbox);
                row.appendChild(cell);
            }
        }

        class UpdateLineListener implements EventListener {
            public void onEvent(Event event) throws Exception {
                Textbox t = (Textbox) event.getTarget();
                Letter letter = (Letter)t.getAttribute("letter");
                letter.setLetter(t.getValue());
                            //Send the changes to the simulated database
                setBackgroundModel(model);
                onRefresh();
            }
        }

        static public class Letter {
            private String letter;

            public Letter(String letter) {
                this.letter = letter;
            }

            public String getLetter() {
                return letter;
            }

            public void setLetter(String letter) {
                this.letter = letter;
            }
        }
    }

This is the solution that so far is giving me the results I want in ZK8. Basically it creates the SimpleListModel once, instead of every time the data is updated, and it creates the ArrayList that backs the SimpleListModel once, then clears and refills it on updates.

public class LetterSingleModelCtrl extends GenericForwardComposer  {

private static final long serialVersionUID = -162277024462534754L;

private static ArrayList<Letter> backgroundModel;
{
    backgroundModel  = new ArrayList<Letter>();
    for(char i = 65;i < (65+26);i++) {
        char[] ca = new char[] {i};
        backgroundModel.add(new Letter(new String(ca)));
    }
}
private void setBackgroundModel(ArrayList<Letter> model) {
    backgroundModel = new ArrayList<Letter>();
    for(Letter l:model) {
        backgroundModel.add(new Letter(l.getLetter()));
    }
}
private AnnotateDataBinder binder;

private UpdateLineListener updateLineListener;
private ArrayList<Letter> model =  new ArrayList<Letter>();
private SimpleListModel simpleListModel = null;

Grid piLetterGrid;

public void doAfterCompose(Component comp) throws Exception {
    super.doAfterCompose(comp); 
    binder = new AnnotateDataBinder(comp);

    updateLineListener = new UpdateLineListener();

    onRefresh();
}

public void onRefresh() {
    model.clear();
    for(Letter l:backgroundModel) {
        model.add(l);
    }

    if(simpleListModel == null) {
        simpleListModel = new SimpleListModel(model);
        piLetterGrid.setModel(simpleListModel);     
    }

    piLetterGrid.setRowRenderer(new LetterRowRenderer());
}

class LetterRowRenderer implements RowRenderer {
    public void render(Row row, java.lang.Object obj) {
        Letter letter = (Letter) obj;
        row.setAttribute("letter", obj);
        Cell cell = new Cell();
        Label label = new Label();
        label.setValue(letter.getLetter());
        cell.appendChild(label);
        row.appendChild(cell);

        cell = new Cell();
        Textbox textbox = new Textbox(letter.getLetter());
        textbox.addEventListener(Events.ON_CHANGE, updateLineListener);
        textbox.setAttribute("letter", letter);
        textbox.setWidth("50px");
        cell.appendChild(textbox);
        row.appendChild(cell);
    }
}

class UpdateLineListener implements EventListener {
    public void onEvent(Event event) throws Exception {
        Textbox t = (Textbox) event.getTarget();
        Letter letter = (Letter)t.getAttribute("letter");
        letter.setLetter(t.getValue());
        setBackgroundModel(model);
        onRefresh();
    }
}

static public class Letter {
    private String letter;

    public Letter(String letter) {
        this.letter = letter;
    }

    public String getLetter() {
        return letter;
    }

    public void setLetter(String letter) {
        this.letter = letter;
    }
}

}


The answer provided by Darksu is definitely the right way to go if starting from scratch. I unfortunately have a large volume of legacy code that needs to work again quickly. The ideal solution unfortunately is not the practical one.

delete flag offensive retag edit

Comments

Looks like a 'common law feature' due to the rebuilding of your model

chillworld ( 2016-02-19 17:33:45 +0800 )edit

@chillworld I'm afraid this is likely the case. I was hoping for a technical explanation like, X was done in ZK 5 but now Y is done in ZK 8 which doesn't support this behaviour. But I recognize this is a big ask.

djr ( 2016-02-19 18:23:49 +0800 )edit

I can understand why it's fixed. When you reload your model, your data could be less then before. So if you stay at same position, you don't see a thing. Now, as for the solution you just need to update that object in your list. If possible post some of your code and I'll help you with it.

chillworld ( 2016-02-19 19:52:27 +0800 )edit

@chilworld thank you very much for your followup. I'm working on a simplified version of our existing ZK5 pattern so I can resolve how to transition it to ZK8. The irony is so far I can't get the simplified ZK 5 code to behave like production code. It behaves, as you'd expect, resets to the top.

djr ( 2016-02-19 20:18:19 +0800 )edit

Don't worry about that. Just try to show the data flow in code and in what controllers as zk 5 don't use MVVM :)

chillworld ( 2016-02-19 21:45:11 +0800 )edit

1 Answer

Sort by ยป oldest newest most voted
0

answered 2016-02-20 11:37:10 +0800

Darksu gravatar image Darksu
1991 1 4

Hello djr,

Please find below a example of updating a listbox without re-positioning after the model is updated.

https://www.zkoss.org/zkdemo/grid/data_binding

And try using mvvm, it's much simpler and will save you a lot of time and effor.

Best Regards,

Darksu

link publish delete flag offensive edit
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow
1 follower

RSS

Stats

Asked: 2016-02-19 16:46:27 +0800

Seen: 22 times

Last updated: Feb 22 '16

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More