KendoUI: ComboBoxes avoiding non-documented-features (bugs?)


I’ve already published some posts on how to use KendoUI ComboBox and how delighted I was (and I am) about it.
But, this morning I did a little change in the UI (just cosmetic and it stop working). Here I share with you the problem and how to avoid it but not solving it: this is KendoUI engineers job and they will not be happy if I do it for free 😀

First problem: List area wrong positioning

If the body of your HTML page has a border, then the position of the open list is wrong (read about this in the KendoUI forum).

NOTE: This is actually the second one that I found looking for the solution in reading KendoUI forums.

This is the code:

<script type="text/javascript">
    $(document).ready(function () {
        var numbers = [
            "One",
            "Two",
            "Three"
        ];

        $("#numbers").kendoComboBox({
            dataSource:numbers
        }).data("kendoComboBox");
    });
</script>

and this the HTML:

<body style="border: 50px solid red;">
    <div>
        <input id="numbers"/>
    </div>
</body>

This is how it looks like:

KendoUI ComboBox list when body has border
KendoUI ComboBox list when body has border

Solution

Don’t use borders in your body. Insert a div that contains that border… Sorry if you were waiting for something much smarter!

<body>
<div style="border: 50px solid red;">
    <div>
        <input id="numbers"/>
    </div>
</div>
</body>

And this is how it looks like.

KendoUI ComboBox list moving style from body to a div
KendoUI ComboBox list moving style from body to a div

Second problem: List area wrong positioning

The topic is the same since this is what I trying to solve when I found problem number 1.

Here, I was trying to set a div as container and looking similar to KendoUI popups. Something like this:

Styling a div to look like a KendoUI popup
Styling a div to look like a KendoUI popup

So I have defined the following HTML:

<div class="k-popup k-group" style="min-height: 200px; padding: 8px;">
    <div>
        <input id="numbers"/>
    </div>
</div>

And when I open the ComboBox:

Misplace ComboBox list
Misplace ComboBox list

As you can see it is not correctly positioned (a little left and up).

Solution

Despite of this information about KendoUI styling, you cannot use k-popup and k-group around ComboBoxes. You have to copy the style and define your own.

<div class="ob-popup" style="min-height: 200px; padding: 8px">
    <div>
        <input id="numbers"/>
    </div>
</div>

where ob-group is:

.ob-group {
    -webkit-box-shadow: rgba(0, 0, 0, 0.298039) 0px 2px 2px 0px;
    box-shadow: rgba(0, 0, 0, 0.298039) 0px 2px 2px 0px;
    background-color: #ebebeb;
    border: 1px solid #c5c5c5;
}

This is not a very nice solution since you need to check what k-popup and k-group are in your theme but at least it works.

Third Problem: (very) Wrong positioning

As I’ve already said, I’m curious and I like to do extensive testing before shipping a product / a solution / a patch / a piece of code… it saves me a looooot of time.

So, I prepare a test where I mixed two ComboBoxes, the first with the solution to problem 2 (use ob-group) and another without the solution (use k-group and k-popup).

This is the HTML code:

<div class="ob-group" style="min-height: 100px; padding: 8px">
    <div>
        <input id="numbers1"/>
    </div>
</div>
<div class="k-group k-popup" style="min-height: 100px; padding: 8px">
    <div>
        <input id="numbers2"/>
    </div>
</div>

this the JavaScript:

$(document).ready(function () {
    var numbers1 = [
        "One",
        "Two",
        "Three"
    ];
    var numbers2 = [
        "1",
        "2",
        "3"
    ];
    $("#numbers1").kendoComboBox({
        dataSource :numbers1,
        placeholder:"number1"
    }).data("kendoComboBox");
    $("#numbers2").kendoComboBox({
        dataSource :numbers2,
        placeholder:"number2"
    }).data("kendoComboBox");
});

The first ComboBox has a list with: “One”, “Two” and “Three” while the second with: 1, 2, 3.

and this the capture…

ComboBoxes not using and using  k-popup and k-group in a container div
ComboBoxes not using and using k-popup and k-group in a container div

Looks fine! Lets try opening the second one…

Oops! It open just bellow the first but shows the values of the second!!!

Actually, the problem is not that it opens near the first but in that absolute position, if we remove the ComboBox but leave the DIV we see that it actually opens in the same place.

So, it doesn’t look that bad. Lets try it not using k-group and k-popup

Conclusion

Actually, there is only one bug: the one about the border and body. The second is a side effect of a common dangerous practice used in JavaScript and HTML (and I must recognize that I use it too) based on using class names as node selectors: this is a huge source of errors since there are side effect when someone uses that class name where is not expected leading to wrong node selection.

Zafu: CouchDB and KendoUI (part 4)


In recent posts I’ve shown how to use KendoUI cascading ComboBox and map/reduce in CouchApps, Lets combine the two of them.

Populating KendoUI ComboBox

NOTE: I’m going to be using the database used in here, refer to that post for details.

Lets start defining the map and reduce JavaScript code using in this view:

// Map function
function(doc) {
    if (doc.type==="cities") emit(doc.state, doc.city );
}
// Reduce function
function(keys, values) {
    return true;
}

The map function emits pairs of records with a key that is the state and a value that is the city. This allows me to use the same map/reduce for getting the states (setting reduce and group to true) and for getting the cities in a state (by setting as key the name of the state).

Then I will start populating the first ComboBox with the name of the states:

$("#state").kendoComboBox({
    autoBind      :true,
    ignoreCase    :true,
    highlightFirst:true,
    delay         :100,
    placeholder   :"State",
    suggest       :true,
    dataSource    :{
        serverFiltering:true,
        transport      :{
            read:function (operation) {
                db.view("post20/getCities", {
                    success:function (data) {
                        var states = [];
                        var rows = data.rows;
                        $.each(rows, function (idx, value) {
                            states.push(value.key);
                        });
                        operation.success(states);
                    },
                    error  :function (status) {
                        console.log(status);
                    },
                    group  :true,
                    reduce :true
                });
            }
        }
    }
}).data("kendoComboBox");

In the success function what I do is extracting the keys retrieved that are the name of the states.

Populating the cities uses the same view but disables reduce by setting it to false, In addition I sort the results in order to get the cities order alphabetically.

$("#city").kendoComboBox({
    autoBind      :false,
    cascadeFrom   :"state",
    highlightFirst:true,
    delay         :100,
    index         :0,
    placeholder   :"City",
    suggest       :true,
    dataSource    :{
        serverFiltering:true,
        transport      :{
            read:function (operation) {
                db.view("post20/getCities", {
                    success:function (data) {
                        var cities = [];
                        var rows = data.rows;
                        $.each(rows, function (idx, value) {
                            cities.push(value.value);
                        });
                        operation.success(cities.sort());
                    },
                    error  :function (status) {
                        console.log(status);
                    },
                    key    :$("#state").val(),
                    reduce :false
                });
            }
        }
    }
}).data("kendoComboBox");

Optimizations

Both the data organization in the documents and views are not optimal neither in time nor in space but designed for illustrating map/reduce and KendoUI Cascading ComboBoxes.