angularjsangularjs-scope

Angular binding does not work in data- attribute


I am using some css html template that comes with many html components and with lots of data-attributes for various things. For example for slider it has something like

 <div class="slider slider-default">
    <input type="text" data-slider class="slider-span" value="" data-slider-orientation="vertical" data-slider-min="0" data-slider-max="200" data-slider-value="{{ slider }}" data-slider-selection="after" data-slider-tooltip="hide">
</div>

Here I am trying to bind the value

data-slider-value="{{ slider }}"

But it's not working. Variable 'slider' is set in the $scope as:

   $scope.slider = 80;

Same value 80 shows up right when I bind it as:

 <h4>I have {{ slider }} cats</h4>

I have also tried

    ng-attr-data-slider-value="{{ slider }}" 

It didn't work.

Update

The directive has something like this

function slider() {
    return {
        restrict: 'A',
        link: function (scope, element) {
            element.slider();
        }
    }
};

where element.slider(); calls the code in bootstrap-slider.js (from here) for each of the sliders.


Solution

  • I played with this for a while, and came up with a few options for you. See my Plunkr to see them in action.

    Option 1: No need to update the scope value when the slider changes

    This will work with the HTML from your question. The following is what you should change the directive code to.

    app.directive('slider', function slider() {
      return {
        restrict: 'A',
        link: function(scope, element, attrs) {
          attrs.$observe('sliderValue', function(newVal, oldVal) {
            element.slider('setValue', newVal);
          });
        }
      }
    });
    

    Option 2: Two way binding to the scope property

    If you need the scope property to be updated when the slider handle is dragged, you should change the directive to the following instead:

    app.directive('sliderBind', ['$parse',
      function slider($parse) {
        return {
          restrict: 'A',
          link: function(scope, element, attrs) {
            var val = $parse(attrs.sliderBind);
            scope.$watch(val, function(newVal, oldVal) {
              element.slider('setValue', newVal);
            });
    
            // when the slider is changed, update the scope
            // property.
            // Note that this will only update it when you stop dragging.
            // If you need it to happen whilst the user is dragging the
            // handle, change it to "slide" instead of "slideStop"
            // (this is not as efficient so I left it up to you)
            element.on('slideStop', function(event) {
              // if expression is assignable
              if (val.assign) {
                val.assign(scope, event.value);
                scope.$digest();
              }
            });
          }
        }
      }
    ]);
    

    The markup for this changes slightly to:

    <div class="slider slider-default">
      <input type="text" data-slider-bind="slider2" class="slider-span" value="" data-slider-orientation="vertical" data-slider-min="0" data-slider-max="200" data-slider-selection="after" data-slider-tooltip="hide" />
    </div>
    

    Note the use of the data-slider-bind attribute to specify the scope property to bind to, and the lack of a data-slider-value attribute.

    Hopefully one of these two options is what you were after.