Opened 7 years ago

Closed 7 years ago

Last modified 7 years ago

#15676 closed defect (invalid)

The onChange event of dijit.form.CheckBox is triggered before the onClick event of the outer DOM node.

Reported by: siqi Owned by: Douglas Hays
Priority: undecided Milestone: tbd
Component: Dijit - Form Version: 1.8.0b1
Keywords: Cc:
Blocked By: Blocking:

Description

<div onclick="console.log('div clicked');">
	<input id="cb1" data-dojo-id="cb1" data-dojo-type="dijit/form/CheckBox" 
	data-dojo-props='name:"cb1", value:"foo", onClick: function(value){console.log("CheckBox Clicked");}, onChange:function(value){console.log("CheckBox onChange")}'/>
</div>

With above code, click on the checkbox, the console logs: CheckBox? Clicked -> div Clicked -> CheckBox? onChange. As in dijit/form/_FormWidgetMixin.js, onChange is triggered with a defer, it seems aim at some issues. But not sure whether such event order is intended.

_handleOnChange: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
...
// defer allows hidden value processing to run and
// also the onChange handler can safely adjust focus, etc
this._onChangeHandle = this.defer(
    function(){
    this._onChangeHandle = null;
    this.onChange(newValue);
}); // try to collapse multiple onChange's fired faster than can be processed
...
}

Change History (4)

comment:1 Changed 7 years ago by Douglas Hays

Resolution: invalid
Status: newclosed

It is intended that onChange happens after onClick of the CheckBox?. There's no contract about the order of onChange wrt bubbled click events to parent nodes.

comment:2 Changed 7 years ago by siqi

Doug, I totally agree that onChange shoud happend after onClick, what I feel confused is that the onChange event doesn't get triggered immediately after onClick (it is triggered asychronously). Let's have a look at following code snippet. It simply updates a global check box status map when the onChange even get triggered. When you click on the container of these check boxes, you can get the check status from the status map. Since the onChange event is triggered after the onClick event to the parent node, when you click on a checkbox, you can not get the correct value from the status map while the checked attribute does change correctly...

	<script type="text/javascript">
		dojo.require("dijit.form.CheckBox");
		var itemStatus = {};
		function updateStatusMap(){
			console.log('updateStatusMap');
			itemStatus[this.id] = this.checked;
		}
		function onContainerClick(){
			console.log('onContainerClick');
                        debugger;
		}
		
	</script>
</head>
<body class="claro">
<div onclick="onContainerClick()">
	<input id="cb1" data-dojo-type="dijit/form/CheckBox" data-dojo-props='onChange:updateStatusMap'/>
	<input id="cb2" data-dojo-type="dijit/form/CheckBox" data-dojo-props='onChange:updateStatusMap'/>
	<input id="cb3" data-dojo-type="dijit/form/CheckBox" data-dojo-props='onChange:updateStatusMap'/>
</div>

comment:3 Changed 7 years ago by Douglas Hays

Mixing native synchronous events with asynchronous widget pseudo-events will introduce races that you don't want. I would recommend only using Dojo pseudo-events which will also reduce the number of event handlers as well:

dojo.ready(function(){
dojo.on(
        dojo.byId("pz"),
        "attrmodified-checked",
        function(evt){
                var widget = dijit.byNode(evt.target);
                console.log('updateStatusMap');
                itemStatus[widget.id] = widget.checked;
                onContainerClick();
        }
)
});
...
<div id="pz">
	<input id="cb1" data-dojo-type="dijit/form/CheckBox"/>
	<input id="cb2" data-dojo-type="dijit/form/CheckBox"/>
	<input id="cb3" data-dojo-type="dijit/form/CheckBox"/>
</div>

comment:4 in reply to:  3 Changed 7 years ago by siqi

Replying to doughays: Yes, the 'attrmodified-checked' event can be used to solve the problem. But as I know, it's introduced in dojo 1.8, so I'm afraid it doesn't work in dojo 1.7... Actually, I just don't want to drop native events for using Dojo pseudo-events... Don't understand why the onChange event of CheckBox? is asynchronous though it maybe useful for some widgets such as slider...

Mixing native synchronous events with asynchronous widget pseudo-events will introduce races that you don't want. I would recommend only using Dojo pseudo-events which will also reduce the number of event handlers as well:

dojo.ready(function(){
dojo.on(
        dojo.byId("pz"),
        "attrmodified-checked",
        function(evt){
                var widget = dijit.byNode(evt.target);
                console.log('updateStatusMap');
                itemStatus[widget.id] = widget.checked;
                onContainerClick();
        }
)
});
...
<div id="pz">
	<input id="cb1" data-dojo-type="dijit/form/CheckBox"/>
	<input id="cb2" data-dojo-type="dijit/form/CheckBox"/>
	<input id="cb3" data-dojo-type="dijit/form/CheckBox"/>
</div>
Note: See TracTickets for help on using tickets.