Uluk Biy
Uluk Biy

Reputation: 49185

Triggering Primefaces p:selectOneMenu onchange

It seems Primefaces p:selectOneMenu component wraps the rendered HTML <select> tag in a div and shows the selected item as a different label. The changes made by the user are reflected to original <select> by javascript I guess, resulting the onchange event binded to <select> not to be worked. Thus my following binding of onchange event for all :inputs is not working for p:selectOneMenus.

function applyChangeHandler() {
    $(':input').on('change', function() {
        console.log('on change: ' + this.id);
    });
}

However onchange attribute of p:selectOneMenu is being fired. So Primefaces triggers this handler under the hood (again I guess).

<p:selectOneMenu id="myList" onchange="console.log('selectOneMenu')">
    <f:selectItem itemLabel="val1" itemValue="val1"/>
    <f:selectItem itemLabel="val2" itemValue="val2"/>
</p:selectOneMenu>

So my requirement is to somehow bind the onchange handler to all p:selectOneMenus from applyChangeHandler() function above. Or it may be triggerred manually with Primefaces specific API or other ways which I expect from you guys to share with. Otherwise a quick workaround will be to use h:selectOneMenu instead.

My goal is to detect "unsaved changes on the page". So script above will be placed in a common template as:

<p:outputPanel id="sc" autoUpdate="true">
    <script type="text/javascript">
        applyChangeHandler();
    </script>
</p:outputPanel>

Upvotes: 1

Views: 11410

Answers (3)

Abdulrhman Alkhodiry
Abdulrhman Alkhodiry

Reputation: 2248

You need to add widgetVar to p:selectOneMenu to play with it in JS

<p:selectOneMenu id="myList" onchange="console.log('selectOneMenu')" widgetVar="myList">
  <f:selectItem itemLabel="val1" itemValue="val1"/>
  <f:selectItem itemLabel="val2" itemValue="val2"/>
</p:selectOneMenu>

this Will add this code to you page

$(function(){
  PrimeFaces.cw("SelectOneMenu","myList",{
       id:"A2:Form:myList",
       effect:"fade"
  })
});

Hope this will help.

Upvotes: 0

Fraction
Fraction

Reputation: 463

Instead of using onChange, you could utilize "DOMSubtreeModified".

This works for p:selectOneMenu

$(".ui-selectonemenu-label").each(function(index) {
    $(this).on("DOMSubtreeModified", setDirty());
});

Also. Another possibility if you want the same generic code everywhere is to overwrite the prototype of SelectOneMenu as follows:

var origTriggerChange = PrimeFaces.widget.SelectOneMenu.prototype.triggerChange;
// if this code has been run already, don't accumulate triggerChangemethods!
if(origTriggerChange.isModified != "true"){
      PrimeFaces.widget.SelectOneMenu.prototype.triggerChange = function(b){
      this.jq.find("select").change();
      origTriggerChange.call(this, b);
   };
   PrimeFaces.widget.SelectOneMenu.prototype.triggerChange.isModified = "true";
}

Upvotes: 0

kidwon
kidwon

Reputation: 4504

Why do you need to provide additional listeners when the framework has already provided you with such?

If your goal is to use jQuery you just put your handler in a js file accessible from the window global scope.

function myChangeHandler(that) {
    //wrap the element with jQuery
    var select = jQuery(that);
    //Get the div parent. The actual wrapper of the `selection-menu` widget markup
    var selectMenu = select.parents('div.ui-selectonemenu');
    //From here I can manipulate any HTML child element using jQuery
    jQuery('label.ui-selectonemenu-label', selectMenu).text('mooo');
}

Then call your handler onchange, passing the selectOneMenu as parameter

<p:selectOneMenu id="myList" onchange="myChangeHandler(this)">
    <f:selectItem itemLabel="val1" itemValue="val1" />
    <f:selectItem itemLabel="val2" itemValue="val2" />
</p:selectOneMenu>

Upvotes: 1

Related Questions