none
Multi-Select Issue HTML5 Client

Answers

  • Hi Mark,

    A couple of suggestions:

    - Set a breakpoint at var checked = checkbox[0].checked; and see if the breakpoint is hit.

    - When the breakpoint is hit, check and see what is the value of contentItem.value and contentItem.value.details, do they exist? In the blog's scenario, the content item is bound to an entity object, so I know that contentItem.value and contentItem.value.details do exist. In your project, I'm not sure what Box01 and Box2 are bound to.

    - Or try this:

    function getCheckBox(contentItem) {
        var checkbox = $("<input type='checkbox'/>");
        checkbox.css("height", "20");
        checkbox.css("width", "20");
        checkbox.css("margin", "10px");
    
        checkbox.change(function () {
            contentItem.myCheckBoxIsChecked = checkbox[0].checked;
        });
        return checkbox;
    };
    
    myapp.ViewStoreGroup.Box01_render = function (element, contentItem) {
        var checkbox1 = getCheckBox(contentItem);
        checkbox1.appendTo($(element));
    };
    
    myapp.ViewStoreGroup.Box2_render = function (element, contentItem) {
        var checkbox2 = getCheckBox(contentItem);
        checkbox2.appendTo($(element));
    };

    and

    myapp.ViewStoreGroup.MultiOk_execute = function (screen) {
    
        if (screen.findContentItem("BG1").isVisible && screen.findContentItem("Box01").myCheckBoxIsChecked) {
            screen.ActionItem.selectedItem.Choice01 = screen.ProjectQuestions.selectedItem.Choice01;
        }
        else {
            screen.ActionItem.selectedItem.Choice01 = null;
        }
    
    
        if (screen.findContentItem("BG2").isVisible && screen.findContentItem("Box2").myCheckBoxIsChecked){
            screen.ActionItem.selectedItem.Choice02 = screen.ProjectQuestions.selectedItem.Choice02;
        }
        else{
                    screen.ActionItem.selectedItem.Choice02 = null;
        }

    Our main goal here is to remember the value of each checkbox somewhere when the checkbox value is changed, so that we can retrieve that value later. The content item is a logical place to store it because the content item can be retrieved from any places. Where we store it on the content item is less important in JavaScript because you can set pretty much anything on any object. In the blog, it's convenient to store it on each entity object details, which is bound to the content item value, because we will enumerate the entity object later. In this case, we can use the content item to store the value because we will try to find the content item anyway. contentItem.value can be very different depends on the binding.

    Best regards,
    Huy



    Thursday, July 18, 2013 2:23 PM
  • Hi Mark,

    Do your methods to setup the check boxes still look like this?

    function getCheckBox(contentItem) {
        var checkbox = $("<input type='checkbox'/>");
        checkbox.css("height", "20");
        checkbox.css("width", "20");
        checkbox.css("margin", "10px");
    
        checkbox.change(function () {
            var checked = checkbox[0].checked;
            if (!!contentItem.value.details["__isSelected"] !== checked) {
                contentItem.value.details["__isSelected"] = checked;
            }
        });
        return checkbox;
    };
    
    myapp.ViewStoreGroup.Box01_render = function (element, contentItem) {
        var checkbox1 = getCheckBox(contentItem);
        $(checkbox1).appendTo($(element));
    };
    
    myapp.ViewStoreGroup.Box2_render = function (element, contentItem) {
        var checkbox2 = getCheckBox(contentItem);
        $(checkbox2).appendTo($(element));
    };

    If so, it looks like you only use the check box to set value to object, not to reflect the current value of that object. Are you sure it will not look strange to your application's users when they open the popup and even though they know that the current value is supposed to be true, the check box is unchecked?

    Anyway, since there is no data binding from the content item to the check boxes, here's how I would clear them:

    function getCheckBox(contentItem) {
        var checkbox = $("<input type='checkbox'/>");
        checkbox.css("height", "20");
        checkbox.css("width", "20");
        checkbox.css("margin", "10px");
    
        checkbox.change(function () {
            var checked = checkbox[0].checked;
            if (!!contentItem.value.details["__isSelected"] !== checked) {
                contentItem.value.details["__isSelected"] = checked;
            }
        });
    
        // Cache the checkbox HTML element on the content item.
    contentItem.myCheckBox = checkbox[0]; return checkbox; };

    And before you show the pop-up, clear the values as you want.

                // Set the ActionItem Filter to include the curremtly selected type of "Store", "Schematic" or the actual ProductName = Product 
                screen.ActionTypeFilter = screen.ActionItem.selectedItem.Product;
    
                if (screen.ActionItem.selectedItem.QuestionType == "Multiple Select" || screen.ActionItem.selectedItem.QuestionType == "Single Select") {
    
                    screen.findContentItem("Box01")
                        .myCheckBox.checked = false;
                    screen.findContentItem("Box2")
                        .myCheckBox.checked = false;
                     
                    screen.showPopup("ChoiceList")
                    .then(function() {
    

    Best regards,
    Huy
    • Marked as answer by ITPSB Friday, August 09, 2013 2:22 AM
    Thursday, August 08, 2013 3:34 PM

All replies

  • Hi Mark,

    It would help if you can share the full screen code. Also, from the screenshot, you're working on a different scenario compared to the blog scenario, so I cannot guess here.

    Best regards,
    Huy

    Wednesday, July 17, 2013 3:55 PM
  • Thanks for picking up on my Issue Huy.

    This is the screen-shot I should have submitted - oops.

    https://dl.dropboxusercontent.com/u/10788935/Pic8.png

    Best regards, Mark.


    Mark

    Wednesday, July 17, 2013 4:30 PM
  • Hi Mark,

    I will need the full code you wrote for the screen and your custom control to determine the issue.

    Thanks,
    Huy

    Wednesday, July 17, 2013 4:45 PM
  • Hi

    Below is the relevant code. Please let me know if you need additional information.

    Thank you very much, Mark.

    function getCheckBox(contentItem) {
        var checkbox = $("<input type='checkbox'/>");
        checkbox.css("height", "20");
        checkbox.css("width", "20");
        checkbox.css("margin", "10px");
    
        checkbox.change(function () {
            var checked = checkbox[0].checked;
            if (!!contentItem.value.details["__isSelected"] !== checked) {
                contentItem.value.details["__isSelected"] = checked;
            }
        });
        return checkbox;
    };
    
    myapp.ViewStoreGroup.Box01_render = function (element, contentItem) {
        var checkbox1 = getCheckBox(contentItem);
        $(checkbox1).appendTo($(element));
    };
    
    myapp.ViewStoreGroup.Box2_render = function (element, contentItem) {
        var checkbox2 = getCheckBox(contentItem);
        $(checkbox2).appendTo($(element));
    };

    And this is the button click to save the changes where I have the issue:

    myapp.ViewStoreGroup.MultiOk_execute = function (screen) {
    
        if (screen.findContentItem("BG1").isVisible == true && screen.findContentItem("Box01").value.details["__isSelected"] == true) {
            screen.ActionItem.selectedItem.Choice01 = screen.ProjectQuestions.selectedItem.Choice01;
        }
        else {
            screen.ActionItem.selectedItem.Choice01 = null;
        }
    
    
        if (screen.findContentItem("BG2").isVisible == true && screen.findContentItem("Box2").value.details["__isSelected"] == true){
            screen.ActionItem.selectedItem.Choice02 = screen.ProjectQuestions.selectedItem.Choice02;
        }
        else{
                    screen.ActionItem.selectedItem.Choice02 = null;
        }


    Mark


    • Edited by ITPSB Thursday, July 18, 2013 4:18 AM typo
    Thursday, July 18, 2013 4:18 AM
  • Hi Mark,

    A couple of suggestions:

    - Set a breakpoint at var checked = checkbox[0].checked; and see if the breakpoint is hit.

    - When the breakpoint is hit, check and see what is the value of contentItem.value and contentItem.value.details, do they exist? In the blog's scenario, the content item is bound to an entity object, so I know that contentItem.value and contentItem.value.details do exist. In your project, I'm not sure what Box01 and Box2 are bound to.

    - Or try this:

    function getCheckBox(contentItem) {
        var checkbox = $("<input type='checkbox'/>");
        checkbox.css("height", "20");
        checkbox.css("width", "20");
        checkbox.css("margin", "10px");
    
        checkbox.change(function () {
            contentItem.myCheckBoxIsChecked = checkbox[0].checked;
        });
        return checkbox;
    };
    
    myapp.ViewStoreGroup.Box01_render = function (element, contentItem) {
        var checkbox1 = getCheckBox(contentItem);
        checkbox1.appendTo($(element));
    };
    
    myapp.ViewStoreGroup.Box2_render = function (element, contentItem) {
        var checkbox2 = getCheckBox(contentItem);
        checkbox2.appendTo($(element));
    };

    and

    myapp.ViewStoreGroup.MultiOk_execute = function (screen) {
    
        if (screen.findContentItem("BG1").isVisible && screen.findContentItem("Box01").myCheckBoxIsChecked) {
            screen.ActionItem.selectedItem.Choice01 = screen.ProjectQuestions.selectedItem.Choice01;
        }
        else {
            screen.ActionItem.selectedItem.Choice01 = null;
        }
    
    
        if (screen.findContentItem("BG2").isVisible && screen.findContentItem("Box2").myCheckBoxIsChecked){
            screen.ActionItem.selectedItem.Choice02 = screen.ProjectQuestions.selectedItem.Choice02;
        }
        else{
                    screen.ActionItem.selectedItem.Choice02 = null;
        }

    Our main goal here is to remember the value of each checkbox somewhere when the checkbox value is changed, so that we can retrieve that value later. The content item is a logical place to store it because the content item can be retrieved from any places. Where we store it on the content item is less important in JavaScript because you can set pretty much anything on any object. In the blog, it's convenient to store it on each entity object details, which is bound to the content item value, because we will enumerate the entity object later. In this case, we can use the content item to store the value because we will try to find the content item anyway. contentItem.value can be very different depends on the binding.

    Best regards,
    Huy



    Thursday, July 18, 2013 2:23 PM
  • Woo Hooo!!!

    The below line of code from your suggestion fixed the issue. So a big Thank You.

    There's no way I could have figured it out alone.

    contentItem.myCheckBoxIsChecked = checkbox[0].checked;

    Plus the line

    if (screen.findContentItem("BG1").isVisible == true && screen.findContentItem("Box01").myCheckBoxIsChecked == true)
    

    Many thanks indeed for your excellent support.

    Best regards, Mark.


    Mark


    • Edited by ITPSB Friday, July 19, 2013 3:19 AM Typo
    Friday, July 19, 2013 3:15 AM
  • Hi

    One last question please.

    In the example, on creating the custom control, you say "Make sure the Data Context is left as the default ‘Screen’ value".

    But in my solution I need to bind the control to a Boolean field in my record.

    Without such binding the pop-up that displays the check-boxes doesn't reflect the saved settings in the record.

    I had a stab at it by binding the custom control to the Boolean field in my record but the behaviour doesn't change. It still shows whatever the checkboxes were set to when I viewed the previous record.

    Thanks again, Mark.


    Mark

    Friday, July 19, 2013 5:13 AM
  • Hi Mark,

    Just to be clear we are talking about a total different scenario. What you're trying to do now is to write a custom checkbox control binding to an entity field (the Flip-switch does not work for you?).

    I would suggest reading and following this blog post to get a general view on how things work.

    An important thing to check is making sure you have the correct data binding.

    For example, binding to the same Residence.NeedMaintenance field on an Add/Edit Screen is Residence.NeedMaintenance

    but on a Browse screen built like a List / Detail screen, it will be Residences.selectedItem.NeedMaintenance

    Once the data binding is correct, the code is pretty simple.

    If you only need one-way binding - user cannot change the value using the checkbox, the code is like this

    myapp.BrowseResidences.NeedMaintenance_render = function (element, contentItem) {
        // Create the checkbox and add to the DOM.
        var checkbox = $("<input type='checkbox'/>")
                .css({
                    height: 20,
                    width: 20,
                    margin: "10px"
                })
                .appendTo($(element));
    
        // One-way data bind.
        contentItem.dataBind("value", function (newValue) {
            checkbox[0].checked = newValue;
        });
    };

    If you want to allow changing the value using the check box, code is a little bit longer. Comments are verbose just to explain in details, feel free to omit them in real code =)

    myapp.AddEditResidence.NeedMaintenanceCheckBox_render = function (element, contentItem) {
        // Create the checkbox and add to the DOM.
        var checkbox = $("<input type='checkbox'/>")
                .css({
                    height: 20,
                    width: 20,
                    margin: "10px"
                })
                .appendTo($(element));
    
        // Two ways data binding.
        // Are we the one causing the value change?
        var changingValue = false;
    
        checkbox.change(function () {
            // We are causing the value change.
            changingValue = true;
            // Change the value.
            contentItem.value = checkbox[0].checked;
            // We're done.
            changingValue = false;
        });
        contentItem.dataBind("value", function (newValue) {
            // If the value is changed because of us,
            // no need to update the check box.
            if (!changingValue) {            
                checkbox[0].checked = newValue;
            }
        });
    };

    Best regards,
    Huy
    Friday, July 19, 2013 3:15 PM
  • Dear Huy

    After much head-scratching, I've figured out what would work best for my app.

    In a nut-shell, I have many survey questions that when answered (using the checkbox custom control), the user can see text descriptions of their choices (associated with the checks) in separate tiles. And if they want to change any one of their choices they tap one of these tiles and the choice list with the custom controls appears as a pop-up.

    With one-way binding, (I've decided not to change the binding to two-way), this works very well except for one issue.

    The issue is that the pop-up control "remembers" whatever was the last custom control settings.

    I've tried to figure out how to clear the checks for each time the pop-up is re-displayed but cannot figure out how it's done. Can you please assist me with this issue.

    Many thanks, Mark.


    Mark

    Wednesday, August 07, 2013 5:22 AM
  • Hi Mark,

    Assuming you already setup a data binding from each check box to its content item's value property, and in the call back you set the value of the check box, you can try this: When you intend to show the popup, instead of binding that Button or Tap to the method showPopup, bind it to your custom method and write this:

    myapp.Browse.ShowStorePopup_execute = function (screen) {
        // Replace ViewStoreGroup with your popup's content item's name.
        screen.showPopup("ViewStoreGroup")
            .then(function () {
                // Replace Box01, Box02 with your check boxes'
                // content items' names.
                screen.findContentItem("Box01").dispatchChange("value");
                screen.findContentItem("Box02").dispatchChange("value");
                // ... Repeat for all check boxes.
            });
    };
    Best regards,
    Huy
     

     

    Wednesday, August 07, 2013 9:54 PM
  • Dear Huy

    Not quite understanding the purpose of the line,

    screen.findContentItem("Box01").dispatchChange("value");

    I just "blindly" copied your example as below. But when I run the project it still "remembers" the check-box values from the previous item selected, so I must be missing something.

    Many thanks for assisting me with this issue.

                // Set the ActionItem Filter to include the curremtly selected type of "Store", "Schematic" or the actual ProductName = Product 
                screen.ActionTypeFilter = screen.ActionItem.selectedItem.Product;
    
                if (screen.ActionItem.selectedItem.QuestionType == "Multiple Select" || screen.ActionItem.selectedItem.QuestionType == "Single Select") {
    
                    screen.showPopup("ChoiceList")
                    .then(function() {
    
                        if (screen.ProjectQuestions.selectedItem.Choice01 == null) {
                            screen.findContentItem("BG1").isVisible = false;
                        }
                        else {
                            screen.findContentItem("BG1").isVisible = true;
                        }
                        screen.findContentItem("Box01").dispatchChange("value");

    Below is a screen-shot of the design view:


    Mark

    Thursday, August 08, 2013 3:55 AM
  • And this is the Render code if it's of interest:

    myapp.ViewStoreGroup.Box01_render = function (element, contentItem) {
        var checkbox1 = getCheckBox(contentItem);
        checkbox1.appendTo($(element));
    };


    Mark

    Thursday, August 08, 2013 3:57 AM
  • Hi Mark,

    Do your methods to setup the check boxes still look like this?

    function getCheckBox(contentItem) {
        var checkbox = $("<input type='checkbox'/>");
        checkbox.css("height", "20");
        checkbox.css("width", "20");
        checkbox.css("margin", "10px");
    
        checkbox.change(function () {
            var checked = checkbox[0].checked;
            if (!!contentItem.value.details["__isSelected"] !== checked) {
                contentItem.value.details["__isSelected"] = checked;
            }
        });
        return checkbox;
    };
    
    myapp.ViewStoreGroup.Box01_render = function (element, contentItem) {
        var checkbox1 = getCheckBox(contentItem);
        $(checkbox1).appendTo($(element));
    };
    
    myapp.ViewStoreGroup.Box2_render = function (element, contentItem) {
        var checkbox2 = getCheckBox(contentItem);
        $(checkbox2).appendTo($(element));
    };

    If so, it looks like you only use the check box to set value to object, not to reflect the current value of that object. Are you sure it will not look strange to your application's users when they open the popup and even though they know that the current value is supposed to be true, the check box is unchecked?

    Anyway, since there is no data binding from the content item to the check boxes, here's how I would clear them:

    function getCheckBox(contentItem) {
        var checkbox = $("<input type='checkbox'/>");
        checkbox.css("height", "20");
        checkbox.css("width", "20");
        checkbox.css("margin", "10px");
    
        checkbox.change(function () {
            var checked = checkbox[0].checked;
            if (!!contentItem.value.details["__isSelected"] !== checked) {
                contentItem.value.details["__isSelected"] = checked;
            }
        });
    
        // Cache the checkbox HTML element on the content item.
    contentItem.myCheckBox = checkbox[0]; return checkbox; };

    And before you show the pop-up, clear the values as you want.

                // Set the ActionItem Filter to include the curremtly selected type of "Store", "Schematic" or the actual ProductName = Product 
                screen.ActionTypeFilter = screen.ActionItem.selectedItem.Product;
    
                if (screen.ActionItem.selectedItem.QuestionType == "Multiple Select" || screen.ActionItem.selectedItem.QuestionType == "Single Select") {
    
                    screen.findContentItem("Box01")
                        .myCheckBox.checked = false;
                    screen.findContentItem("Box2")
                        .myCheckBox.checked = false;
                     
                    screen.showPopup("ChoiceList")
                    .then(function() {
    

    Best regards,
    Huy
    • Marked as answer by ITPSB Friday, August 09, 2013 2:22 AM
    Thursday, August 08, 2013 3:34 PM
  • Dear Huy

    Fantastic! That worked like a charm :-)

    In response to your comment "Are you sure it will not look strange to your application's users when they open the popup and even though they know that the current value is supposed to be true, the check box is unchecked?",

    After much head-scratching what became evident is this:

    The user's previous response is in plain view in a tile that displays text associated with the checkbox responses. E.g. "Missing Item". If the user wants to change the selected choice from (say) "Missing Item" to "Item Damaged" then, on tapping the question again, they need to select the new issue with one tap. If I left the check-box element checked then it would require 2 taps, one to de-select and another to select a different choice.

    Anyway, I am very happy with your great support. I could not have figured this out without assistance.

    Many thanks and best regards.


    Mark

    Friday, August 09, 2013 2:22 AM