MultiSelect: view and model not in sync

7 posts, 0 answers
  1. Lawrence
    Lawrence avatar
    7 posts
    Member since:
    Jun 2015

    Posted 03 Jun Link to this post

    I am using a Kendo MultiSelect (within a column of a tr-ng-grid) and I am trying to add a functionality where an item is deselected when another is selected.

    Ex. I have the options 1, 2, 3,  and UNKNOWN; only 2 and 3 are selected. The rule is when UNKNOWN is selected, the rest are deselected and when 1, 2, or 3 is selected, UNKNOWN is deselected.

    The problem that I am facing is that the model and the view is not always in sync, which poses a problem.

     

    Here is the code.

    index.html (short version)

    1.<dir-multi-select selected-items="gridItem.items" />

    directive.js

    01.(function() {
    02.    'use strict';
    03.    angular.module('moduleA').directive('dirMultiSelect', function() {
    04.        return {
    05.            restrict : 'E',
    06.            scope : {
    07.                selectedItems : '='
    08.            },
    09.            controller : 'MultiSelectController',
    10.            templateUrl : 'multiselect.html',
    11.            replace : true
    12.        }
    13.    })
    14.})();

    multiselect.html

    01.<div ng-init="init()">
    02.    <select kendo-multi-select
    03.        id="'multiSelect'"
    04.        ng-if="dataSource"
    05.        k-data-source="dataSource"
    06.        k-data-text-field="'name'"
    07.        k-data-value-field="'id'"
    08.        k-ng-model="selectedItems"
    09.        k-rebind="selectedItems"
    10.        k-value-primitive=true
    11.        k-auto-close=false
    12.        k-data-placeholder="'Select items...'"
    13.        k-on-select="onSelect(kendoEvent)">
    14.    </select>
    15.</div>

    multiselect.controller.js

    01.(function() {
    02.    angular.module('moduleA').controller(
    03.            'MultiSelectController',
    04.            [
    05.                    '$scope',
    06.                    function($scope) {
    07.                        $scope.init = function() {
    08.                                $scope.dataSource = //http call
    09.                        }
    10. 
    11.                        $scope.onSelect = function(kendoEvent) {
    12.                            var selectedItem = kendoEvent.sender.dataItem(kendoEvent.item.index());
    13.                            if (selectedItem ) {
    14.                                autoDeselectItems(kendoEvent, selectedItem);
    15.                            }
    16.                        }
    17. 
    18.                        function autoDeselectItems(kendoEvent, selectedItem) {
    19.                            if (isItemIdUnknown(selectedItem.id)) {
    20.                                kendoEvent.preventDefault();
    21.                                if (!doesSelectedItemContainUnknown()) {
    22.                                    setSelectedItemsToUnknown();
    23.                                }
    24.                            }
    25.                            else {
    26.                                if (doesSelectedItemsContainUnknown()) {
    27.                                    kendoEvent.preventDefault();
    28.                                    setSelectedItems(selectedItem);
    29.                                }
    30.                                else {
    31.                                    if (doesSelectedItemsContain(selectedItem.id)
    32.                                            && $scope.selectedItems.length == 1) {
    33.                                        setSelectedItemsToUnknown();
    34.                                    }
    35. 
    36.                                }
    37.                            }
    38.                        }
    39. 
    40.                        function isItemIdUnknown(id) {
    41.                            return id == "0";
    42.                        }
    43. 
    44.                        function doesSelectedItemsContainUnknown() {
    45.                            for (var i = 0; i < $scope.selectedItems.length; i++) {
    46.                                if (isItemIdUnknown($scope.selectedItems[i].id)) {
    47.                                    return true;
    48.                                }
    49.                            }
    50.                            return false;
    51.                        }
    52. 
    53.                        function doesSelectedItemsContain(id) {
    54.                            for (var i = 0; i < $scope.selectedItems.length; i++) {
    55.                                if ($scope.selectedItems[i].id == id) {
    56.                                    return true;
    57.                                }
    58.                            }
    59.                            return false;
    60.                        }
    61. 
    62.                        function removeUnknownFromSelectedItems() {
    63.                            for (var i = 0; i < $scope.selectedItems.length; i++) {
    64.                                if ($scope.selectedItems[i].id == 0) { // "UNKNOWN"
    65.                                    $scope.selectedItems.splice(i, 1);
    66.                                    break;
    67.                                }
    68.                            }
    69.                        }
    70. 
    71.                        function setSelectedItemsToUnknown() {
    72.                            $scope.selectedItems = [ {
    73.                                id : "0",
    74.                                name : "UNKNOWN"
    75.                            } ];
    76.                        }
    77. 
    78.                        function setSelectedItems(ids) {
    79.                            if (ids) {
    80.                                $scope.selectedItems = [];
    81.                                if (ids.length) {
    82.                                    for (var i = 0; i < ids.length; i++) {
    83.                                        $scope.selectedItems.push({
    84.                                            id : ids[i].id,
    85.                                            name : ids[i].name
    86.                                        });
    87.                                    }
    88.                                }
    89.                                else {
    90.                                    $scope.selectedItems.push({
    91.                                        id : ids.id,
    92.                                        name : ids.name
    93.                                    });
    94.                                }
    95.                            }
    96.                        }
    97.                    } ]);
    98.})();

    a

  2. Alex Hajigeorgieva
    Admin
    Alex Hajigeorgieva avatar
    119 posts

    Posted 07 Jun Link to this post

    Hello Lawrence,

    I have updated one of our Kendo UI MultiSelect demos to work with a configuration similar to the one provided. For some Kendo UI widgets with multiple options, the k-options attribute is necessary as outlined below:

    http://docs.telerik.com/kendo-ui/AngularJS/introduction#widget-update-upon-option-changes

    A sample demo for your convenience:
    http://dojo.telerik.com/ANeHE

    Additionally, the AngularJS directive ng-if is not supported and should be used at own risk. If possible, use ng-show instead:
    http://www.telerik.com/forums/kendo-and-angular---ng-if#SrNHC_3VR0auZ9LR8d9kMg

    Please avoid creating posts in different threads that are related to the same issue. This way we can track all relevant details in one place and focus our efforts to reach a resolution faster.

    Let me know if you need further assistance with the Kendo UI MultiSelect.

    Regards,
    Alex
    Telerik
     
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
     
  3. Kendo UI is VS 2017 Ready
  4. Lawrence
    Lawrence avatar
    7 posts
    Member since:
    Jun 2015

    Posted 07 Jun in reply to Alex Hajigeorgieva Link to this post

    The reason I am using ng-if instead of ng-show because I don't want it to be rendered until the DataSource is valid.
  5. Lawrence
    Lawrence avatar
    7 posts
    Member since:
    Jun 2015

    Posted 07 Jun in reply to Alex Hajigeorgieva Link to this post

    In your sample demo, you have two widgets: the first is not using k-options and the second is. The first one is not working, but the second one is. In the second one, you don't modify the selectedIds within the select event, which is what I am trying to do, while keeping the model in sync with the view.

  6. Alex Hajigeorgieva
    Admin
    Alex Hajigeorgieva avatar
    119 posts

    Posted 09 Jun Link to this post

    Hello Lawrence,


    Please accept my apology for sending a wrong Dojo demo - I have updated it now and also added onSelect function with a Kendo Event.

    http://dojo.telerik.com/ejEmO

    A Kendo UI widget will not be created if any of the defined attribute options evaluate to undefined: 
    http://docs.telerik.com/kendo-ui/AngularJS/introduction#widget-options-in-html

    To delay a Kendo UI widget until the data source becomes available, make use of the k-ng-delay attribute instead of using the non-supported ng-if
    http://docs.telerik.com/kendo-ui/AngularJS/introduction#delay-widget-initialization

    Let me know if you need any more help with the Kendo UI MultiSelect integration with AngularJS.

    Kind Regards,
    Alex
    Telerik
     
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
     
  7. Lawrence
    Lawrence avatar
    7 posts
    Member since:
    Jun 2015

    Posted 13 Jun in reply to Alex Hajigeorgieva Link to this post

    Still not there. You didn't modify the scope in your select event.

  8. Alex Hajigeorgieva
    Admin
    Alex Hajigeorgieva avatar
    119 posts

    Posted 16 Jun Link to this post

    Hi Lawrence,

    I was under the impression that the issue was with binding the Kendo UI Multiselect and that the model is not always in sync, so I provided a generic example. I would not recommend changing the ids of the DataSource to achieve the desired custom item selection logic inside the Kendo UI MultiSelect. 

    I created a simple conditional statement that handles the selected items in the model of the Kendo UI MultiSelect using the following steps:

    1)  Attach an event listener to the select event using k-on-select:
    http://docs.telerik.com/kendo-ui/api/javascript/ui/multiselect#events-select

    2) If "Unknown" is selected, then all others are deselected by assigning the value of "Unknown" to the model
    $scope.selectedIds = [0];

    3) If any other option is selected, then find the "Unknown" option and remove it from the model. Finally, add the current selection.

    A similar result can be implemented by following the same steps with a change event handler:
    http://docs.telerik.com/kendo-ui/api/javascript/ui/multiselect#events-change

    If change is used, adding the current selection in step 3 will not be necessary.

    Please find the demo at: http://dojo.telerik.com/AruRe

    Kind Regards,
    Alex
    Telerik
    Get started with Kendo UI in days. Online training courses help you quickly implement components into your apps.
Back to Top
Kendo UI is VS 2017 Ready