Kendo UI: One data source, two widgets
Asked Answered
F

2

9

UPDATE: Here is a link to reproduce the problem

RELATED: This is another question of mine where similar problems are happening with Kendo UI Map, maybe it could help someone figure this one out! It has one failing and one working version.


I use Kendo UI's DataSource, DropDownList and Map in an Angular single-page application.

I want to use the same DataSource object for both the DropDownList and the Map. However, the Map behaves in a very unpredictable manner.

  1. When I put the DropDownList before the Map in the template, only the DropDownList gets populated. Inspecting the network traffic reveals that indeed only one request is being made. When I put the Map first, both of them get populated and two requests are made.
  2. When I don't use any promises in transport.read, but just call options.success immediately with a static value, everything works as expected. Two calls are being made.

I've been pulling my hair over this the entire work day, so any help is highly appreciated.

The data source service:

m.factory('ourDataSource', function(foo, bar, baz) {
    return new kendo.data.DataSource({
        transport: {
            read: function(options) {
                foo().then(function (result) {
                    return bar(result);
                }).then(function (result) {
                    return baz(result);
                }).then(function (result) {
                    options.success(result);
                }).catch(function (err) {
                    options.error(err);
                });
            }
        }
    });
});

The controller:

m.controller('ourController', ['ourDataSource', function(ourDataSource) {

    // set the data source of the dropdownlist
    this.ourDataSource = ourDataSource;

    // set up the map layers
    this.mapLayers = [{
        type: 'tile',
        urlTemplate: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/#= zoom #/#= y #/#= x #',
    }, {
        type: 'marker',
        dataSource: ourDataSource, // the same data source as before
        locationField: 'Position',
        titleField: 'Title'
    }];
}]);

The view:

<div ng-controller="ourController as ctrl">

    <select kendo-drop-down-list
            k-data-text-field="'Title'"
            k-data-value-field="'Title'"
            k-data-source="ctrl.ourDataSource"></select>

    <div kendo-map
         k-zoom="2"
         k-center="[1, 1]"
         k-layers="ctrl.mapLayers">
    </div>

</div>

What am I missing here?

Fencible answered 3/3, 2016 at 15:40 Comment(12)
But, you don't want two read requests. It's a shared data source, so, why would you want it to request the same data twice? As for why it's not binding to the data, we'd probably need a public example that duplicates this behavior. It's hard to deduce as-is.Nicolasanicolau
@Brett: Indeed, I don't want two requests, but even when I disable autoBind and call fetch manually, the result is the same. I felt like it would be easier to figure out if I reduced the test case to the simplest possible. I'll see if I can set up a public example.Fencible
Could it be because ourDataSource is a factory that's returning a new datasource object? Try returning it as a singleton.Nicolasanicolau
@Brett: I'll try your suggestion. Meanwhile, I wrote an example displaying the problem in action, see the edited question!Fencible
@Brett: When I think about it, factory already creates a singleton in AngularJS, unless I'm mistaken?Fencible
Yea, I'm not sure either. It was a guess. Unfortunately, I can't get the dojo to run because work blocks it. I'll try from home later.Nicolasanicolau
@Brett: Have you had a chance to check it out yet? :)Fencible
Odd behavior. I'm at a loss to why this is occurring.Nicolasanicolau
Just to confirm : From the another question that you had posted, If we apply the same fix to this, it is working fine I guess. Dojo Link. Am I right?Subdelirium
@pathrik: Yes, I think so. The questions are slightly different though, even though the cause might be the same. For example, in this question, everything works if I put the map before the dropdown in the template, but not the other way around. The other question is specifically about why k-layers and k-options behave differently.Fencible
Does this problem still occur with a different promise library other than $q, say $http?Nicolasanicolau
@Brett: It happens when I use $resource as well, which I think uses $http. In fact, that's how I noticed the problem, I just happened to reproduce it using $q. I'm not sure, but I think $http probably uses $q itself!Fencible
N
0

I believe that this might be a bug in the Kendo UI Map widget, since the behavior occurring here isn't at all what one would expect. However, I do have a workaround solution. Rather than return the data source as a singleton object, return it as a function. This is probably not ideal, but it works.


angular.module('ourModule', ['kendo.directives'])
.factory('getDataSource', function ($q) {
  return function() {  // return a function that creates a new data source
    return new kendo.data.DataSource({
      transport: {
        read: function (options) {
          $q.when([
            {Position: [1, 1], Title: 'First place'},
            {Position: [10, 10], Title: 'Second place'}
          ]).then(function (result) {
            options.success(result);
          });
        }
      }
    });
  };
})
.controller('ourController', function (getDataSource) {
  this.ourDataSource = getDataSource();      
  this.mapLayers = [{
    type: 'tile',
    urlTemplate: '...removed for brevity...'
  }, {
    type: 'marker',
    dataSource: getDataSource(),
    locationField: 'Position',
    titleField: 'Title'
  }];
});
Nicolasanicolau answered 9/3, 2016 at 15:23 Comment(0)
B
0

Factory mostly used to create instances on demand. See this example

var app = angular.module('ourModule', ['kendo.directives']);

 app.factory('dataSourceFactory', function($q) {

  function dataSourceFactory() {}

  dataSourceFactory.prototype = {
   contentTypes: function() {
    return new kendo.data.DataSource({
     transport: {
      read: function(options) {
       $q.when(
         [{
          Position: [1, 1],
          Title: 'First place'
         }, {
          Position: [10, 10],
          Title: 'Second place'
         }])
        .then(function(result) {
         options.success(result);
        });
      }
     }
    })
   }
  };

  return dataSourceFactory;
 });

 app.controller('ourController', ['$scope', 'dataSourceFactory',

  function($scope, dataSourceFactory) {

   var dataSourceFactory = new dataSourceFactory();

   $scope.mapLayers = [{
    type: 'tile',
    urlTemplate: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/#= zoom #/#= y #/#= x #',
   }, {
    type: 'marker',
    dataSource: dataSourceFactory.contentTypes(), // the same data source as before
    locationField: 'Position',
    titleField: 'Title'
   }];

   $scope.ourDataSource = dataSourceFactory.contentTypes();
  }
 ]);
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2015.3.930/styles/kendo.common.min.css">
  <link rel="stylesheet" href="http://kendo.cdn.telerik.com/2015.3.930/styles/kendo.rtl.min.css">
  <link rel="stylesheet" href="http://kendo.cdn.telerik.com/2015.3.930/styles/kendo.default.min.css">
  <link rel="stylesheet" href="http://kendo.cdn.telerik.com/2015.3.930/styles/kendo.mobile.all.min.css">

  <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
  <script src="http://kendo.cdn.telerik.com/2015.3.930/js/angular.min.js"></script>
  <script src="http://kendo.cdn.telerik.com/2015.3.930/js/jszip.min.js"></script>
  <script src="http://kendo.cdn.telerik.com/2015.3.930/js/kendo.all.min.js"></script>

<div ng-app="ourModule">
  
  <div ng-controller="ourController">
 		   
    <kendo-drop-down-list k-data-source="ourDataSource"
                          k-data-text-field="'Title'"
                          k-data-value-field="'Title'">
    </kendo-drop-down-list>

    <kendo-map k-zoom="2"
               k-layers="mapLayers">
    </kendo-map>
    
  </div>
</div>

See this JSFiddle demo

Burgle answered 10/3, 2016 at 8:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.