locked
Simple control value changed notifications

    Question

  • Hi all, I have created my own 'class' to manage ComboBoxes. The class itself is simple and it just creates a select control and adds its options to it. The thing is I need to know when they've changed so I can do more stuff.

    Here the living sample. I have two ComboBoxes in my form. One of them has a list of countries and the second one loads cities from the selected country. So what I need is to my cities combo be notified somehow that the country combo changed so I can go ahead and reload the cities.

    I have been playing around with WinJS.Class.mix firing a custom 'dependantChanged' event (took the sample from here: http://msdn.microsoft.com/en-us/library/windows/apps/hh967789.aspx). What I'm seeing is that both Combos (Country and City) fire the event, keep in mind it is they are two instances of the same class. Only the city combo is has an event listener to that event, and I see the city combo capturing the event only when it is fired by itself. When the country combo fires the event the city combo does not capture it :(

    What am I doing wrong?

    This is pretty much the important parts of my control (class):

    var _myComboBox = WinJS.Class.define(
    
    	function (element, options) {
    		this.parent = element;
    		element.appendChild(select);
    		select.disabled = options.mode == 'view';
    		this.select = select;
    
    		if (options.serviceUrl) {
    			var fullUri = "http://myserver/rest/" + options.serviceUrl;
    			if (options.params) {
    				fullUri = fullUri + '?' + options.params + '=1';
    				this.addEventListener('dependantChanged', this.reload.bind(this));
    			}
    			WinJS.xhr({ url: fullUri })
    			.done(function (response) {
    				var data = JSON.parse(response.responseText);
    				for (i = 0; i < data.length; i++) {
    					item = data[i];
    					this.addOption(item[0], item[1]);
    				}
    
    			}.bind(this));
    		}
    
    		this.select.addEventListener("change", this.changed.bind(this));
    	},
    	{
    		reload: function (data){
    			MyControl.UI.showMessage('selectedItem: ' + data.target.selectedItem);
    		},
    		changed: function () {
    			this.value = this.select.value;
    			this.dispatchEvent('dependantChanged');
    		},
    	});
    
    WinJS.Class.mix(_myComboBox, WinJS.Utilities.eventMixin);
    WinJS.Class.mix(_myComboBox, WinJS.Utilities.createEventProperties('dependantChanged'));

    EDIT: Full repro project here http://sdrv.ms/OgmFlx


    http://bit.ly/sebagomez



    Monday, August 13, 2012 4:17 PM

Answers

  • Hi Sebastian,

    I am sorry I was not sensitive to your level of expertise.  You cannot arbitrarily fire an event that everyone will get.  Each element must subscribe to the events they wish to capture using the addEventListener method.

    Does that make things a little clearer?

    -Jeff


    Jeff Sanders (MSFT)

    Friday, August 17, 2012 8:54 PM
    Moderator

All replies

  • Hi Sebastian,

    There is not enough of a repro to comment on what your problem may be.  Please post a repro for investigation.  Why don't you simplify this and simply trap the change event of the native control and call a function to do your work on the 2nd control?

    -Jeff


    Jeff Sanders (MSFT)

    Monday, August 13, 2012 6:00 PM
    Moderator
  • Hi Jeff, thanks for answering. I want to make my control as 'open' as possible, so I don't want to tie it to another control. I want it to raise an event and whoever is listening to do the desired actions.

    I don't understand why you say that the code is not enough to see my problem, the only thing missing are the two divs I have in my html page with myComboBox as the data-win-control.

    Can you please let me know what else would you need? Do you think both my combos should be able to catch the raised event?

    Regards

     

    http://bit.ly/sebagomez

    Monday, August 13, 2012 6:06 PM
  • Hi Sebastian,

    I do not see you doing anything wrong by inspection so I need to repro the issue myself.

    You can simplify the example using static data so I have a self contained repro to investigate with.  Any time you save me lets me investigate deeper and allows me to help everyone on the forums.  If you do not have time to create a simple repro, that is fine.  I will investigate later when I have time to build a complete repro.

    -Jeff


    Jeff Sanders (MSFT)

    Monday, August 13, 2012 6:52 PM
    Moderator
  • I know what you mean Jeff, I'll try to create a small repro project. Since we're only two days away for RTM, do you think I should wait and test with that build first?

    There's a lot of time involved in creating a functional repro project.

    EDIT: Nevermind :) here it is http://sdrv.ms/OgmFlx thanks for your help


    http://bit.ly/sebagomez



    Tuesday, August 14, 2012 2:34 AM
  • Thanks!


    Jeff Sanders (MSFT)

    Wednesday, August 15, 2012 11:53 AM
    Moderator
  • Hi Sebastian,

    You want to modify your control.js file to this:

    var _myComboBox = WinJS.Class.define(
    
    		function (element, options) {
    			this.parent = element;
    			this.selectedItem = null;
    			var i = 0;
    			var item;
    			var select = document.createElement('select');
    			element.appendChild(select);
    			this.select = select;
    
    			if (options.entity == 'Country') {
    				var countries = My.Data.getCountries();
    				for (i = 0; i < countries.length; i++) {
    					this.addOption(countries[i].id, countries[i].name);
    				}
    			} else {
    				var cities = My.Data.getCities("UY"); // <--- how do I get the selected country?
    				for (i = 0; i < cities.length; i++) {
    					this.addOption(cities[i].id, cities[i].name);
    				}
    			
    			}
    
    			if (options.dependsOn) {
    			    var depCtl = document.getElementById(options.dependsOn).winControl;
    
    			    depCtl.addEventListener('dependantChanged', this.reload.bind(this)); // <--- this get handled ONLY when the city combo fires it
    			}
    
    			this.select.addEventListener("change", this.changed.bind(this));
    		},

    Realize that this is highly order dependent...  Your dependsOn: control must be after the one that it depends on!

    -Jeff


    Jeff Sanders (MSFT)


    Thursday, August 16, 2012 3:04 PM
    Moderator
  • Hi Jeff for you help but that solution is no good for me for a couple of things.

    1) I do not know the id of the element I'm depending on. I just write the repro project like that for clarification.

    2) I want to make sure the controls work always as expected, and not depending on how I layout my controls.

    So I was thinking of a more generic solution. I want to City combo to 'listen' for the 'CountryChanged' event. I don't want to tie my city control to the one from country, since I could have many different controls that might have things to do when the country is changed. I've been reading about Binding and Mixins. Is there a way I can implement what I need?

    Thanks again for your time.


    http://bit.ly/sebagomez

    Thursday, August 16, 2012 7:37 PM
  • RE: " do not know the id of the element I'm depending on." 

    Even in binding you have to specify what to bind to.  I have no idea how you could bind or listen to anything unless you tell the object what to listen for.


    Jeff Sanders (MSFT)

    Friday, August 17, 2012 1:18 PM
    Moderator
  • Thanks Jeff, please jeep in mind I'm pretty new to javascript. I was hoping I could have some mechanism to tell my control to notify 'everybody' when it changed and somehow tell other control when your 'hear' this event do this action.

    Let me put it in an abstract example. I have control A and control B. I want control A to fire an event when it changed, let's call it "aChanged". I need control B to listen to the event 'aChanged' and do something. But I want (at least if I can avoid it), to tell B "listen to what happens with A". Maybe what I want is not even possible.

    Thanks again for your time


    http://bit.ly/sebagomez

    Friday, August 17, 2012 3:03 PM
  • Hi Sebastian,

    I am sorry I was not sensitive to your level of expertise.  You cannot arbitrarily fire an event that everyone will get.  Each element must subscribe to the events they wish to capture using the addEventListener method.

    Does that make things a little clearer?

    -Jeff


    Jeff Sanders (MSFT)

    Friday, August 17, 2012 8:54 PM
    Moderator
  • It sure does.

    Thanks!


    http://bit.ly/sebagomez

    Friday, August 17, 2012 10:12 PM