Friday, March 5, 2010

New and better (?) ZoneUpdater

I recently sat down and did some evaluation of the ZoneUpdater code. I found that it is a bit hard to configure and debug, so I decided to do a little refactoring to trade some flexibility for readability and usability.

I also wanted to add a missing feature, the ability to update a zone simply by calling a javascript function. This is a nice way of "object orienting" different features/sections on a page, by giving different sections their own client API that they can communicate with.

Most important changes:
- Removed support for specifying another listening element than the container
- Cleaner code
- Request parameter instead of encoding parameter into link context.
- Generates a javascript variable to easy zone update through javascript.

I also wanted to add an internal listener that triggers the actual event with context, so the page/component listener doesn't have to inject the Request and do request.getParameter("param"). Didn't succeed so far.

Anyway, here's the modified code. No code formatting this time, but it should be short enough to be readable. Enjoy :)

ZoneUpdater.java


@IncludeJavaScriptLibrary( { "ZoneUpdater.js" })
public class ZoneUpdater {

@Inject
private ComponentResources resources;

@Environmental
private RenderSupport renderSupport;

/**
* The event to listen for on the client. If not specified, zone update can only be triggered manually through calling updateZone on the JS object.
*/
@Parameter(defaultPrefix = BindingConstants.LITERAL)
private String clientEvent;

/**
* The event to listen for in your component class
*/
@Parameter(defaultPrefix = BindingConstants.LITERAL, required = true)
private String event;

@Parameter(defaultPrefix = BindingConstants.LITERAL, value = "default")
private String prefix;

/**
* The element we attach ourselves to
*/
@InjectContainer
private ClientElement element;

@Parameter
private Object[] context;

/**
* The zone to be updated by us.
*/
@Parameter(defaultPrefix = BindingConstants.LITERAL, required = true)
private String zone;

void afterRender() {
String url = resources.createEventLink(event, context).toAbsoluteURI();
String elementId = element.getClientId();
JSONObject spec = new JSONObject();
spec.put("url", url);
spec.put("elementId", elementId);
spec.put("event", clientEvent);
spec.put("zone", zone);

renderSupport.addScript("%sZoneUpdater = new ZoneUpdater(%s)", prefix, spec.toString());
}
}





ZoneUpdater.js


var ZoneUpdater = Class.create({
initialize: function(spec) {
this.element = $(spec.elementId);
this.url = spec.url;
$T(this.element).zoneId = spec.zone;
if (spec.event) {
this.event = spec.event;
this.element.observe(this.event, this.updateZone.bindAsEventListener(this));
}
},
updateZone: function() {
var zoneManager = Tapestry.findZoneManager(this.element);
if ( !zoneManager ) return;

var updatedUrl = this.url;
if (this.element.value) {
var param = this.element.value;
if (param) {
updatedUrl = addParameter('param', param, updatedUrl); // You need to provide your own function for this...
}
}
zoneManager.updateFromURL(updatedUrl);
}
});

13 comments:

  1. Hi Inge,

    I'm using your original ZoneUpdater implementation, here is my code:



    public void onSelectChange(String value) {
    System.out.println("AAA");
    }

    The onSelectChange method gets called successfully, but the problem I'm seeing is that the value (which i'm expecting to be the value of the Select is always null).

    I understand Tapestry has implemented something similar to this in the current SNAPSHOT version with the zone parameter on select, but unfortunately our company policy is to not use SNAPSHOTs.

    Looking to get this fixed in the next day or so, would appreciate your input.

    Thanks,
    Ben.

    ReplyDelete
  2. It appears the template was lost, here it is again without the square brackets!

    t:select t:id="selectAddress" t:value="selectedAddressIndex" t:model="addressModel" blankOption="never" t:mixins="zoneUpdater" zone="addressZone" t:event="selectChange" t:clientEvent="change"/

    ReplyDelete
  3. If we use zoneUpdater in a linksubmit component,
    what should be the "t:clientEvent", what should be the event handling method signagure in the jave code?

    For example
    MySubmit

    is "submit" the correct event?
    What is the method signature for "myEvent"?

    thanks,

    ReplyDelete
  4. Sorry the sample code line did not show correctly,
    here it is:

    <t:linksubmit t:id="myId" t:mixins="x/zoneUpdater" zone="myZone" zoneUpdater.event="myEvent" clientEvent="submit">MySubmit</t:linksubmit>

    ReplyDelete
  5. When I use this mixin to my select model, the ajax submit clears all the textfields in my form. To be more specific,the zone encloses the form and the form encloses several textfields and a select with the mixin attached to it. If I type any text into the textfield, it will disappear whenever I make a selection from the drop down menu. Any ideas?

    Thanks

    ReplyDelete
  6. Thank for this ZoneUpdater, it helped me a lot !

    @Alexis

    I encountered the same issue. The problem is that Tapestry copy the textfield value in the Java variable only when the form is submitted.

    Then, when your zone is updated, the value which is displayed in the textfields is the value contained in Java variables.

    There is one easy way to avoid this problem.
    On each component (textfield, select, etc.) add a ZoneUpdater mixin which will only update Java value.

    Example for a textfield whose value is "text1":
    void onText1Updated() {
    text1 = request.getParameter("param");
    }

    The variable takes the new value, and won't be cleared next time you will refresh the zone.

    I hope this is clear!

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete
  8. This breaks in Tapestry 5.2, and I'm in the process of trying to fix it. Any chance you can post an update?

    ReplyDelete
  9. @desikage
    The jumpstart project uses an updated version, check it out at http://jumpstart.doublenegative.com.au/jumpstart/examples/javascript/ajaxonevent

    ReplyDelete
  10. Thanks for this great mixin!

    But there seems to be an UTF-8 encoding bug. Using this version the mixin replaced all special (non-ASCII) characters with "." or "$".
    Regarding to this [http://ecmanaut.blogspot.ch/2006/07/encoding-decoding-utf8-in-javascript.html] I had only to replace one line in ZoneUpdater.js:
    updatedUrl = addParameter('param', param, updatedUrl);
    to
    updatedUrl = addRequestParameter('param', unescape(encodeURIComponent(param)), updatedUrl);

    It would be nice if you could update your blog post (and the jumpstart -- if this is possible).

    Regards,
    René

    ReplyDelete
  11. Hi again, I've had more problems with this mixin. Since the content of the form is sent via GET parameter, there are several difficulties. For example, if you write a '+', it gets replaced with a space ' ', because the '+' (and many other characters, I guess) are not encoded for the url. And also, the maximal length of the input is limited to approximately 1000 tokens (depends on the browser).

    I don't use this mixin anymore. Instead, I realized the same behaviour with a non-tapestry form, a zone that includes a tapestry-form and some js around. When the user writes text in the non-tapestry form, js copies it to the tapestry-form and clicks on the submit button. The form is ajaxly sent via POST and can be handled by the server in a normal onSuccessFromMyDataSendForm() {} method.
    That's probably not as elegant as a mixin would be, but it works for me. And, the most important thing, it all works with common tapestry tools (t:form, t:actionlink, etc) and it sends the data using POST.

    Regards,
    René

    ReplyDelete
  12. INTERNATIONAL CONCEPT OF WORK FROM HOME
    Work from home theory is fast gaining popularity because of the freedom and flexibility that comes with it. Since one is not bound by fixed working hours, they can schedule their work at the time when they feel most productive and convenient to them. Women & Men benefit a lot from this concept of work since they can balance their home and work perfectly. People mostly find that in this situation, their productivity is higher and stress levels lower. Those who like isolation and a tranquil work environment also tend to prefer this way of working. Today, with the kind of communication networks available, millions of people worldwide are considering this option.

    Women & Men who want to be independent but cannot afford to leave their responsibilities at home aside will benefit a lot from this concept of work. It makes it easier to maintain a healthy balance between home and work. The family doesn't get neglected and you can get your work done too. You can thus effectively juggle home responsibilities with your career. Working from home is definitely a viable option but it also needs a lot of hard work and discipline. You have to make a time schedule for yourself and stick to it. There will be a time frame of course for any job you take up and you have to fulfill that project within that time frame.

    There are many things that can be done working from home. A few of them is listed below that will give you a general idea about the benefits of this concept.

    Baby-sitting
    This is the most common and highly preferred job that Women & Men like doing. Since in today's competitive world both the parents have to work they need a secure place to leave behind their children who will take care of them and parents can also relax without being worried all the time. In this job you don't require any degree or qualifications. You only have to know how to take care of children. Parents are happy to pay handsome salary and you can also earn a lot without putting too much of an effort.

    Nursery
    For those who have a garden or an open space at your disposal and are also interested in gardening can go for this method of earning money. If given proper time and efforts nursery business can flourish very well and you will earn handsomely. But just as all jobs establishing it will be a bit difficult but the end results are outstanding.

    Freelance
    Freelance can be in different wings. Either you can be a freelance reporter or a freelance photographer. You can also do designing or be in the advertising field doing project on your own. Being independent and working independently will depend on your field of work and the availability of its worth in the market. If you like doing jewellery designing you can do that at home totally independently. You can also work on freelancing as a marketing executive working from home. Wanna know more, email us on workfromhome.otr214422@gmail.com and we will send you information on how you can actually work as a marketing freelancer.


    Internet related work
    This is a very vast field and here sky is the limit. All you need is a computer and Internet facility. Whatever field you are into work at home is perfect match in the software field. You can match your time according to your convenience and complete whatever projects you get. To learn more about how to work from home, contact us today on workfromhome.otr214422@gmail.comand our team will get you started on some excellent work from home projects.


    Diet food
    Since now a days Women & Men are more conscious of the food that they eat hence they prefer to have homemade low cal food and if you can start supplying low cal food to various offices then it will be a very good source of income and not too much of efforts. You can hire a few ladies who will help you out and this can be a good business.

    Thus think over this concept and go ahead.

    ReplyDelete
  13. I think, needed to change line from
    if (this.element.value) {
    to
    if (this.element.val()) {

    ReplyDelete