我有一块手表正在查看我的滑块模型,当我想将其中一个属性设置为可见或启用时,它似乎不想触发更改了手表的事件。如果我单击按钮它应该隐藏或禁用手柄,它不会。如果我拖动另一个句柄,则调用updateDOM,然后隐藏或禁用句柄。不确定我在这里做错了什么。
scope.$watch('sliders', function(oldValue, newValue) {
console.log('sliders Update: ', oldValue, ' : ', newValue);
updateDOM();
});
这是一个有效的插件:http://plnkr.co/edit/I3A9H8qTs0z4CVaYnyJZ?p=preview
'use strict';
angular.module('angularMultiSlider', [])
.directive('multiSliderKey', function($compile) {
return {
restrict: 'EA',
transclude: true,
scope: {
displayFilter: '@',
sliders : '=ngModel'
},
link: function(scope, element) {
var sliderStr = '';
if (scope.displayFilter === undefined) scope.displayFilter = '';
var filterExpression = scope.displayFilter === '' ? '' : ' | ' + scope.displayFilter;
angular.forEach(scope.sliders, function(slider, key){
var colorKey = slider.color ? '<span style="background-color:' + slider.color + ';"></span> ' : '';
sliderStr += '<div class="key">' + colorKey + '{{ sliders[' + key.toString() + '].title }} <strong>{{ sliders[' + key.toString() + '].value ' + filterExpression + '}}</strong></div>';
});
var sliderControls = angular.element('<div class="angular-multi-slider-key">' + sliderStr + '</div>');
element.append(sliderControls);
$compile(sliderControls)(scope);
}
}
})
.directive('multiSlider', function($compile, $filter) {
var events = {
mouse: {
start: 'mousedown',
move: 'mousemove',
end: 'mouseup'
},
touch: {
start: 'touchstart',
move: 'touchmove',
end: 'touchend'
}
};
function roundStep(value, precision, step, floor) {
var remainder = (value - floor) % step;
var steppedValue = remainder > (step / 2) ? value + step - remainder : value - remainder;
var decimals = Math.pow(10, precision);
var roundedValue = steppedValue * decimals / decimals;
return parseFloat(roundedValue.toFixed(precision));
}
function offset(element, position) {
return element.css({
left: position
});
}
function pixelize(position) {
return parseInt(position) + 'px';
}
function contain(value) {
if (isNaN(value)) return value;
return Math.min(Math.max(0, value), 100);
}
function overlaps(b1, b2, offsetTop) {
function comparePositions(p1, p2) {
var r1 = p1[0] < p2[0] ? p1 : p2;
var r2 = p1[0] < p2[0] ? p2 : p1;
return r1[1] > r2[0] || r1[0] === r2[0];
}
var posB1 = [[ b1.offsetLeft, b1.offsetLeft + b1.offsetWidth ], [ offsetTop, offsetTop - b1.scrollTop + b1.offsetHeight ]],
posB2 = [[ b2.offsetLeft, b2.offsetLeft + b2.offsetWidth ], [ b2.offsetTop, b2.offsetTop - b2.scrollTop + b2.offsetHeight ]];
return comparePositions( posB1[0], posB2[0] ) && comparePositions( posB1[1], posB2[1] );
}
return {
restrict: 'EA',
require: '?ngModel',
scope: {
floor: '@',
ceiling: '@',
step: '@',
precision: '@',
bubbles: '@',
displayFilter: '@',
sliders: '=ngModel'
},
template :
'<div class="bar"></div>',
link: function(scope, element, attrs, ngModel) {
if (!ngModel) return; // do nothing if no ng-model
//base copy to see if sliders returned to original
var original;
ngModel.$render = function() {
original = angular.copy(scope.sliders);
};
element.addClass('angular-multi-slider');
// DOM Components
if (scope.displayFilter === undefined) scope.displayFilter = '';
var filterExpression = scope.displayFilter === '' ? '' : ' | ' + scope.displayFilter;
var sliderStr = '<div class="limit floor">{{ floor ' + filterExpression + ' }}</div>' +
'<div class="limit ceiling">{{ ceiling ' + filterExpression + '}}</div>';
angular.forEach(scope.sliders, function(slider, key){
sliderStr += '<div class="handle"></div><div class="bubble">{{ sliders[' + key.toString() + '].title }}{{ sliders[' + key.toString() + '].value ' + filterExpression + ' }}</div>';
});
var sliderControls = angular.element(sliderStr);
element.append(sliderControls);
$compile(sliderControls)(scope);
var children = element.children();
var bar = angular.element(children[0]),
ngDocument = angular.element(document),
floorBubble = angular.element(children[1]),
ceilBubble = angular.element(children[2]),
bubbles = [],
handles = [];
angular.forEach(scope.sliders, function(slider, key) {
handles.push(angular.element(children[(key * 2) + 3]));
bubbles.push(angular.element(children[(key * 2) + 4]));
});
// Control Dimensions Used for Calculations
var handleHalfWidth = 0,
barWidth = 0,
minOffset = 0,
maxOffset = 0,
minValue = 0,
maxValue = 0,
valueRange = 0,
offsetRange = 0,
bubbleTop = undefined,
bubbleHeight = undefined,
handleTop = undefined,
handleHeight = undefined;
if (scope.step === undefined) scope.step = 10;
if (scope.floor === undefined) scope.floor = 0;
if (scope.ceiling === undefined) scope.ceiling = 500;
if (scope.precision === undefined) scope.precision = 2;
if (scope.bubbles === undefined) scope.bubbles = false;
var bindingsSet = false;
var updateCalculations = function() {
scope.floor = roundStep(parseFloat(scope.floor), parseInt(scope.precision), parseFloat(scope.step), parseFloat(scope.floor));
scope.ceiling = roundStep(parseFloat(scope.ceiling), parseInt(scope.precision), parseFloat(scope.step), parseFloat(scope.floor));
angular.forEach(scope.sliders, function(slider) {
slider.value = roundStep(parseFloat(slider.value), parseInt(scope.precision), parseFloat(scope.step), parseFloat(scope.floor));
});
handleHalfWidth = handles[0][0].offsetWidth / 2;
barWidth = bar[0].offsetWidth;
minOffset = 0;
maxOffset = barWidth - handles[0][0].offsetWidth;
minValue = parseFloat(scope.floor);
maxValue = parseFloat(scope.ceiling);
valueRange = maxValue - minValue;
offsetRange = maxOffset - minOffset;
};
var updateDOM = function () {
updateCalculations();
var percentOffset = function (offset) {
return contain(((offset - minOffset) / offsetRange) * 100);
};
var percentValue = function (value) {
return contain(((value - minValue) / valueRange) * 100);
};
var pixelsToOffset = function (percent) {
return pixelize(percent * offsetRange / 100);
};
var setHandles = function () {
offset(ceilBubble, pixelize(barWidth - ceilBubble[0].offsetWidth));
angular.forEach(scope.sliders, function(slider,key){
if (slider.color) {
handles[key].css({'background-color': slider.color});
}
if (slider.value >= minValue && slider.value <= maxValue) {
offset(handles[key], pixelsToOffset(percentValue(slider.value)));
offset(bubbles[key], pixelize(handles[key][0].offsetLeft - (bubbles[key][0].offsetWidth / 2) + handleHalfWidth));
handles[key].css({'display': 'block'});
if ('' + scope.bubbles === 'true') {
bubbles[key].css({'display': 'block'});
}
} else {
handles[key].css({'display': 'none'});
bubbles[key].css({'display': 'none'});
}
if (slider.hasOwnProperty("visible") && slider.visible === false) {
handles[key].css({'display': 'none'});
bubbles[key].css({'display': 'none'});
}
if (slider.hasOwnProperty("enabled") && slider.enabled === false) {
handles[key].addClass('disabled');
bubbles[key].addClass('disabled');
} else {
handles[key].removeClass('disabled');
bubbles[key].removeClass('disabled');
}
});
};
var resetBubbles = function() {
if (scope.sliders.length > 1) {
//timeout must be longer than css animation for proper bubble collision detection
for (var i = 0; i < scope.sliders.length; i++) {
(function (index) {
setTimeout(function () {
overlapCheck(index);
}, i * 150);
})(i);
}
}
};
var overlapCheck = function(currentRef) {
var safeAtLevel = function(cRef, level) {
for (var x = 0; x < scope.sliders.length; x++) {
if (x != cRef && overlaps(bubbles[cRef][0], bubbles[x][0], (bubbleTop * level))) {
return safeAtLevel(cRef, level + 1);
}
}
return level;
};
if (scope.sliders.length > 1) {
var safeLevel = safeAtLevel(currentRef, 1) - 1;
handles[currentRef].css({top: pixelize((-1 * (safeLevel * bubbleHeight)) + handleTop), height: pixelize(handleHeight + (bubbleHeight * safeLevel)), 'z-index': 99-safeLevel});
bubbles[currentRef].css({top: pixelize(bubbleTop - (bubbleHeight * safeLevel))});
}
};
var bind = function (handle, bubble, currentRef, events) {
var onEnd = function () {
handle.removeClass('grab');
bubble.removeClass('grab');
if (!(''+scope.bubbles === 'true')) {
bubble.removeClass('active');
}
ngDocument.unbind(events.move);
ngDocument.unbind(events.end);
if (angular.equals(scope.sliders, original)) {
ngModel.$setPristine();
}
//Move possible elevated bubbles back down if one below it moved.
resetBubbles();
scope.$apply();
};
var onMove = function (event) {
// Suss out which event type we are capturing and get the x value
var eventX = 0;
if (event.clientX !== undefined) {
eventX = event.clientX;
}
else if ( event.touches !== undefined && event.touches.length) {
eventX = event.touches[0].clientX;
}
else if ( event.originalEvent !== undefined &&
event.originalEvent.changedTouches !== undefined &&
event.originalEvent.changedTouches.length) {
eventX = event.originalEvent.changedTouches[0].clientX;
}
var newOffset = Math.max(Math.min((eventX - element[0].getBoundingClientRect().left - handleHalfWidth), maxOffset), minOffset),
newPercent = percentOffset(newOffset),
newValue = minValue + (valueRange * newPercent / 100.0);
newValue = roundStep(newValue, parseInt(scope.precision), parseFloat(scope.step), parseFloat(scope.floor));
scope.sliders[currentRef].value = newValue;
setHandles();
overlapCheck(currentRef);
ngModel.$setDirty();
scope.$apply();
};
var onStart = function (event) {
if (scope.sliders[currentRef].hasOwnProperty("enabled") && scope.sliders[currentRef].enabled === false) {
bubble.addClass('disabled');
handle.addClass('disabled');
return;
}
updateCalculations();
bubble.addClass('active grab');
handle.addClass('active grab');
setHandles();
event.stopPropagation();
event.preventDefault();
ngDocument.bind(events.move, onMove);
return ngDocument.bind(events.end, onEnd);
};
handle.bind(events.start, onStart);
};
var setBindings = function () {
var method, i;
var inputTypes = ['touch', 'mouse'];
for (i = 0; i < inputTypes.length; i++) {
method = inputTypes[i];
angular.forEach(scope.sliders, function(slider, key){
bind(handles[key], bubbles[key], key, events[method]);
if (scope.sliders[key].hasOwnProperty("enabled") && scope.sliders[key].enabled === false) {
handles[key].addClass('disabled');
bubbles[key].addClass('disabled');
}
});
}
bindingsSet = true;
};
if (!bindingsSet) {
setBindings();
// Timeout needed because bubbles offsetWidth is incorrect during initial rendering of html elements
setTimeout( function() {
if ('' + scope.bubbles === 'true') {
angular.forEach(bubbles, function (bubble) {
bubble.addClass('active');
});
}
updateCalculations();
setHandles();
//Get Default sizes of bubbles and handles, assuming each are equal, calculated from css
handleTop = handleTop === undefined ? handles[0][0].offsetTop : handleTop;
handleHeight = handleHeight === undefined ? handles[0][0].offsetHeight : handleHeight;
bubbleTop = bubbleTop === undefined ? bubbles[0][0].offsetTop : bubbleTop;
bubbleHeight = bubbleHeight === undefined ? bubbles[0][0].offsetHeight + 7 : bubbleHeight ; //add 7px bottom margin to the bubble offset for handle
resetBubbles();
}, 10);
}
};
// Watch Models based on mode
scope.$watch('sliders', function(oldValue, newValue) {
console.log('sliders Update: ', oldValue, ' : ', newValue);
updateDOM();
});
scope.$watch('ceiling', function() {
bindingsSet = false;
updateDOM();
});
scope.$watch('floor', function() {
bindingsSet = false;
updateDOM();
});
// Update on Window resize
window.addEventListener('resize', updateDOM);
}
}
});
答案 0 :(得分:0)
我在这里找到了解决方案:How to deep watch an array in angularjs?深表/财产观察。
$scope.$watch('columns', function() {
// some value in the array has changed
}, true); // watching properties