Limit ComboBox "Text Entered" to items in the drop down list except if a certain option is selected in the "Parent" ComboBox.

7 posts, 0 answers
  1. Agropur
    Agropur avatar
    5 posts
    Member since:
    Oct 2013

    Posted 26 Nov 2013 Link to this post

    What I'm trying to do is I have 2 ComboBoxes that are setup in a Cascading relationship.  What I am not able to get working is that when 1 option is selected in the first ComboBox the cascaded ComboBox should ONLY allow choices from the Items list it is populated with.  When a 2nd option is selected in the first ComboBox(i.e. Other) the cascaded ComboBox should allow ANY text to be entered.

    How can I achieve this?  Below is my View and Controller in question. 

    VIEW:
    <div class="form-group">
                @Html.LabelFor(model => model.locationCode, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @(Html.Kendo().ComboBox()
                            .Name("locationCode")
                            .Filter(FilterType.Contains)
                            .DataTextField("Text")
                            .DataValueField("Value")
                            .BindTo(Model.Locations)
                            .Suggest(true)
                    )
                    @Html.ValidationMessageFor(model => model.locationCode)
                </div>
            </div>
     
            <div class="form-group">
                @Html.LabelFor(model => model.loadType, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @(Html.Kendo().ComboBox()
                            .Name("loadType")
                            .Filter(FilterType.Contains)
                            .DataTextField("Text")
                            .DataValueField("Value")
                            .BindTo(Model.LoadTypes)
                            .Suggest(true)
                    )
                    @Html.ValidationMessageFor(model => model.loadType)
                </div>
            </div>
     
            <div class="form-group">
                @Html.LabelFor(model => model.loadDescrip, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @(Html.Kendo().ComboBox()
                            .Name("loadDescription")
                            .Filter(FilterType.Contains)
                            .DataTextField("DocCode")
                            .DataValueField("DocCode")
                            .DataSource(source =>
                            {
                                source.Read(read =>
                                {
                                    read.Action("GetCascadeDocumentNumbers", "DockDoor")
                                        .Data("filterLoadDescription");
                                })
                              .ServerFiltering(true);
                            })
                            .Enable(false)
                            .AutoBind(false)
                            .CascadeFrom("loadType")
                    )
                    <script>
                        function filterLoadDescription() {
                            return {
                                locCode: $("#locationCode").val(),
                                loadType: $("#loadType").val(),
                                docNumFilter: $("#loadDescription").data("kendoComboBox").input.val()
                            };
                        }
                    </script>
                    @Html.ValidationMessageFor(model => model.loadDescrip)
                </div>
            </div>
    CONTROLLER:
    public JsonResult GetCascadeDocumentNumbers(string locCode, string loadType, string docNumFilter)
    {
        if (loadType != "OPEN" && loadType != "GENERIC")
        {
            var docNums = db.GetCurrentDocumentNumbers(locCode, loadType).AsEnumerable();
     
            if (!string.IsNullOrWhiteSpace(docNumFilter))
            {
                docNums = docNums.Where(x => x.Contains(docNumFilter));
            }
     
            return Json(docNums.Select(x => new { DocCode = x.ToString() }), JsonRequestBehavior.AllowGet);
        }
        return Json(string.Empty, JsonRequestBehavior.AllowGet);
    }


  2. Agropur
    Agropur avatar
    5 posts
    Member since:
    Oct 2013

    Posted 27 Nov 2013 Link to this post

    So here is what I have so far:

    In my VIEW:
    <div class="form-group">
               @Html.LabelFor(model => model.loadType, new { @class = "control-label col-md-2" })
               <div class="col-md-10">
                   @(Html.Kendo().ComboBox()
                           .Name("loadType")
                           .Filter(FilterType.Contains)
                           .DataTextField("Text")
                           .DataValueField("Value")
                           .BindTo(Model.LoadTypes)
                           .Suggest(true)
                   )
                   @Html.ValidationMessageFor(model => model.loadType)
               </div>
           </div>
     
           <div class="form-group">
               @Html.LabelFor(model => model.loadDescrip, new { @class = "control-label col-md-2" })
               <div class="col-md-10">
                   @(Html.Kendo().ComboBox()
                           .Name("loadDescrip")
                           .Filter(FilterType.Contains)
                           .DataTextField("DocCode")
                           .DataValueField("DocCode")
                           .DataSource(source =>
                           {
                               source.Read(read =>
                               {
                                   read.Action("GetCascadeDocumentNumbers", "DockDoor")
                                       .Data("filterLoadDescription");
                               })
                             .ServerFiltering(true);
                           })
                           .Enable(false)
                           .AutoBind(false)
                           .CascadeFrom("loadType")
                           .Events(e =>
                               {
                       e.Change("onChange");
                               })
                   )
                   @Html.ValidationMessageFor(model => model.loadDescrip)
               </div>
           </div>

    Also in my view, the Script stuff:
    <script>
        function filterLoadDescription() {
            return {
                locCode: $("#locationCode").val(),
                loadType: $("#loadType").val(),
                docNumFilter: $("#loadDescrip").data("kendoComboBox").input.val()
            };
        };
     
        function onChange(e) {
            var lT = $("#loadType").data("kendoComboBox").input.val();
            if (lT != "Generic") {
                // Here I need to compare 'lD' to what is populated in the comboBox dropdown
                if (this.selectedIndex == -1) {
                    this._filterSource({
                        value: "",
                        field: this.options.dataTextField,
                        operator: "contains"
                    });
                    var comboBox = $("loadDescrip").data("kendoComboBox");
                    comboBox.select(1);               
                }           
            }
        };
    </script>
    The part that I cannot seem to make work is what's inside the if() statement.  What I am trying to accomplish is that, depending on what they select in a previous combobox this child combobox will not allow custom text.  This is where I am trying to check for that.

    In fact, the line `comboBox.select(1)` generates a JavaScript runtime error: "Unable to get property 'select' of undefined or null reference"

  3. UI for ASP.NET MVC is VS 2017 Ready
  4. Georgi Krustev
    Admin
    Georgi Krustev avatar
    3707 posts

    Posted 28 Nov 2013 Link to this post

    Hello,

    I will suggest you use the filter method of the data source:
    var that = this;
     
    if (that.selectedIndex == -1) {
        that.dataSource
              .one("change", function() {
                   that.select(1);
              })
              .filter({
                 value: "",
                 field: that.options.dataTextField,
                 operator: "contains"
              });
    }
    Note that data source is asynchronous and you will need to apply the required changes when the widget is re-bound. Also please avoid using private methods (with underscore) as they can change in future.

    Regarding second issue, I am not exactly sure what is the cause of the problem. If it still persists then I will ask you to send us a simple repro test project. Thus I will be able to observe the issue locally and advice you further.

    Regards,
    Georgi Krustev
    Telerik
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
  5. Agropur
    Agropur avatar
    5 posts
    Member since:
    Oct 2013

    Posted 02 Dec 2013 Link to this post

    Thanks.  Couple of follow up questions:
    What does ".one()" do?
    Could you explain, a little, what you meant with this statement:"you will need to apply the required changes when the widget is re-bound."?  What more would I need to do besides what was shown in your answer?  I understand the Why just not the How...
    Lastly, how do I get the filter to clear itself?  I have an issue where the last value still sits in there even if the parent combobox choice would make it invalid.  I tried the following but maybe I'm not using it in the right way?  
    // This is the Parent Combobox Change Event. $lD is the child one.
    function
    onTypeChange(e) {
        if (this.value() == "OPEN") {
            var $lD = $("#loadDescrip").data("kendoComboBox");
            $lD.dataSource.filter([]);
            //$lD.value("");
            $lD.text("empty");
            $lD.dataSource.read();
        }
    }
  6. Georgi Krustev
    Admin
    Georgi Krustev avatar
    3707 posts

    Posted 04 Dec 2013 Link to this post

    Hello again,

    The "one" method is a short-hand to listen to event raise only once. It is same as:
    var changeHandler = function() {
         //
     
         widget.unbind("change", changeHandler);
    }
     
    widget.bind("change", changeHandler);
    This code snippet shows the same functionality using the bind method of the ObservableObject.

    With "you will need to apply the required changes when the widget is re-bound" statement I wanted to mention that any changes like selecting item or setting value will need to be done after the widget is re-populated. Wiring the change event of the dropdownlist's data source is sufficiant to achieve the aforementioned requirement. 

    The applied filter can be cleared either using your approach or passing empty object as an argument:
    $lD.dataSource.filter([])
     
    /// or
     
    $lD.dataSource.filter({});


    Regards,
    Georgi Krustev
    Telerik
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
  7. Agropur
    Agropur avatar
    5 posts
    Member since:
    Oct 2013

    Posted 04 Dec 2013 Link to this post

    Thanks. The filter thing still does not work, unless I am simply doing it wrong or not understanding what the filter is.  I have submitted a Support Ticket with my project attached to it.
  8. Georgi Krustev
    Admin
    Georgi Krustev avatar
    3707 posts

    Posted 09 Dec 2013 Link to this post

    Hello,

    I've answered you  in the support thread on the same matter. I will suggest you continue our conversation there in order to avoid any duplications.

    Regards,
    Georgi Krustev
    Telerik
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
Back to Top
UI for ASP.NET MVC is VS 2017 Ready