This is a migrated thread and some comments may be shown as answers.

View Model with an Array Property - Performance Issue (maybe a bug).

3 Answers 151 Views
MVVM
This is a migrated thread and some comments may be shown as answers.
Grant Parker
Top achievements
Rank 1
Grant Parker asked on 26 Nov 2013, 08:37 PM
If you have a View Model that has a property that is an array and you bind it via "kendo.bind", whenever you change any input bound to the array, it refreshes/rebinds the ENTIRE ARRAY.  Is this by design or a bug?  It is definitely a performance issue when you have a big array.  Below is a sample project I made to demonstrate.  If you type a character in any of the inputs, it will auto-tab to the next input.  However, due to performance issue, it takes a long time for it to do so.  I am logging the "get" event to the console, and you will see that after you type into one of the inputs, every property of every item in the array is gotten again; hence the horrible performance.

================================================================
@{
ViewBag.Title = "Test";
}

<div id="placeholder"></div>

<script type="text/x-kendo-template" id="template">
<table id="scorecard">
<caption>#= TeamName #</caption>
# for (var i = 0; i < Scores.length; i++) { #
<tr>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H1', i) #" value="#= Scores[i].H1 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H2', i) #" value="#= Scores[i].H2 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H3', i) #" value="#= Scores[i].H3 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H4', i) #" value="#= Scores[i].H4 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H5', i) #" value="#= Scores[i].H5 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H6', i) #" value="#= Scores[i].H6 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H7', i) #" value="#= Scores[i].H7 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H8', i) #" value="#= Scores[i].H8 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H9', i) #" value="#= Scores[i].H9 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H10', i) #" value="#= Scores[i].H10 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H11', i) #" value="#= Scores[i].H11 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H12', i) #" value="#= Scores[i].H12 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H13', i) #" value="#= Scores[i].H13 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H14', i) #" value="#= Scores[i].H14 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H15', i) #" value="#= Scores[i].H15 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H16', i) #" value="#= Scores[i].H16 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H17', i) #" value="#= Scores[i].H17 #" /></td>
<td><input data-bind="#= kendo.format('value: Scores[{0}].H18', i) #" value="#= Scores[i].H18 #" /></td>
</tr>
# } #
</table>
</script>

@section Scripts
{
<script>
$(function () {
var
score, template, placeholder,
randomScore = function () { return Math.floor((Math.random()*10)+1); },
model = { TeamName: 'John Doe', Scores: [] };

for (var i = 0; i < 500; i++) {
score = { Number: i };
for (var j = 1; j <= 18; j++)
score['H' + j] = randomScore();
model.Scores.push(score);
}

model = kendo.observable(model);
model
.bind('get', function (e) {
console.log('getting...' + e.field);
})
.bind('set', function (e) {
console.log('setting...' + e.field);
});

template = kendo.template($('#template').html());
placeholder = $('#placeholder');
placeholder.html(template(model));
kendo.bind(placeholder, model);

$('#scorecard')
.on('focus', 'input', function (e) {
setTimeout(function () {
$(e.target).select();
})
})
.on('input', 'input', function (e) {
var next = $(this).closest('td').next().find('input').focus();
if (!next.length)
$(this).closest('tr').next().find('input:first').focus();
});

});
</script>
}

@section Styles
{
<style>
#scorecard input { width: 2em; }
</style>
}

================================================================

3 Answers, 1 is accepted

Sort by
0
Petur Subev
Telerik team
answered on 28 Nov 2013, 12:14 PM
Hello Grant,

Indeed this is by design, when you bind the ViewModel to whatever is generated from the ListView the following workflow happens:

  1. You change an input
  2. The change event of the bound item is triggered
  3. It bubbles and reaches the dataSource of the listView
  4. The change event of the dataSource is triggered 
  5. The listview listens for this change event of the dataSource and it redraws its template

Sadly I cannot offer you a work-around to this case.

I am sorry for any inconvenience caused.

If you have an idea how to improve the framework in that direction please share it on the feedback portal

Kind Regards,
Petur Subev
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
0
Grant Parker
Top achievements
Rank 1
answered on 02 Dec 2013, 09:33 PM
Hey Petur,

I don't know what "ListView" you are referring too.  I am not using one. 

If you run my demo that I made especially for this post, you will see a table with 500 rows and 18 inputs in each row.  If you change the value of Score #1 in Row #1 all 9000 inputs are refreshed/rebound.  To verify this you can look at your browser's console you will see  9000 entries that look like this  "getting...Scores[0].H1", "getting...Scores[0].H2", all the way to "Scores[499].H18". 

I have changed the demo to be a standalone "*.htm" file that uses your CDN, and attached it.  You should just be able to save to your desktop and click it.  Be sure to have your browser console open when you run it.

** Console Output **
   setting...Scores[0].H1
   getting...Scores[0].H1
   getting...Scores[0].H2
   getting...Scores[0].H3
   getting...Scores[0].H4
   getting...Scores[0].H5
   getting...Scores[0].H6
   getting...Scores[0].H7
   getting...Scores[0].H8
   getting...Scores[0].H9
   getting...Scores[0].H10
   getting...Scores[0].H11
   getting...Scores[0].H12
   getting...Scores[0].H13
   getting...Scores[0].H14
   getting...Scores[0].H15
   getting...Scores[0].H16
   getting...Scores[0].H17
   getting...Scores[0].H18
   getting...Scores[1].H1
   getting...Scores[1].H2
   getting...Scores[1].H3
   getting...Scores[1].H4
   getting...Scores[1].H5
   getting...Scores[1].H6
   getting...Scores[1].H7
   getting...Scores[1].H8
   getting...Scores[1].H9
   getting...Scores[1].H10
   getting...Scores[1].H11
   getting...Scores[1].H12
   getting...Scores[1].H13
   getting...Scores[1].H14
   getting...Scores[1].H15
   getting...Scores[1].H16
   getting...Scores[1].H17
   getting...Scores[1].H18
   getting...Scores[2].H1
   getting...Scores[2].H2
   getting...Scores[2].H3
   getting...Scores[2].H4
   getting...Scores[2].H5
   getting...Scores[2].H6
   getting...Scores[2].H7
   getting...Scores[2].H8
   getting...Scores[2].H9
   getting...Scores[2].H10
   getting...Scores[2].H11
   getting...Scores[2].H12
   getting...Scores[2].H13
   getting...Scores[2].H14
   getting...Scores[2].H15
   getting...Scores[2].H16
   getting...Scores[2].H17
   getting...Scores[2].H18
...
...
...
   getting...Scores[499].H18

0
Petur Subev
Telerik team
answered on 04 Dec 2013, 02:32 PM
Hello again,

Thank you for sending the sample page. It seems I misunderstood your case - my apologies. I can suggest you to use source binding instead of the nested binding that you are trying.

Check the attached example - you will avoid redrawing the whole hierarchy and also avoid focus issue.

I hope this helps.

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Kendo MVVM Bug</title>
        <style>
            #scorecard input { width: 2em; }
        </style>
    </head>
    <body>
        <div id="placeholder"></div>
        <script type="text/x-kendo-template" id="template">
            <table id="scorecard">
                <caption>#= TeamName #</caption>
                <tbody data-bind="source:Scores" data-template="rowTemplate">
                </tbody>
            </table>
        </script>
         
        <script type="text/kendo" id="rowTemplate">
                <tr>
                    <td><input data-bind="value:H1" /></td>
                    <td><input data-bind="value:H2" /></td>
                    <td><input data-bind="value:H3" /></td>
                    <td><input data-bind="value:H4" /></td>
                    <td><input data-bind="value:H5" /></td>
                    <td><input data-bind="value:H6" /></td>
                    <td><input data-bind="value:H7" /></td>
                    <td><input data-bind="value:H8" /></td>
                    <td><input data-bind="value:H9" /></td>
                    <td><input data-bind="value:H10" /></td>
                    <td><input data-bind="value:H11" /></td>
                    <td><input data-bind="value:H12" /></td>
                    <td><input data-bind="value:H13" /></td>
                    <td><input data-bind="value:H14" /></td>
                    <td><input data-bind="value:H15" /></td>
                    <td><input data-bind="value:H16" /></td>
                    <td><input data-bind="value:H17" /></td>
                    <td><input data-bind="value:H18" /></td>
                </tr>       
        </script>
 
 
        <script src="http://cdn.kendostatic.com/2013.2.918/js/jquery.min.js"></script>
        <script src="http://cdn.kendostatic.com/2013.2.918/js/kendo.all.min.js"></script>
        <script>
            $(function () {
                var
                    score, template, placeholder,
                    randomScore = function () { return Math.floor((Math.random() * 10) + 1); },
                    model = { TeamName: 'John Doe', Scores: [] };
 
                for (var i = 0; i < 500; i++) {
                    score = { Number: i };
                    for (var j = 1; j <= 18; j++)
                        score['H' + j] = randomScore();
                    model.Scores.push(score);
                }
 
                model = kendo.observable(model);
                model
                    .bind('get', function (e) {
                        console.log('getting...' + e.field);
                    })
                    .bind('set', function (e) {
                        console.log('setting...' + e.field);
                    });
 
                template = kendo.template($('#template').html());
                placeholder = $('#placeholder');
                placeholder.html(template(model));
                kendo.bind(placeholder, model);
            });
        </script>
    </body>
</html>


Kind Regards,
Petur Subev
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
Tags
MVVM
Asked by
Grant Parker
Top achievements
Rank 1
Answers by
Petur Subev
Telerik team
Grant Parker
Top achievements
Rank 1
Share this question
or