I’ve starting hitting walls with Kendo UI not supporting some expected functionality. The Angular UI Slider makes it easy change the configuration options at run time and thereby change the min and max settings. I’m hugely disappointed that there isn’t a way to do this seamlessly with the Kendo UI slider. I was hoping this was a case of me needing to RTFM but my forum post confirmed that I can’t “refresh” the slider.

The current recommended hack is to call the destroy function, remove it from the DOM, and then recreate the slider. That isn’t slick but I have a job to do so here we go:

<div kendo-slider="baddassSlider" expanding-slider="[100, 300, 700, 1500]"></div>
(function () {
  angular
    .module('kendoExtensions', [])
    .directive('expandingSlider', expandingSlider);
   
  expandingSlider.$inject = ['$compile'];
    
  function expandingSlider() {
    return {
      restrict: 'A',
      link: function (scope, el, attrs) {
        var increments = scope.$eval(attrs.expandingSlider).slice();
        var $el = $(el);
        
        var unbindWatch = scope.$watch(function () {
          return scope[attrs.kendoSlider];
        }, function(slider) {
          if (angular.isDefined(slider)) {
            unbindWatch();
            bindSliderBehavior(slider);
          }
        });
        
        function bindSliderBehavior(slider) {
          scope.$watch(function () {
            return slider.value();
          }, function (newSliderVal) {
            var max = attrs.kMax;
            
            if (newSliderVal && newSliderVal >= max && increments.length > 0) {
              var newMax = getNextIncrement(newSliderVal);
              $el.attr('k-max', newMax);
              $el.attr('k-small-step', newMax / 100);
              $el.attr('increasing-slider', '[' + increments.toString() + ']');
              var html = $el.get(0).outerHTML;
              
              slider.destroy();
              
              var newSlider = $compile(html)(scope);
              newSlider.attr('style', '');
              delete scope[attrs.kendoSlider];
              $el.parents('.k-slider').replaceWith(newSlider);
            }
          });
        }
        
        function getNextIncrement(currentValue) {
          var nextIncrement;
    
          do {
            nextIncrement = increments.shift();
            if (!nextIncrement) {
                nextIncrement = currentValue;
            }
          } while (nextIncrement < currentValue);
    
           return nextIncrement;
        }
      }
    };
  }
})();

I started the ReactJS-OC meetup group this month and we just had our first gathering. I presented on the fundamental concepts of ReactJS and how to get started. There were technical difficulties but we managed with some humor. Humongous thanks to PeopleSpace and Codazen for sponsoring with a venue and food, respectively.

I quit my cushy engineering job a month and half ago to be an independent developer. It wasn’t an overnight decision and a lot of thought and ramp up went into it. My long game is to bootstrap a recurring revenue product but for now this is what pays the bills. I’ll detail that path in another post but this one is about being a hired gun.

If you are looking for inspiration then I’ve got a list of freelancing resources for you.

Podcasts

  1. Freelancer’s Show
  2. Double Your Freelancing Rate
  3. Working without Pants
  4. The Art of Value

Reading

  1. Double Your Freelancing Rate
  2. Nusii
  3. Badass: Making Users Awesome
  4. Get Clients Now!
  5. Book Yourself Solid

If you’re already using Kendo UI in your AngularJS project then I don’t need to sing praises for how easy Telerik made integration. They’ve made the developer experience simple and I’m happy to for the Pro version. I’ve recently become an independent consultant and it’s amazing what I will pay for to get my work done better and faster. That’s another post for another day, though.;

Using any of the Kendo UI widgets is as simple as using a directive.

<input kendo-date-picker name="dob" id="dobPicker" />

In real life though you often want to call on the widget APIs to programmatically do something. If you were in a plain ole’ jQuery app you could open the above date picker like so

$('#dobPicker').data('kendoDatePicker').open();

But how do you do this in AngularJS without using jQuery? In one of my applications I use an accordion but the specs changed to say the first two sections have to always expand on page load. I needed a way to access the Panel Bar’s APIs to do this.

<ul kendo-panel-bar="accountAccordion" k-expand-mode="'multiple'" init-expanded="[1,2]" id="accountFormAccordion">
    <li>
        Personal Information
        <div>Some personal info inputs</div>
    </li>
    <li>
        Business Information
        <div>Some business information inputs</div>
    </li>
    <li>
        Permissions
        <div>ome permission inputs</div>
    </li>
</ul>

Of course I don’t want to rely on using $('#accountFormAccordion').data('kendoPanelBar') because this is an Angular application. Instead I created a directive that can be reused with the kendo-panel-bar directive.

angular
    .module('kendo.extras')
    .directive('initExpanded', initExpanded);

function initExpanded() {
    return {
        restrict: 'A',
        link: function (scope, el, attrs) {
            var sectionIndexes = scope.$eval(attrs.initExpanded);

            scope.$watch('accountAccordion', function (accordion) {
                if (angular.isDefined(accordion)) {
                    sectionIndexes.forEach((idx) => {
                        accordion.expand('li:nth-child(' + idx + ')');
                    });
                }
            });
        }
    };
}

You can access your Kendo widget inside your Angular directives and controllers by giving it name when you declare your Kendo widget in your template. In my example I name it ‘accountAccordion’ and Kendo puts it on the scope for me to use.

If you want to use Kendo UI or any other UI widget library with ReactJS then you’ll need to understand the component lifecycle. This really somewhat contrived example uses the Kendo date picker.

var React = require('react');

var KDatePicker = React.createClass({
    render: function () {
        return (
            <input type="text" id={this.props.id}/>
        );
    },

    componentDidMount: function () {
        $(this.getDOMNode()).kendoDatePicker();
    }
});

module.exports = KDatePicker;

After the component renders React will call the componentDidMount method and this is where you can call Kendo or jQuery UI’s methods to initialize their widgets.