locked
HTML client (March 2014 update) - auto selecting first item in Visual Collection in Table control - bug? RRS feed

  • Question

  • One can use the following code in the created event of a screen to select the first item in a visual collection bound to a Table control (or any list control - code based on an old example from Huy):

    myapp.MyScreen.created = function (screen) {
    
        var visualCollection = screen.Orders;
    
        function selectFirst() {
    	var first = visualCollection.data[0];
    	visualCollection.selectedItem = (first) ? first : null;
        }
    
        if (visualCollection.state === msls.VisualCollection.State.idle) {
    	// If the visual collection is already loaded, try selecting the first item.
    	selectFirst();
        } else {
    	// Otherwise, listen to the state change event and when the visual collection is loaded,
    	// select the first item. Also remove the event handler because this should only happen once.
    	function onVisualCollectionStateChanged() {
                if (visualCollection.state === msls.VisualCollection.State.idle) {
    		visualCollection.removeChangeListener("state", onVisualCollectionStateChanged);
    	    }
    	    selectFirst();
    	}
    	// add the change listener
    	visualCollection.addChangeListener("state", onVisualCollectionStateChanged);
        };
    };

    This will indeed selected the first item in the Orders visual collection, but will not show that item as selected (using the blue selector) in the Table control. Even more confusing, if you now tap the first item in the Table it looks like you cannot select it - you have to select the second item and then you can visually select the first item again.

    I suspect that this is a bug in the Table control - can anyone confirm or provide a workaround?


    Regards, Xander. My Blog

    Wednesday, April 23, 2014 2:32 AM

Answers

  • By experimenting with your code, I suspect you have come up with a bug, or at least a flaw, in LightSwitch's MVVM architectural programming pattern, in that the View Model fails to update the View (the blue highlighting of the selected table row) while correctly data binding the Model (setting the selectedItem equal to the first entity in the screen's visual collection).

    Your code is excessively complex.  I also don't know if there is a compelling reason that you need to place this code in the screen's created method.  I was able to select the first item in a table, with row highlighting, using the _postRender method of the "Table Row | Rows" code behind, as follows:

    myapp.BrowseOrders.rows_postRender = function (element, contentItem) {
    
    var visualCollection = contentItem.screen.Orders;
    
    if (visualCollection.isLoaded && visualCollection.data[0] != null) 
        visualCollection.selectedItem = visualCollection.data[0];
    
    };


    Wednesday, April 23, 2014 4:58 AM
  • Thanks for confirming that you see the same behavior. Perhaps it is a side-effect rather than a bug.

    Although the code is overly complex (it was a copy from some code Huy provided in the early days), I have wrapped it into a reusable function, so it is just a one line call like so:

    LSU.selectFirstInVisualCollection(contentItem.screen.Orders);

    I have tried your code in the "Table | Table Row" _postRender but it does not work for me and I believe the reason is that there are a number of dropdown lists used for filtering on the Table that need to be populated and perhaps it is a timing thing.

    However, if I add my function (or the one line call to the reusable function) to the "Table | Table Row" _postRender then it does indeed work!

    So thanks for the "Table | Table Row" _postRender hint as that seems to have been the breakthrough to make it work!

    Thanks again


    Regards, Xander. My Blog

    • Edited by novascape Wednesday, April 23, 2014 5:15 AM
    • Marked as answer by novascape Wednesday, April 23, 2014 5:44 AM
    Wednesday, April 23, 2014 5:14 AM

All replies

  • By experimenting with your code, I suspect you have come up with a bug, or at least a flaw, in LightSwitch's MVVM architectural programming pattern, in that the View Model fails to update the View (the blue highlighting of the selected table row) while correctly data binding the Model (setting the selectedItem equal to the first entity in the screen's visual collection).

    Your code is excessively complex.  I also don't know if there is a compelling reason that you need to place this code in the screen's created method.  I was able to select the first item in a table, with row highlighting, using the _postRender method of the "Table Row | Rows" code behind, as follows:

    myapp.BrowseOrders.rows_postRender = function (element, contentItem) {
    
    var visualCollection = contentItem.screen.Orders;
    
    if (visualCollection.isLoaded && visualCollection.data[0] != null) 
        visualCollection.selectedItem = visualCollection.data[0];
    
    };


    Wednesday, April 23, 2014 4:58 AM
  • Thanks for confirming that you see the same behavior. Perhaps it is a side-effect rather than a bug.

    Although the code is overly complex (it was a copy from some code Huy provided in the early days), I have wrapped it into a reusable function, so it is just a one line call like so:

    LSU.selectFirstInVisualCollection(contentItem.screen.Orders);

    I have tried your code in the "Table | Table Row" _postRender but it does not work for me and I believe the reason is that there are a number of dropdown lists used for filtering on the Table that need to be populated and perhaps it is a timing thing.

    However, if I add my function (or the one line call to the reusable function) to the "Table | Table Row" _postRender then it does indeed work!

    So thanks for the "Table | Table Row" _postRender hint as that seems to have been the breakthrough to make it work!

    Thanks again


    Regards, Xander. My Blog

    • Edited by novascape Wednesday, April 23, 2014 5:15 AM
    • Marked as answer by novascape Wednesday, April 23, 2014 5:44 AM
    Wednesday, April 23, 2014 5:14 AM
  • Naturally it's not possible to reproduce the exact scenario your screen depicts in my simple example.  I will add, however, that including an event listener allowing the visual collection to completely load, if there happens to be delays, may help you or anyone else wanting to programmatically select a Table item as follows:

    myapp.BrowseOrders.rows_postRender = function (element, contentItem) {
    
    var visualCollection = contentItem.screen.Orders;
    
    if (visualCollection.isLoaded && visualCollection.data[0] != null) 
        visualCollection.selectedItem = visualCollection.data[0];
        else {
            visualCollection.addChangeListener('isLoaded', function () {
            visualCollection.selectedItem = null || visualCollection.data[0];
        }
    };

    Not to pick on you or Huy for that matter (although I strongly suspect he would be completely familiar with this), but here is an example of a JavaScript feature that will simplify your code and make it easier for others to interpret.

    Instead of the expression:

    visualCollection.selectedItem = (first) ? first : null;
        

    ...a more concise and simpler expression is to use the null coalescing feature of the logical Or operator (||, see above), since JavaScript does not have the equivalent "??" C# operator or VB.net's If() operator.


    Wednesday, April 23, 2014 6:20 AM
  • Thanks for the correct code - that is how we learn. Javascript is a big leap for us previously non-Javascript developers.

    Just to be clear, the "(first) ? first : null;" part was my own addition and not part of the original code which is here btw:

    master-detail-select-first-value

    I've changed my reusable function as per your new example above and it works well.

    Question: when we add in-line change listeners as you've illustrated above, do we still have to worry about cleaning up the change listeners when the screen is closed or does garbage collection automatically take care of that?

    Thanks


    Regards, Xander. My Blog

    • Edited by novascape Wednesday, April 23, 2014 6:58 AM
    Wednesday, April 23, 2014 6:58 AM
  • Can you use a button to select an entire visual collection? This could be useful for, say, printing a list, or even copying to a clipboard. Given that LS HTML cannot export to xcel or any other format without extensive coding and other work, selecting an entire collection with a button could be helpful?

    Thank you!

    Friday, April 1, 2016 4:57 PM