-
FEATURED COMPONENTS
First time here? Check out the FAQ!
Since no one seems to be following up in this thread http://www.zkoss.org/forum/listComment/18752-Event-Queue-subscribed-more-than-once, I'll briefly explain the issue.
When trying to use an MVVM pattern, you often see suggestions to use Composers for things where you are dealing more directly with the UI elements (the idea being that ViewModels shouldn't know about a UI elements.
However in order for a ViewModel to notify a Composer of an event, you can't just listen for a regular global command, it has to subscribe to a queue with a listener and your ViewModel has to send out a global command to that queue.
From the above thread though this seems to have a lot of messy issues with having to clean up listeners, whereas instead of using a Composer I just use a ViewModel I don't have those issues. In fact the ViewModel code and the Composer look almost identical.
Am I taking the wrong approach here?
As an example (real life one that I ran into), think of your navigation controller that might open and close new windows. It works fine as a regular Composer to start with, but what if you need another ViewModel to trigger that Composer fire and open a page? You have to create a queue in order to notify it. Now if you refresh the page you have multiple instances of listeners unless you handle complicated clean up routines. Vs instead I just use a ViewModel on top of my navigation and I can listen for a globalCommand:
//use by the navigation menu clicks @Command public void onNavigate(@BindingParam("page") String page) { //code to open the correct page } //called from external view models @GlobalCommand public void switchPage(@BindingParam("page") String page) { onNavigate(page); }
With a Composer handling this you'd need
@Subscribe("navigationQueue") public void switchPage(Event event) { //.... }
Bottom line is I don't see what advantage I get not using ViewModels for everything.
@rickr:
"I did read your comment "I chose not to go with MVVM for the portal container itself due to its heavy involvement with dynamically creating, updating, and destroying its child components." and that's interesting- you must know a lot more about what's going on 'under the hood' than I do since I wasn't aware of all that."
No, I didn't mean the MVVM does all that, I meant the business portal is doing all that, which is why I use MVC over MMVM for the portal portion. Hope that's clearer.
@czynga:
The afterCompose doesn't break the MVVM pattern, since they included an @AfterCompose annotation specifically for MVVM, which is executed in the BindComposer's doAfterCompose method.
@Senthilchettyin:
Per the documentation for the Window component:
"onClose is sent when the close button is pressed (if isClosable() is true). The window has to detach or hide the window. By default, onClose() detaches the window. "
So, I'm not sure why you need to go to extraordinary means to detach the window. Seems like, when you close a Window, it detaches automatically from the parent.
Hi
rdgrimes
For the end user, in the modal window, i have placed explicit close button to close the current screen and back to the listing window. So how i can do this in MVVM.
You can check here.
What Senthil means is: Where is the place in a MVVM to call programatically a myWindow.onClose();
@terrytornado, @Senthilchettyin:
I really don't know what you're looking for because you don't need to call myWindow.onClose(). Per the Window source:
/** Process the onClose event sent when the close button is pressed. * <p>Default: detach itself. */ public void onClose() { detach(); }
Further, the documentation makes it clear that you don't need to send the onClose event, but the clicking of the close button automatically sends the onClose event so that the above cited method is invoked:
"Once the user clicks on the close button, an onClose event is sent to the window which is processed by the onClose method of the Window component. Then, onClose, by default, detaches the window itself." - source
And, since Senthichettyin stated previously he supplied a close button in the modal window so the user could click it, there is no need to call onClose() explicitly. The user's action will cause the detach to occur.
Hi
I dont think so we are all in the same page. Rdgrimes, We are NOT talking about the default close button in the top right corner of the window with X Mark. (This will appear when you set closable property (Window.setClosable(boolean)) to true.
All we are asking, how to close the current window by clicking button using button component using MVVM.
Just a small example, in any typical crud window, we will always have save and cancel button in the bottom, so that either user can enter the information in the
window and click save button , or they can simple cancel the operation and back to the listing window.
Regards
Senthil M
So, are you asking how to close the window after the save button is clicked? If so, why can't you, in the save button @command:
onClick="@command('save', target=self)"
Then, in your viewmodel's save method, you have access to the self component via:
@Command public void save(@BindingParam("target")Component target){ }
I haven't tested it, but you should be able to access target or an ancestor of target (whichever ancestor is the actual Window component), casting it to Window, and execute its detach method.
@Senthilchettyin, maybe I'm missing the obvious and I might not undertand exactly what you mean? Do you mean you want to explicitly close a window from you ViewModel?
I do that by binding the window in my ViewModel with @Wire
for example I have a popup window definedi in my zul and I want the viewmodel to close it after the user does "search"...
@Wire("#catFilterPopup") protected Popup catFilterPopup; @AfterCompose public void afterCompose(@ContextParam(ContextType.VIEW) org.zkoss.zk.ui.Component view){ Selectors.wireComponents(view, this, false); } @Command public void search() { //do stuff catFilterPopup.close(); }
In your case if you want to close the entire window that is bound by the ViewModel, did you try wiring the window id like I do above with the Popup? I'd think it would behave the same way but I haven't tried. Just bind the window by id then manually close it where you want in the ViewModel?
I do that by binding the window in my ViewModel with @Wire
Does this not brokes the MVVM paradigm?
@rickr, terrytornado:
The ZK team recommends against rickr's approach. See link
"Although the design principle of MVVM pattern is that ViewModel should not have any reference to UI components, ZK still provides two ways to retrieve UI components in a ViewModel. However, we do not suggest this usage as it loses ViewModel an important advantage: loose coupling with View. Notice that binder also manipulates UI components, so your operation to UI components may affect binder's work. Please be careful when using it."
Instead, the proper way to do it is as I detailed in my previous post (passing a reference of self or an ancestor thereof via the @command, which is then received as a binding parameter in the vm method).
Asked: 2012-11-15 14:01:50 +0800
Seen: 552 times
Last updated: Dec 07 '12