locked
how to call clear button of html details picker control programmaticaly? RRS feed

  • Question

  • Neither of these work:

        screen.SelectedContinent = null;
    
        screen.findContentItem("SelectedContinent").value = null;

    thx

    paul


    paul van bladel

    Monday, June 23, 2014 1:32 PM

Answers

  • This is the code sample that someone previously posted to achieve cascading dropdowns between two controls for City and State:

    myapp.BrowseOrders.created = function (screen) {
        screen.USState = "AZ";
        stateDropDown = screen.findContentItem("StateDropdown");
        screen.getUSStates().then(function (result) {
            var index = result.data.length;
            var mylist = new Array();
            for (var i = 0; i < result.data.length; i++)
            {
                mylist[i] = { "value": i, "stringValue": result.data[i].StateName };
            }
            stateDropDown.choiceList = mylist;
            stateDropDown.dispatchChange("choiceList");
    	stateDropDown.dispatchChange("value");
        });
        screen.addChangeListener("StateDropdown", function () {
            stateDropDown = screen.findContentItem("StateDropdown");
            screen.USState = stateDropDown.choiceList[screen.StateDropdown].stringValue;
        });
    };
    
    myapp.BrowseOrders.CityDropdown_postRender = function (element, contentItem) {
        contentItem.dataBind("screen.StateDropdown", function () {
            if (contentItem.screen.USState != null)
            {
         myapp.activeDataWorkspace.MyEntitiesData.CityByState(contentItem.screen.USState)
                .execute()
                .then(function(result){
                    var index = result.results.length;
                    var mylist = new Array();
                    for (var i = 0; i < index; i++) {
                        mylist[i] = { "value": i, "stringValue": result.results[i].CityName };
                    }
                    contentItem.choiceList = mylist;
                    contentItem.dispatchChange("choiceList");
                    contentItem.dispatchChange("value");
                });
            };
        });
    };
    

    Note that the State is initialized to Arizona, and a dataBind function connects changes to the State with the City dropdown.

    You can achieve cascading dropdowns with little/no individual coding, if you happen to own ComponentOne's Studio for LightSwitch HTML controls:

    DROP DOWN: Filter

    Wednesday, June 25, 2014 2:18 PM
  • LittleBobbyTables,

    I got it to work simply using the screen designer and no code like this:

    Continent Entity related to Country Entity

    Order Entity related to Continent and Country

    Screen Designer (AddEditOrders):

    Include both Continent and Country pickers on layout

    Add Data Items Continents(All) and Countries(All)

    Countries | Edit Query | Add Parameter ContinentID | add Filter Country.Continent.id = Param

    Bind Param on Screen to Orders.Continent.Id 

    Set source query of pickers to Continents and Countries respectively

    Done

    Aside from clearing the child picker on change of parent picker this no-code solution works the same as in SL client for filtered drop downs.

    PS...I could be wrong, but I think this is a change from earlier versions as I read a year old comment from Huy that the picker choices queries fire only once.  Thus the need to do it in code.  Apparently this is no longer the case(?)

    HTH,

    Josh






    • Edited by joshbooker Wednesday, June 25, 2014 5:46 PM PS...
    • Marked as answer by Paul Van Bladel Thursday, June 26, 2014 4:51 AM
    Wednesday, June 25, 2014 2:28 PM

All replies

  • Is there an entity from your ViewModel that you can refer to the Data Context from the Properties window?

    If I were to guess what the Data Context might be, I would try:

    screen.Continent.selectedItem = null;

    Monday, June 23, 2014 3:01 PM
  • Hi,

    Indeed, screen.Continent refers to a single entity on the viewModel.

    As a result, screen.Continent has no selectedItem method.


    paul van bladel

    Monday, June 23, 2014 3:46 PM
  • No one?

    When I call 

    screen.SelectedContinent = null;

    SelectedContinent is an element on my viewModel (of type Continent)

    the contentItem is correctly updated to null, but I would expect that the control's value would be updated as well and that's not happening.



    paul van bladel

    Tuesday, June 24, 2014 10:26 AM
  • Hi Paul,

    The modal picker is a little strange about setting/updating display text.  I suspect after setting the value to null, then the serach box would be blank if you were to close and reopen the screen.  To force it to be blank you can set the input text like this (assuming you're working in the post Render of the picker control):

    $(element).find("input").val("");

    More info:

    http://social.msdn.microsoft.com/Forums/vstudio/en-US/108d54ff-bb0c-4e28-ab95-b05fa7ecf588/details-picker-based-on-sql-view?forum=lightswitch 

    HTH,

    Josh

    Tuesday, June 24, 2014 11:40 AM
  • Hi Josh,

    Thanks for helping me.

    No, Im' not going via post render.

    I'm simply trying to configure cascading drop downs and the scenario where I need to be able to set the current value of a dropdown to null is when the parent drop down changes. In that case the child dropdown needs to be "reset".

    Currently, just for testing, I put the code to set the current value of dropdown to null, just behind a button, but eventually I would move it to a changeListener on the parent dropdown.

    Cheers

    paul.


    paul van bladel


    Tuesday, June 24, 2014 1:25 PM
  • It seems like you've found a bug in LightSwitch's MVVM implementation, if setting screen.SelectedContent does not update your View as you describe.  This would be the 2nd bug reported here on the forums, although this one seems much more straightforward.

    So, since the recommended method of VM -> M -> V isn't working, you're faced with using the non-preferred methods VM->V->M, or even VM->V and VM->M with these:

    screen.findContentItem("SelectedContinent").value = null;  // or
    
    $(element).find("input").val("");

    The second line of code really makes me uncomfortable because if it works, you have set your Model value to null and your View value to empty string, which is inconsistent and liable to cause side effects.

    What is the Clear link really doing?  You had asked, can it be called programmatically?

    The Clear link is a boolean argument of the internal LS function _renderList, that when true, adds a blank link with event handlers that set detailsProperty to null using dependency injection.

    I'm not sure how you could call this internal function yourself, or if it's possible to use the dependency injection of detailsProperty in your user code, as I've not tried it.

    As a last resort, you may also try raising LightSwitch's change event handlers using

    contentItem.dispatchChange('value');

    ...which is the canonical method to inform LS that a View needs to be updated.  See this link and this link for more discussion on this method.

    Tuesday, June 24, 2014 4:14 PM
  • Wow,

    It always gives me a very comfortable feeling with so many javascript guroes around.

    You shared great insights !

    I discovered in the mean time that when giving focus  to  the dropdown and than leaving focus, does indeed update the text of the dropdown.

    Strange...

    Thanks


    paul van bladel

    Tuesday, June 24, 2014 4:59 PM
  • It tried dispatchChange and couldn't get it to work. 

    I believe the DetailsModalPicker is a frankenstien conglomerate of three controls (searchbox, autocompletebox and modal listview) each having 'values' which stay in 'sync' just well enough for it to work.  ...but they definitely break the pattern by not using proper binding.  Perhaps that's why the dispatch change doesn't work(?)  The only way I've been able to get this to work is to add the binding in _postRender, then the search text will blank out when you set the contentItem.value.

    myapp.AddEditOrder.SelectedContinent_postRender = function (element, contentItem) {
        // Write code here.
        contentItem.dataBind("value", function (newValue) {
            if (!newValue){
                $(element).find("input").val(null);
            }
        })
    };
    myapp.AddEditOrder.clearSelectedContinent_execute = function (screen) {
        // Write code here.
        var picker = screen.findContentItem("SelectedContinent");
        picker.value = null;
    };

    HTH,

    Josh


    • Edited by joshbooker Tuesday, June 24, 2014 7:55 PM
    • Proposed as answer by joshbooker Monday, September 15, 2014 10:27 AM
    Tuesday, June 24, 2014 7:54 PM
  • Thanks Josh,

    Will give that a try.

    A pity that so much code is needed for simple cascading dropdowns.

    Suggestions welcome if you know a simple approach for cascading dropdowns (with setting child dropdown to null when parent is updated).

    Thanks

    paul.


    paul van bladel

    Tuesday, June 24, 2014 8:00 PM
  • Hi Paul,

    You can do cascading drop downs without code by using parameter queries for choice lists and binding the parameter to <parentquery>.selectedItem.Id.  I think it's the same as on a SL screen.

    Let me know if you need more specific steps.

    HTH,

    Josh

    Wednesday, June 25, 2014 12:06 AM
  • Hi Josh,

    Sure, the underlying query mechanism is exactly what is done with SL.

    But, I want to add some logic when the user changes the parent dropdown value, the child dropdown is reset to null, in such a way the user is forced to make a new choice in the child dropdown.

    E.g. : continent and country dropdown. Current value of continent= europe and country = belgium. User opens the edit screen, and changes continent to africa. What we want now is that belgium is cleared. (the subject of this thread).

    Thanks a lot for your continuous support.

    paul.


    paul van bladel

    Wednesday, June 25, 2014 5:25 AM
  • Hey Paul, 

    I've seen some posts in the forums that make it seem like cascading drop downs are not possible without lots of code.  (for example, see LittleBobby's second link above)  They are doing State > City drop downs with lots of dataWorkspace code to build the choices array.

    My point about param queries was in reply to your comment:

    A pity that so much code is needed for simple cascading dropdowns.

    The dataWorkspace code is not necessary.  Instead, you can set the choice lists to use parameter queries at design time. (not sure if this is a recent change... I seem to remember it didn't work in earlier versions...but I could be wrong)

    However, as you point out, the child doesn't clear when the parent is cleared so you do need to add a little code for that.

    Josh


    • Edited by joshbooker Wednesday, June 25, 2014 4:07 PM
    Wednesday, June 25, 2014 11:50 AM
  • This is the code sample that someone previously posted to achieve cascading dropdowns between two controls for City and State:

    myapp.BrowseOrders.created = function (screen) {
        screen.USState = "AZ";
        stateDropDown = screen.findContentItem("StateDropdown");
        screen.getUSStates().then(function (result) {
            var index = result.data.length;
            var mylist = new Array();
            for (var i = 0; i < result.data.length; i++)
            {
                mylist[i] = { "value": i, "stringValue": result.data[i].StateName };
            }
            stateDropDown.choiceList = mylist;
            stateDropDown.dispatchChange("choiceList");
    	stateDropDown.dispatchChange("value");
        });
        screen.addChangeListener("StateDropdown", function () {
            stateDropDown = screen.findContentItem("StateDropdown");
            screen.USState = stateDropDown.choiceList[screen.StateDropdown].stringValue;
        });
    };
    
    myapp.BrowseOrders.CityDropdown_postRender = function (element, contentItem) {
        contentItem.dataBind("screen.StateDropdown", function () {
            if (contentItem.screen.USState != null)
            {
         myapp.activeDataWorkspace.MyEntitiesData.CityByState(contentItem.screen.USState)
                .execute()
                .then(function(result){
                    var index = result.results.length;
                    var mylist = new Array();
                    for (var i = 0; i < index; i++) {
                        mylist[i] = { "value": i, "stringValue": result.results[i].CityName };
                    }
                    contentItem.choiceList = mylist;
                    contentItem.dispatchChange("choiceList");
                    contentItem.dispatchChange("value");
                });
            };
        });
    };
    

    Note that the State is initialized to Arizona, and a dataBind function connects changes to the State with the City dropdown.

    You can achieve cascading dropdowns with little/no individual coding, if you happen to own ComponentOne's Studio for LightSwitch HTML controls:

    DROP DOWN: Filter

    Wednesday, June 25, 2014 2:18 PM
  • LittleBobbyTables,

    I got it to work simply using the screen designer and no code like this:

    Continent Entity related to Country Entity

    Order Entity related to Continent and Country

    Screen Designer (AddEditOrders):

    Include both Continent and Country pickers on layout

    Add Data Items Continents(All) and Countries(All)

    Countries | Edit Query | Add Parameter ContinentID | add Filter Country.Continent.id = Param

    Bind Param on Screen to Orders.Continent.Id 

    Set source query of pickers to Continents and Countries respectively

    Done

    Aside from clearing the child picker on change of parent picker this no-code solution works the same as in SL client for filtered drop downs.

    PS...I could be wrong, but I think this is a change from earlier versions as I read a year old comment from Huy that the picker choices queries fire only once.  Thus the need to do it in code.  Apparently this is no longer the case(?)

    HTH,

    Josh






    • Edited by joshbooker Wednesday, June 25, 2014 5:46 PM PS...
    • Marked as answer by Paul Van Bladel Thursday, June 26, 2014 4:51 AM
    Wednesday, June 25, 2014 2:28 PM
  • Hi Josh, Hi LittleBobbyTables,

    Thanks again.


    Indeed, I have done similar things in the silverlight client, where the cascading drop down were simply handled by the intelligence of the viewmodel queries. But in SL clearing the child picker was more "viewModel friendly" (read: the binding simply did his job).

    Now, with cascading dropdowns comes cascading data as well. 

    I would prefer that the parent data is not stored in the entity. I'll explain with an example. 

    I have a customer with has a city. In order to facilitate the selection of the city, I add on screen a country picker and a continent picker.

    I think that, the country nor the continent should be part of the customer entity. Otherwise, you create a functional dependency. 

    That would mean that the customer edit screen should load the country and continent separately but in reverse order (so based on the existing city). Something like:

    myapp.AddEditCustomer.Details_postRender = function (element, contentItem) {
    
        var screen = contentItem.screen;
        screen.Customer.getCity().done(function (city) {
            city.getCountry().done(
                function (country) {
                    screen.SelectedCountry = country;
                    country.getContinent().done(
                        function (continent) {
                            screen.SelectedContinent = continent;
                        });
                });
        });
    };

    I'm doing this in a post render (maybe in the screen created it would work as well)

    I'll try to work out the full cascading drop down scenario and drop the code somewhere so you can take a look :)

    paul.


    paul van bladel

    Wednesday, June 25, 2014 6:07 PM
  • sure Michael, it should be .then() rather than .done().

    thanks


    paul van bladel

    Wednesday, June 25, 2014 6:44 PM
  • The solution Paul proposed only works if the following is inserted between the dispatchChange() calls in CityDropdown_postRender:

    • contentItem.value = null;

    Bruce

    Friday, June 27, 2014 3:47 PM
  • Hi,

    It's easy.

        screen.findContentItem("SelectedContinent").value = "";
       
       screen.SelectedContinent = null;

    You must have both. The first will empty the picker, the second set the control to null.

    Good luck


    Sven Elm


    • Edited by Sven Elm Saturday, June 28, 2014 9:14 AM
    Saturday, June 28, 2014 9:12 AM
  • Hi,

    It's easy.

        screen.findContentItem("SelectedContinent").value = "";
       
       screen.SelectedContinent = null;

    You must have both. The first will empty the picker, the second set the control to null.

    Good luck


    Sven Elm



    The above works like the "clear" in the modal picker.

    Sven Elm


    • Edited by Sven Elm Saturday, June 28, 2014 9:18 AM
    Saturday, June 28, 2014 9:17 AM
  • Sven,

    That will only work, after running the code you propose, put the focus in the dropdown and leave the focus, than the value will be set null.

    The backing value (so the contentItem itself) is correctly set to null though.


    paul van bladel

    Saturday, June 28, 2014 11:42 AM
  • Hi,

    Ok, but I'm using a button and:

    1. choose a value in picker.

    2. browse the list

    3. Click my clear button beside the picker.

    4. the picker clears and the list is refreshed with non filtered data.

    Am I'm missing something. Do you mean you have to put the focus back on the picker before you can clear it?

    //Sven


    Sven Elm

    Saturday, June 28, 2014 12:47 PM
  • Hi,

    Ok, but I'm using a button and:

    1. choose a value in picker.

    2. browse the list

    3. Click my clear button beside the picker.

    4. the picker clears and the list is refreshed with non filtered data.

    Am I'm missing something. Do you mean you have to put the focus back on the picker before you can clear it?

    //Sven


    Sven Elm

    Hi,

    Ok. Now I read the whole post. You don't want to use a button for this. Am I right?


    Sven Elm

    Saturday, June 28, 2014 12:50 PM
  • Hi Sven,

    Thanks you so much for your reply.

    Indeed, I need the functionality for cascading dropdowns, but even behind a button I don't get it working. I'm on a detail screen it has a simple dropdown on a continents.

    The code you propose:

    screen.findContentItem("SelectedContinent").value = ""; screen.SelectedContinent = null;

    is not clearing the dropdown. (it's indeed setting the contentItem to null

    I'm using 2013 update 2


    paul van bladel

    Saturday, June 28, 2014 1:05 PM
  • Sven, is yours a details picker or a choice list of string values?
    Saturday, June 28, 2014 1:10 PM
  • It's a detailpicker. Strange.... It works for me (vs2013 update 2)

    Sven Elm


    • Edited by Sven Elm Saturday, June 28, 2014 1:12 PM
    Saturday, June 28, 2014 1:12 PM
  • It's a detailpicker. Strange.... It works for me (vs2013 update 2)

    Sven Elm



    Try with a timeout and see what happens

    Sven Elm

    Saturday, June 28, 2014 1:13 PM
  • It's a detailpicker. Strange.... It works for me (vs2013 update 2)


    Sven Elm



    Try with a timeout and see what happens

    Sven Elm

    Ok. You are right. I just upgraded to update 2 and the contentItem is cleared, but not the picker.

    Hmmm. It worked under vs2013. Bug?

    Sven


    Sven Elm

    Saturday, June 28, 2014 1:40 PM
  • Indeed, Sven. It smells like a bug.

    Thanks for giving it a try.


    paul van bladel

    Saturday, June 28, 2014 2:49 PM
  • Just stumbled upon this LS bug in the latest VS2013 CTP3 myself. Only way to get it to work was to use Josh's databind code in the _postRender() event above.

    Hope this will be fixed in the next version...


    Regards, Xander. My Blog

    Sunday, August 24, 2014 4:29 AM
  • Did anyone ever find a way to clear a details picker from code.

    I want to create a Reset button on some filter fields.

    I managed to call the clear button with the code below which refreshes the data but does not clear the text box.

    var tmp = $("SelectSupplier");
    tmp.find(".ui-link").trigger("click");

    Monday, September 15, 2014 8:07 AM
  • The answer to clearing the input of a details picker is my proposed answer using dataBind above. Some after that the thread goes off into cascading drop downs which off topic as are the marked answers.
    Monday, September 15, 2014 10:32 AM
  • Thanks just found it, I must of tried that but not in a dataBind. Thanks again.

        contentItem.dataBind("value", function (newValue) {
           
    if (!newValue){
                $
    (element).find("input").val(null);
           
    }
       
    })

    Monday, September 15, 2014 10:40 AM
  • I haven't tried it yet to confirm, but it looks a fix was released today for the issue requiring dataBind to set the search box to null when you clear the picker programmatically.

    HTH,

    Josh

    Tuesday, October 7, 2014 5:21 PM