Telerik blogs

In our first release of this year, we announced a new project at Kendo UI called "Labs". This is an incubator where we put all of the community contributions, as well as integrations with third party libraries. One of our most requested integrations has been for AngularJS.

Today, I am pleased to announce the official release of Angular Kendo UI. This is a complete set of directives for every widget in both the Web and DataViz suites. The goal was to provide deep integration with AngularJS while keeping Kendo UI's familiar declarative API. Angular Kendo UI is offered completely free and open under the Apache 2 license, and you can start using it in your Angular Projects today.

*Disclaimer*: While Angular Kendo UI is not supported under the formal Kendo UI support agreement, this is an active community project, and we would LOVE for you to open an issue, or fork the repo and submit a pull request. StackOverflow is also a great place to get assistance.

This project is brought to you by the Kendo UI Developer Relations team, and the tireless efforts of Pierre Asselin and Omkar Patil, who are members of the Labs Core Team. This project was not created for demos. It is not a proof of concept. It was largely influenced by Pierre and Omkar, who are doing development with Kendo UI and AngularJS right now, where they work, even as I write this article.

Up And Running

We structured the demo page so that you could quickly and easily wrap your mind around the way Kendo UI functions as a set of directives for AngularJS. If you aren't familiar with what AngularJS directives are, I wrote an article on ADC a few months ago that sums up the basics. Plainly stated, they are to AngularJS what declarative initialization is to Kendo UI. Let's look at an example.

If you were going to initialize an element with Kendo UI, you have two choices for how you do it. You can do it either imperatively, or declaratively.

Imperative Widget Initialization

<select id="things">
  <option value="1">Thing 1</option>
  <option value="2">Thing 2</option>
  <option value="3">Thing 3</option>
</select>

<script>
  // initialize a Kendo UI DropDownList imperatively
  $("#things").kendoDropDownList();
</script>

Declarative Widget Initialization

<select id="things" data-role="dropdownlist">
  <option value="1">Thing 1</option>
  <option value="2">Thing 2</option>
  <option value="3">Thing 3</option>
</select>

<script>
  // initialize all widgets in the page declaratively
  kendo.init(document.body);
</script>

There are strong opinions on both sides of the initialization debate. I don't want to stir the pot further, but allow me to propose that letting the markup define it's own function makes applications easier to maintain and scale. A phrase I use commonly is, "A div is not a calendar, a div is a div". It's difficult to tell what your markup's actual function is if the initialization is contained in a separate JavaScript file.

This is the idea of "compontizing" the web. Kendo UI has embraced this with declarative initialization, and AngularJS embraces it with directives. That being said, we have provided you with both methods of initialization to the best of our ability.

The Directive Direction

AngularJS glues the HTML to your JavaScript by way of controllers. While you can reference to the DOM from a controller, you shouldn't do that. Instead, AngularJS allows you to create something called a "directive". This is an isolated unit of code which is executed by AngularJS when it it's reference is found on an HTML element. Directives can be defined either as custom elements, attributes, comments, or classes. Some directives are quite simple, like ng-repeat.

ng-repeat Directive

// controller
function MyController($scope) {
  $scope.things = ["Thing 1", "Thing 2", "Thing 3"];
}

// page
<ul>
  <li ng-repeat="thing in things">{{thing}}</li>
</ul>

This, or course, lists out all of the "things" defined in the array on the controller. It seems kind of like magic doesn't it?

Since you aren't supposed to initialize widgets from a controller, you need to have directives that will do it for you. I initially wrote the first pass at AngularJS directives for Kendo UI. The way that I did it was simply to call kendo.bind() and let you intialize all widgets with the same declarative initialization that you would normally use.

Angular Kendo UI v 0.0.9

function MyController($scope) {
  $scope.model = kendo.observable({
    var things = [ "Thing 1", "Thing 2", "Thing 3" ]
  });
}

// page
// No need to call bind, the AngularJS directive does it for you
<select id="things" data-role="dropdownlist" data-model="model" data-bind="source: things">
</select>

This works fine, and you can even specify a view model on the controller for data. The problem was that it just wasn't deeply integrated with AngularJS. It was essentially adding a second binding framework which was isolated from Angular's own. This meant that there was no way to tie widgets into Angular's binding and thus the full power of AngularJS could not be leveraged. The directive itself was really a very simple operation that simply called kendo.bind() on the current element and used the data-model attribute to define an MVVM observable on the controller.

A Complete Re-Write

Shortly after I published this first update, Pierre contacted me via email to make some suggestions about the integrations. Pierre and his team were using Kendo UI and AngularJS on a large project, and were dealing with integrating the two while in the trenches of real world development. Pierre quickly pointed out that we needed more integration with AngularJS, and took the first stab at re-writing the library. What transpired over the next several months was a complete re-write of Angular Kendo UI where we tied Kendo UI into AngularJS at a very fundamental level. Let's look at that same Kendo UI DropDownList as it works now.

Angular Kendo UI v 0.5.0

function MyController($scope) {
  $scope.things = [ "Thing 1", "Thing 2", "Thing 3" ]
}

<select kendo-drop-down-list k-data-source="things" k-option-label="'Select A Thing'" ></select>

There are a couple of things to notice here...

  1. The widget is specified with a dashed version of it's name - kendo-drop-down-list
  2. Any configuration attributes are preceded with a k-
  3. Anytime you have a configuration value that is not a primitive, you need to put single quotes around it. This is par for the course for AngularJS. We wanted to stay true to Angular, while at the same time staying as true to Kendo UI as we could. This is something that can trip you up, so Pierre added in a check that will shell out an error to your console if you forget the single quotes.
  4. The widget can bind directly to an object on the scope. No need to wrap it in an observable

This means that you could grab the current value of the DropDownList and spit it back out using AngularJS template syntax.

Binding To Widget Values

function MyController($scope) {
  $scope.things = [ "Thing 1", "Thing 2", "Thing 3" ];
  $scope.selected = null;
}

<select kendo-drop-down-list k-data-source="things" k-option-label="'Select A Thing'" ng-model="selected"></select>
<div>You selected: {{selected}}</div>

This will of course display the currently selected item in the DropDownList in the div below it. You can see the tight integration between Kendo UI in AngularJS at work here. All you need to provide is the model that the DropDownList is bound to, and the binding is set.

Imperative Configuration In Controllers

I realize that not everyone agrees with me about putting all the configuration in the markup. On top of that, some configuration values are difficult to cite as attribute values due to the fact that you need to make sure that any objects are properly formed JSON. This can get tedious. For this reason, we allow you to specify your options on the controller, and pass them in to the k-options attribute.

Passing Configuration From The Controller

function MyController($scope) {
  $scope.things = {
    dataSource: {
      data: [ "Thing 1", "Thing 2", "Thing 3" ]
    },
    optionLabel = "Select A Thing"
  };
}

<select kendo-drop-down-list k-data-source="things" ng-model="selected"></select>
<div>You selected: {{thing}}</div>

This allows you to do an imperative sort of initialization, without having to actually break the testability of your controllers by including selection of the DOM.

Events

If you are configuring your widget with options in the controller, handling events is exactly the same as the Kendo UI API.

Events In Configuration Objects

// controller
function MyController($scope) {
  $scope.things = {
    dataSource: new kendo.data.DataSource({
      data: [ "Thing 1", "Thing 2", "Thing 3" ]
    }),
    optionLabel: "Select A Thing",
    change: function(e) {
      console.log(e.sender.text());
    }
  };
}


// markup
<select kendo-drop-down-list k-options="things"></select>

However, if you you can assign any event declaratively to a controller function by prefixing it with k-on and passing in a kendoEvent object.

Handling Widget Events

// controller
function MyController($scope) {
  $scope.things = {
    dataSource: new kendo.data.DataSource({
      data: [ "Thing 1", "Thing 2", "Thing 3" ]
    }),
    optionLabel: "Select A Thing"
  };

  $scope.thingsChange = function(e) {
    console.log(e.sender.text());
  }
}

// markup
<select kendo-drop-down-list k-options="things" k-on-change="thingsChange(kendoEvent)"></select>

Assigning Widget References

There are some occasions where you need to get a reference to a widget so that you can perform some sort of operation on it. A good example of this is the Kendo UI Window widget. It's likely that you will want to show the window on some certain event. You can assign a reference to the widget to a scope variable by passing the name directly into the widget directive itself.

Assigning Widget References

scope MyController($scope) {
  // this variable will hold the window reference
  // it will be automatically added to the scope if you don't declare it
  $scope.window;

  $scope.openWindow = function() {
    $scope.window.open();
  }
}

<button ng-click="openWindow()">Open Window</button>
<div kendo-window="window" k-visible="false" k-modal="true">
  <h1>Hi! I'm a window</h1>
</div>

This is a powerful tool in your arsenal, but use it responsibly. While you can still test your controllers, it's adviseable not to use widget references if you can avoid it.

A Complete UI Framework For AngularJS

We think that Kendo UI is the best choice for rich, fluid, and performant applications. We also think AngularJS provides a compelling end-to-end framework that changes the fundamental way we think about stitching all the pieces of a web application together. Together, you have an extremely powerful stack on which to build applications of considerable size and complexity.

We've worked very hard on this and are really thrilled to be able to release it. We look forward to seeing your feedback, issues, and of course pull requests! :)

Check Out Angular Kendo UI!


Burke Holland is the Director of Developer Relations at Telerik
About the Author

Burke Holland

Burke Holland is a web developer living in Nashville, TN and was the Director of Developer Relations at Progress. He enjoys working with and meeting developers who are building mobile apps with jQuery / HTML5 and loves to hack on social API's. Burke worked for Progress as a Developer Advocate focusing on Kendo UI.

Comments

Comments are disabled in preview mode.