Rodney
Rodney

Reputation: 125

Convert jQuery UI slider widget to AngularJS directive

I'm trying to build an Angular directive that creates a keyboard-accessible slider widget. I found several Angular sliders on Github, but none of them are keyboard-accessible. So, I'm trying to convert the jQuery UI slider to an Angular directive.

Here is how I'd build the widget without Angular.

HTML:

<div id="slider"></slider>
<input type="text" id="amount"/>

Javascript:

$("#slider").slider({
  min: 1,
  max: 10,
  slide: function(event, ui) {
    $("#amount").val(ui.value);
  }
});

And this is how I'd like the Angular directive to work:

<slider min="1" max="10" ng-model="sliderValue"/>
<input type="text" ng-model="sliderValue"/>

As an example, here is a jsFiddle that shows how someone converted a jQuery UI date widget to an Angular directive.

http://jsfiddle.net/xB6c2/121/

I'd like to do something similar to this for the slider widget. Thanks!

Upvotes: 2

Views: 8080

Answers (3)

Ionel POP
Ionel POP

Reputation: 833

A small improvement over the Rodney's solution:

app.directive('slider', function() {
    return {
        restrict: 'AE',
        link: function(scope, element, attrs) {
            element.slider({
                value: scope[attrs.ngModel],
                min: parseInt(attrs.min),
                max: parseInt(attrs.max),
                step: parseFloat(attrs.step),
                slide: function(event, ui) {                    
                    scope.$apply(function() {           
                        scope[attrs.ngModel] = ui.value;
                    });
                }
            });

            scope.$watch(attrs.ngModel, function(newVal, oldVal){
                element.slider({value: newVal});
            });
        }      
    };
});

It allows to detect and update the slider position if the model changes.

If your model contains dots (for instance, ngmodel = "Configuration.Size"), scope[attrs.ngModel] no longer works. A workaround is to use _.get and _.set from lodash library instead.

Upvotes: 1

Rodney
Rodney

Reputation: 125

Here is a solution that works. Thank you to Duc Hong - his answer was instrumental in helping me to figure this out. Please let me know if there is a better way to do this.

app.directive('slider', function() {
    return {
        restrict: 'AE',
        link: function(scope, element, attrs) {
            element.slider({
                value: scope[attrs.ngModel],
                min: parseInt(attrs.min),
                max: parseInt(attrs.max),
                step: parseFloat(attrs.step),
                slide: function(event, ui) {
                    scope.$apply(function() {
                        scope[attrs.ngModel] = ui.value;
                    });
                }
            });
        }
    };
});

Upvotes: 6

Duc Hong
Duc Hong

Reputation: 1179

you can write up a directive for your UI slider, it works something like this:

<input type="text" ng-model="setMin" />
<input type="text" ng-model="setMax" />
<slider min="setMin" max="setMax"></slider>

and your directive would be something like this:

app.directive("slider", function() {
    return {
        restrict: "AE",
        scope:{
           min:"=",
           max:"="
        },
        link: function(scope, ele, attrs) {

            ele.slider({
                min: scope.min,
                max: scope.max,
                range: "min",
                value: "5",
                slide: function(event, ui) {
                    scope.$apply(function() {
                        //update on the view using ui.value;
                        //scope.number =  = ui.value;
                    });
                }
            });

           // You can watch the value min,max and then reapply your UI slider 
            scope.$watch('setMin', function(newValue, oldValue) {
                if (newValue !== null && newValue !== undefined) {
                   // re-apply UI slider
                }
            }, true);

            scope.$watch('setMax', function(newValue, oldValue) {
                if (newValue !== null && newValue !== undefined) {
                   // re-apply UI slider
                }
            }, true);

        }
    }
});

Hopefully you get the idea, cheers

Upvotes: 1

Related Questions