Search code examples
javajavascriptprototypejstapestryzone

Tapestry Prototype selecting element by ID on zone updates


I have a zone on my page that contains a select element.

I'm adding an onChange listener on that element via JavaScript (thanks to http://jsfiddle.net/AnbmU/6/)

void afterRender() {
    javaScriptSupport.addScript(
        "$('groupSelecter').observe('change', function() {" + 
        "    var width = $(this).getWidth();" + 
        "    var selectBox = $('groupSelecter');" + 
        "    var chosen = selectBox.selectedIndex >= 0 ? selectBox.options[selectBox.selectedIndex].innerHTML : undefined;" + 
        "    $(this).next('.ninja-input')" + 
        "         .toggleClassName('hidden', chosen != 'Create New Group...')" + 
        "         .select();" + 
        "});",
        ""
    );
}

The problem occurs when I trigger a zone refresh, my select changes id to something like this: groupSelecter_846e54edd0b5.

Is there a way to either keep the select's element id constant or to be able to change javascript and select's id on each zone update?

EDIT: Another issue I was not aware of before.

Hidden input field is toggled each second change of selected elements, regardless of its contents. For example, if I had GROUP_1, GROUP_2, GROUP_3 and Create New Group... and GROUP_1 initially selected, and changed to GROUP_2, the input box appears. When I change it to Create New Group..., the input is hidden again. Again, when I change to GROUP_3, the input field appears. Mind you, in JSfiddle, this works just fine. But for some reason, it doesn't work in my Tapestry project.

EDIT2: OK, I tried some more fiddling:

Tapestry generated select element with id=groupSelecter_d769af562f89. It also generated inserted this JavaScript (on the bottom of HTML):

$$('.groupSelecter').invoke('observe', 'change', function() {
    var width = $(this).getWidth();
    var chosen = $(this).selectedIndex >= 0 ? $(this).options[$(this).selectedIndex].innerHTML : undefined;
    $(this).next('.ninja-input')
        .toggleClassName('ninja-hidden', chosen != 'Create New Group...');
});

I inpected the element in Firefox, navigated to tags, found the generated code and cut it out. After that, I opened firefox JS console and pasted that same exact code I just cut. And, voila, it works, for some reason. (Class selecting, that is).


Solution

  • You need to make sure you fire the javascript every time the select renders. You are currently only firing it on page render (not ajax update).

    You could either do it in a mixin, or you could add the script during page render AND ajax update. If you use a class attribute or data attribute (as suggested in other answers on this thread) you can just add the script via JavaScriptSupport in both events since the value is known before the select component renders.

    If you want to use the clientId in the ajax action this is slightly tricky because you can only add the script after the select component has rendered. Before this time the clientId will not be defined. If you want to do this I suggest returning a RenderCommand from your ajax action. Note that Block can be TypeCoerced to RenderCommand

    eg:

    @InjectComponent
    private Zone zone;
    
    @InjectComponent
    private Select groupSelector;
    
    @Inject
    private TypeCoercer typeCoercer;
    
    RenderCommand onActionFromSomeComponent() {
        return new RenderCommand() {
            public void render(MarkupWriter writer, RenderQueue queue) {
                RenderCommand zoneBody = typeCoercer.coerce(zone.getBody(), RenderCommand.class);
                zoneBody.render(writer, queue);
                javaScriptSupport.addScript(
                    "$('%s').observe('change', function() {" + 
                       // more stuff
                     "});",
                     groupSelector.getClientId()
                );
            }
        };
    }
    
    void afterRender() {
        javaScriptSupport.addScript(
            "$('%s').observe('change', function() {" + 
                // more stuff
            "});",
            groupSelector.getClientId()
        );
    }