locked
Implement change listener to re-evaluate screen.created function RRS feed

  • Question

  • Hello,

    I am using the following function on a myapp.screen.created method, and it works well...

    myapp.AddEditHoldingInventory.StrInventoryStatus_postRender = function (element, contentItem) {
        // Write code here.
        contentItem.dataBind("screen.HoldingInventory.StrInventoryStatus", function (value) {
            contentItem.validationResults = [];
        });
    }
    
    myapp.AddEditHoldingInventory.created = function (screen) {
    
            var deviceType = screen.HoldingInventory.StrDeviceType;
            var deviceManu = screen.HoldingInventory.StrManufacturer;
            var macAddress = screen.HoldingInventory.StrMacAddress;
    
            if (deviceType == "Laptop" || deviceType == "Desktop" && macAddress == null) {
    
                screen.findContentItem("StrMacAddress").validationResults = [
    
                    new msls.ValidationResult(
    
                        screen.HoldingInventory.details.properties.StrMacAddress,
    
                        "Physical MAC address required to add a Lenovo device to Inventory..."
    
                        )
                ];
    
                return false;
    
            }
            
        }

    The issue is that I need a changeListener on StrMacAddress, so that when it IS entered, this statement will be re-evaluated and the validation will pass. Is that how a changeListener should work?

    I have tried adding lines (commented lines below) such as this...

    myapp.AddEditHoldingInventory.created = function (screen) {
    
        var deviceType = screen.HoldingInventory.StrDeviceType;
        var deviceManu = screen.HoldingInventory.StrManufacturer;
        var macAdress = screen.HoldingInventory.StrMacAddress;
    
        //function updateMacAddress() {
    
            if (deviceType == "Laptop" || deviceType == "Desktop" && macAddress == null) {
    
                screen.findContentItem("StrMacAddress").validationResults = [
    
                    new msls.ValidationResult(
    
                        screen.HoldingInventory.details.properties.StrMacAddress,
    
                        "Physical MAC address required to add a Lenovo device to Inventory..."
    
                        )
                ];
    
                return false;
    
            }
    
            //screen.HoldingInventory.addChangeListener("StrMacAddress", updateMacAddress);
    
        }

    But then the validation does not work at all.

    Please advise. Thank you in advance...

    Tuesday, December 6, 2016 10:22 PM

All replies

  • Hi,

    You probably want to go with a dataBind on the property. 

    //updateMacAddress function
    myapp.AddEditHoldingInventory.updateMacAddress = function(screen){
        var deviceType = screen.HoldingInventory.StrDeviceType;
        var deviceManu = screen.HoldingInventory.StrManufacturer;
        var macAdress = screen.HoldingInventory.StrMacAddress;
    
    	(...)
    }
    
    //If you are setting this up on the created method:
    myapp.AddEditHoldingInventory.created = function (screen) {
    	screen.getHoldingInventory().then(function(holdingInventorySet){ //making sure its loaded before the first dataBind
    		screen.findContentItem("StrMacAddress").dataBind("value",function(newValue){	
    			updateMacAddress(screen); //you could pass the newValue here to a more generic validation function
    		});
    	});
    }
    
    //Or if you have the property on screen, you can set it on the contentItem's postRender: 
    myapp.AddEditHoldingInventory.StrMacAddress_postRender = function (element, contentItem) {
        contentItem.screen.getHoldingInventory().then(function(holdingInventorySet){ //again just making sure its loaded before the first dataBind
    		contentItem.dataBind("value",function(newValue){
    			updateMacAddress(contentItem.screen); 
    		});
    	});
    };

    Hope it helps!

    Nuno

    Wednesday, December 7, 2016 2:50 PM
  • Thank you very much! I am a little confused where the myapp.AddEditHoldingInventory.updateMacAddress function should live. Right now I have a data bind on the StrInventoryStatus properties postrender, and what is essentially the 'updateMacAddress' function on the screen.created method. This is what the code looks like:

    myapp.AddEditHoldingInventory.StrInventoryStatus_postRender = function (element, contentItem) {
        // Write code here.
        contentItem.dataBind("screen.HoldingInventory.StrInventoryStatus", function (value) {
            contentItem.validationResults = [];
        });
    }
    
    myapp.AddEditHoldingInventory.created = function (screen) {
    
        var deviceType = screen.HoldingInventory.StrDeviceType;
        var deviceManu = screen.HoldingInventory.StrManufacturer;
        var macAdress = screen.HoldingInventory.StrMacAddress;
    
            if (deviceType == "Laptop" || deviceType == "Desktop" && deviceManu == "Lenovo" && macAddress == null) {
    
                screen.findContentItem("StrMacAddress").validationResults = [
    
                    new msls.ValidationResult(
    
                        screen.HoldingInventory.details.properties.StrMacAddress,
    
                        "Physical MAC address required to add a Lenovo device to Inventory..."
    
                        )
                ];
    
                return false;
    
            }
        }

    If I use your code on either the postrender or created method, where does the function I currently have on the .created method live?

    Thank you again!



    • Edited by CreedCor Wednesday, December 7, 2016 4:18 PM
    Wednesday, December 7, 2016 4:14 PM
  • I would extract the code from the created method into the a new custom updateMacAddress function (eventually this can be just a generic function that takes the predicate to test, the dataBind property, name and path and the validation method):

    myapp.AddEditHoldingInventory.updateMacAddress = function(screen){
        var deviceType = screen.HoldingInventory.StrDeviceType;
        var deviceManu = screen.HoldingInventory.StrManufacturer;
        var macAdress = screen.HoldingInventory.StrMacAddress;
    
        if (deviceType == "Laptop" || deviceType == "Desktop" && deviceManu == "Lenovo" && macAddress == null) {
        screen.findContentItem("StrMacAddress").validationResults = [new msls.ValidationResult(screen.HoldingInventory.details.properties.StrMacAddress,"Physical MAC address required to add a Lenovo device to Inventory...")];
                return false;
            }
    }

    And if binded from the created method:

    myapp.AddEditHoldingInventory.created = function (screen) {
    	screen.getHoldingInventory().then(function(holdingInventorySet){ //making sure its loaded before the first dataBind
    		screen.findContentItem("StrMacAddress").dataBind("value",function(newValue){	
    			updateMacAddress(screen); //you could pass the newValue here to a more generic validation function
    		});
    	});
    }

    Or if binded from the post render of the property on screen:

    myapp.AddEditHoldingInventory.StrMacAddress_postRender = function (element, contentItem) {
        contentItem.screen.getHoldingInventory().then(function(holdingInventorySet){ //again just making sure its loaded before the first dataBind
    		contentItem.dataBind("value",function(newValue){
    			updateMacAddress(contentItem.screen); 
    		});
    	});
    };
    Nuno

    Wednesday, December 7, 2016 5:43 PM
  • Thank you for the suggestions!

    When I use this configuration on the .created method, the screen does not...create. It's like their is no item-tap assigned on the BrowseHoldingInventory which usually will open the AddEditHoldingInventory screen.

    When I use this configuration on the _postrender method, the updateMacAddress function does not do anything. Its like none of the code is even there. No errors or breaks, but the validationresult does not fire.

    This is what the screen looks like using the .created method...

    myapp.AddEditHoldingInventory.updateMacAddress = function (screen) {
    
        var deviceType = screen.HoldingInventory.StrDeviceType;
        var deviceManu = screen.HoldingInventory.StrManufacturer;
        var macAdress = screen.HoldingInventory.StrMacAddress;
    
        if (deviceType == "Laptop" || deviceType == "Desktop" && deviceManu == "Lenovo" && macAddress == null) {
    
            screen.findContentItem("StrMacAddress").validationResults = [
    
                new msls.ValidationResult(
    
                    screen.HoldingInventory.details.properties.StrMacAddress,
    
                    "Physical MAC address required to add a Lenovo device to Inventory..."
    
                    )
            ];
    
            return false;
    
        }
    }
    
    myapp.AddEditHoldingInventory.created = function (element, contentItem) {
        // Write code here.
        screen.getHoldingInventory().then(function (holdingInventorySet) { //making sure its loaded before the first dataBind
            screen.findContentItem("StrMacAddress").dataBind("value", function (newValue) {
                updateMacAddress(screen); //you could pass the newValue here to a more generic validation function
            });
        });
    }

    With this configuration, the AddEditHoldingInventory screen just doesn't open. Clicking on the line item on BrowseHoldingInventory just does nothing.

    Wednesday, December 7, 2016 6:09 PM
  • Im sorry I didn't run/tested/debug any of the above.

    Invoke 

    myapp.AddEditHoldingInventory.updateMacAddress(screen)

     instead of 

    updateMacAddress(screen)

    It's probably crashing there. I don't know if there is something else, I didn't run or tested any of the above, sry.

    I also noted your created method is taking the wrong args, it only takes the screen as an arg:

    myapp.AddEditHoldingInventory.created = function (element, contentItem) {

    should be

    myapp.AddEditHoldingInventory.created = function (screen) {

    • Edited by Nuno Dâmaso Wednesday, December 7, 2016 6:20 PM created method
    Wednesday, December 7, 2016 6:17 PM
  • Thank you again.

    So, invoking myapp.AddEditHoldingInventory.updateMacAddress on the _postrender method of StrMacAddress makes this all work as it did before.

    There is still no event or change listener happening on the property. 

    My updateMacAddress function works for validation and either runs when the screen is created, or on the postrender of the StrMacAddress property... but it is not re-evaluated when StrMacAddress no longer == null. That is what I am attempting to do. Without reloading the screen, re-evaluate updateMacAddress when a change is detected on StrMacAddress property. I hope that makes sense.

    Wednesday, December 7, 2016 6:34 PM
  • Data binding the StrMacAddress was to do just that - to re-eval when it changes, invoking the updateMacAddress.

    I'm sorry I'm not sure what can be wrong without testing /debugging.

    Wednesday, December 7, 2016 6:49 PM
  • No worries. Thank you for this.

    I am trying a slightly different approach with a changeListener. If I understand it correctly, the changeListener can be added to the .created method for the AddEditHolding screen, and it will 'listen' for changes to a given element while the screen is alive...?

    If so, it could look something like this? ...

    myapp.AddEditHoldingInventory.updateMacAddress = function (screen) {
    
        var deviceType = screen.HoldingInventory.StrDeviceType;
        var deviceManu = screen.HoldingInventory.StrManufacturer;
        var macAddress = screen.HoldingInventory.StrMacAddress;
    
        if (deviceType == "Laptop" || deviceType == "Desktop" && deviceManu == "Lenovo" && macAddress == null) {
    
            screen.findContentItem("StrMacAddress").validationResults = [
    
                new msls.ValidationResult(
    
                    screen.HoldingInventory.details.properties.StrMacAddress,
    
                    "Physical MAC address required to add a Lenovo device to Inventory..."
    
                    )
            ];
    
            return false;
    
        }
    }
    
    myapp.AddEditHoldingInventory.created = function (screen) {
        // Write code here.
        screen.addChangeListener("StrInventoryStatus", function () {
            myapp.AddEditHoldingInventory.updateMacAddress(screen);
    
        })
    }

    I am still playing with this. At the moment the updateMacAddress function isn't being called. I should get there eventually, ha.

    Thank you

    Wednesday, December 7, 2016 10:04 PM
  • Agree dataBind is the way to go. 

    At quick glance, I don't see anything wrong with the code, except where are you actually clearing the validation results.

    Perhaps add this in else branch to the updateMacAddress function

    screen.findContentItem("StrMacAddress").validationResults = []

    PS...  Here's another way to do validation that can be reused across all screens:

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/f84e841d-d5fe-4c63-84d8-9e3d25e7615d/best-place-to-put-client-side-property-validation-code-html-client?forum=lightswitch

    HTH,

    Josh


    • Edited by joshbooker Sunday, December 11, 2016 2:19 PM PS
    Sunday, December 11, 2016 2:11 PM