如何让其他指令在 uib-tab 元素中工作
How to make other directives work inside uib-tab elements
是否有 uib-tab 指令的回调函数,我可以在呈现选项卡后使用它来刷新内部指令?
我试图找到当我在 angular-bootstrap 提供的 uib-tab 指令中使用该指令时出现的第三方指令问题的根源。第三方指令是angular-multi-slider and the issue was first reported in that repository。
一个用例可用 in plnkr. Click on the second tab, and you will see that the inner slider has all its handles one on top of the others (i.e., widths=0px). Then click on one of the handles and it will appear correctly. The issue persists even after following your recommendation regarding scopes in the FAQ。
Angular 应用程序
'use strict';
angular.module('multiSliderDemo', ['angularMultiSlider', 'ngAnimate', 'ui.bootstrap']);
angular.module('multiSliderDemo')
.controller('DemoCtrl', function ($rootScope, $scope, $sce, $uibModal) {
var s = [
{value: 2, title:"Brainstorming", component: "Proposal Making",
symbol: $sce.trustAsHtml("1")},
{value: 50, title:"Working groups formation", component: "Proposal Making",
symbol: $sce.trustAsHtml("2")},
{value: 100, title:"Proposal drafting",component:"Proposal Making",
symbol: $sce.trustAsHtml("3")},
{value: 130, title:"Proposal editing", component: "Versioning",
symbol: $sce.trustAsHtml("4")},
{value: 160, title:"Proposal selection", component: "Versioning",
symbol: $sce.trustAsHtml("5")},
{value: 200, title:"Discussion of proposals", component: "Deliberation",
symbol: $sce.trustAsHtml("6")},
{value: 250, title:"Technical assessment", component: "Deliberation",
symbol: $sce.trustAsHtml("7")},
{value: 300, title:"Voting on proposals", component: "Voting",
symbol: $sce.trustAsHtml("8")}
];
$scope.app = {sliders:s}
});
index.html
<html ng-app="multiSliderDemo">
<head>
<meta charset="UTF-8">
<title>Multi Slider</title>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="multislider.css">
</head>
<body>
<div ng-controller="DemoCtrl" class="container">
<article>
<h2>Multi-Slider Issue with uib-tabs</h2>
<form name="sliderForm" id="sliderForm" novalidate autocomplete="off">
<fieldset class="row">
<uib-tabset>
<uib-tab heading="Tab 1" active="true">
<multi-slider name="mySlider"
floor="0"
step="1"
precision="2"
ceiling="365"
bubbles="true"
ng-model="app.sliders">
</multi-slider>
</uib-tab>
<uib-tab heading="Tab 2" active="false">
<section class="col-sm-6 padding-10">
<multi-slider name="mySlider"
floor="0"
step="1"
precision="2"
ceiling="365"
bubbles="true"
ng-model="app.sliders">
</multi-slider>
</section>
</uib-tab>
</uib-tabset>
</fieldset>
</form>
</article>
</div>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular-animate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.14.3/ui-bootstrap-tpls.min.js"></script>
<script src="multislider.js"></script>
<script src="script.js"></script>
</body>
</html>
CSS
.angular-multi-slider {
display: inline-block;
position: relative;
height: 5px;
width: 100%;
margin: 25px 5px 25px 5px;
vertical-align: middle;
}
.angular-multi-slider div {
white-space: nowrap;
position: absolute;
}
.angular-multi-slider div.bar {
width: 100%;
height: 100%;
border-radius: 6px;
background: #999;
overflow: hidden;
}
.angular-multi-slider div.handle {
cursor: pointer;
width: 10px;
height: 30px;
top: -15px;
background-color: #13b6ff; /*can override with color in slider object*/
border: 2px solid #000;
z-index: 2;
border-radius: 4px;
-o-transition: .3s;
-ms-transition: .3s;
-moz-transition: .3s;
-webkit-transition: .3s;
-webkit-transition-property: background-color;
transition-property: background-color;
}
.angular-multi-slider div.handle:hover,
.angular-multi-slider div.handle:focus,
.angular-multi-slider div.handle:active,
.angular-multi-slider div.handle.active {
-webkit-filter: brightness(70%);
filter: brightness(70%);
}
.angular-multi-slider div.handle:hover + .bubble,
.angular-multi-slider div.handle:focus + .bubble,
.angular-multi-slider div.handle.grab + .bubble,
.angular-multi-slider div.handle:hover,
.angular-multi-slider div.handle:focus,
.angular-multi-slider div.handle.grab {
-webkit-transform: scale(1.1);
transform: scale(1.1);
z-index: 9999;
}
.angular-multi-slider div.handle.grab + .bubble,
.angular-multi-slider div.handle.grab{
background-color: rgba(0,0,0,1);
}
.angular-multi-slider div.bubble {
display: none;
cursor: default;
top: -36px;
padding: 1px 3px 1px 3px;
font-size: 0.7em;
font-family: sans-serif;
-o-transition: .1s;
-ms-transition: .1s;
-moz-transition: .1s;
-webkit-transition: .1s;
-webkit-transition-property: top;
transition-property: top;
}
.angular-multi-slider div.bubble:nth-child(2) {
top: 34px !important;
z-index:9999;
}
.angular-multi-slider div.bubble.active {
display: inline-block;
color: #fff;
font-size:12px;
font-family: 'Arial', sans-serif;
text-align: center;
background-color: rgba(0,0,0,0.75);
border-radius: 8px;
padding: 3px 8px;
}
.angular-multi-slider div.limit {
margin-top: 12px;
color: #000;
font-weight: bold;
}
Multislider.js
'use strict';
angular.module('angularMultiSlider', [])
.directive('multiSlider', function($compile, $timeout) {
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);
}
return {
restrict: 'EA',
require: '?ngModel',
scope: {
floor : '@',
ceiling : '@',
step : '@',
precision : '@',
bubbles : '@',
sliders : '=ngModel'
},
template :
'<div class="bar"></div>' +
'<div class="limit floor">{{ floor }}</div>' +
'<div class="limit ceiling">{{ ceiling }}</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
var sliderStr = '';
angular.forEach(scope.sliders, function(slider, key){
sliderStr += ('<div class="handle">
</div>
<div class="bubble">{{ sliders[' + key.toString()
+ '].title }}{{ sliders[' + key.toString()
+ '].value}}
</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 = [];
//var sliderChildren = sliderControls.children();
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;
if (scope.step === undefined) scope.step = 1;
if (scope.floor === undefined) scope.floor = 0;
if (scope.ceiling === undefined) scope.ceiling = 500;
if (scope.precision === undefined) scope.precision = 0;
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 });
}
offset( handles[key],
pixelsToOffset(percentValue(slider.value)));
offset( bubbles[key],
pixelize(handles[key][0].offsetLeft
- (bubbles[key][0].offsetWidth / 2) + handleHalfWidth));
});
};
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();
}
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();
ngModel.$setDirty();
scope.$apply();
};
var onStart = function (event) {
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]);
});
}
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');
});
}
//added this for tab 1...
updateCalculations();
setHandles();
}, 1);
}
};
// Watch Models based on mode
scope.$watch('sliders', updateDOM);
// Update on Window resize
window.addEventListener('resize', updateDOM);
}
}
});
备注:
我使用的AngularJS版本是1.4.7。 angular-bootstrap的版本是0.14.3。 angular-multi-slider的版本是0.1.1
我已经看了这个一个多小时了,尝试了很多不同的东西,其中 none 已经奏效了。责怪第三方库很容易,但我怀疑这也是由于选项卡的呈现方式(即通过 replace: true
)造成的。您的问题不是我们遇到的第一个用户遇到选项卡内容问题的问题。我们需要为选项卡内容提出最佳做法 - 特别是当用户在内容中放置复杂指令时。
问题是第二个选项卡上的滑块正在渲染并在选项卡内容区域之前点击 multislider.js - updateCaclulations(或计算滑块手柄之间的 space 的任何函数)函数是可见的。所以没有父 space 来计算。 plunk 演示了如何使用 ng-if 仅在选项卡处于活动状态时呈现多滑块。因为 SO 不会让你 post 一个没有代码的答案,这里是:
<uib-tabset>
<uib-tab heading="Tab 1" active="activeTabs[0]">
<multi-slider name="mySlider"
floor="0"
step="1"
precision="2"
ceiling="365"
bubbles="true"
ng-model="app.sliders"
ng-if="activeTabs[0]">
</multi-slider>
</uib-tab>
<uib-tab heading="Tab 2" active="activeTabs[1]">
<section class="col-sm-6 padding-10">
<multi-slider name="mySlider"
floor="0"
step="1"
precision="2"
ceiling="365"
bubbles="true"
ng-model="app.sliders"
ng-if="activeTabs[1]">
</multi-slider>
</section>
</uib-tab>
</uib-tabset>
控制器:
$scope.activeTabs = [true, false];
是否有 uib-tab 指令的回调函数,我可以在呈现选项卡后使用它来刷新内部指令?
我试图找到当我在 angular-bootstrap 提供的 uib-tab 指令中使用该指令时出现的第三方指令问题的根源。第三方指令是angular-multi-slider and the issue was first reported in that repository。
一个用例可用 in plnkr. Click on the second tab, and you will see that the inner slider has all its handles one on top of the others (i.e., widths=0px). Then click on one of the handles and it will appear correctly. The issue persists even after following your recommendation regarding scopes in the FAQ。
Angular 应用程序
'use strict';
angular.module('multiSliderDemo', ['angularMultiSlider', 'ngAnimate', 'ui.bootstrap']);
angular.module('multiSliderDemo')
.controller('DemoCtrl', function ($rootScope, $scope, $sce, $uibModal) {
var s = [
{value: 2, title:"Brainstorming", component: "Proposal Making",
symbol: $sce.trustAsHtml("1")},
{value: 50, title:"Working groups formation", component: "Proposal Making",
symbol: $sce.trustAsHtml("2")},
{value: 100, title:"Proposal drafting",component:"Proposal Making",
symbol: $sce.trustAsHtml("3")},
{value: 130, title:"Proposal editing", component: "Versioning",
symbol: $sce.trustAsHtml("4")},
{value: 160, title:"Proposal selection", component: "Versioning",
symbol: $sce.trustAsHtml("5")},
{value: 200, title:"Discussion of proposals", component: "Deliberation",
symbol: $sce.trustAsHtml("6")},
{value: 250, title:"Technical assessment", component: "Deliberation",
symbol: $sce.trustAsHtml("7")},
{value: 300, title:"Voting on proposals", component: "Voting",
symbol: $sce.trustAsHtml("8")}
];
$scope.app = {sliders:s}
});
index.html
<html ng-app="multiSliderDemo">
<head>
<meta charset="UTF-8">
<title>Multi Slider</title>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="multislider.css">
</head>
<body>
<div ng-controller="DemoCtrl" class="container">
<article>
<h2>Multi-Slider Issue with uib-tabs</h2>
<form name="sliderForm" id="sliderForm" novalidate autocomplete="off">
<fieldset class="row">
<uib-tabset>
<uib-tab heading="Tab 1" active="true">
<multi-slider name="mySlider"
floor="0"
step="1"
precision="2"
ceiling="365"
bubbles="true"
ng-model="app.sliders">
</multi-slider>
</uib-tab>
<uib-tab heading="Tab 2" active="false">
<section class="col-sm-6 padding-10">
<multi-slider name="mySlider"
floor="0"
step="1"
precision="2"
ceiling="365"
bubbles="true"
ng-model="app.sliders">
</multi-slider>
</section>
</uib-tab>
</uib-tabset>
</fieldset>
</form>
</article>
</div>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular-animate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.14.3/ui-bootstrap-tpls.min.js"></script>
<script src="multislider.js"></script>
<script src="script.js"></script>
</body>
</html>
CSS
.angular-multi-slider {
display: inline-block;
position: relative;
height: 5px;
width: 100%;
margin: 25px 5px 25px 5px;
vertical-align: middle;
}
.angular-multi-slider div {
white-space: nowrap;
position: absolute;
}
.angular-multi-slider div.bar {
width: 100%;
height: 100%;
border-radius: 6px;
background: #999;
overflow: hidden;
}
.angular-multi-slider div.handle {
cursor: pointer;
width: 10px;
height: 30px;
top: -15px;
background-color: #13b6ff; /*can override with color in slider object*/
border: 2px solid #000;
z-index: 2;
border-radius: 4px;
-o-transition: .3s;
-ms-transition: .3s;
-moz-transition: .3s;
-webkit-transition: .3s;
-webkit-transition-property: background-color;
transition-property: background-color;
}
.angular-multi-slider div.handle:hover,
.angular-multi-slider div.handle:focus,
.angular-multi-slider div.handle:active,
.angular-multi-slider div.handle.active {
-webkit-filter: brightness(70%);
filter: brightness(70%);
}
.angular-multi-slider div.handle:hover + .bubble,
.angular-multi-slider div.handle:focus + .bubble,
.angular-multi-slider div.handle.grab + .bubble,
.angular-multi-slider div.handle:hover,
.angular-multi-slider div.handle:focus,
.angular-multi-slider div.handle.grab {
-webkit-transform: scale(1.1);
transform: scale(1.1);
z-index: 9999;
}
.angular-multi-slider div.handle.grab + .bubble,
.angular-multi-slider div.handle.grab{
background-color: rgba(0,0,0,1);
}
.angular-multi-slider div.bubble {
display: none;
cursor: default;
top: -36px;
padding: 1px 3px 1px 3px;
font-size: 0.7em;
font-family: sans-serif;
-o-transition: .1s;
-ms-transition: .1s;
-moz-transition: .1s;
-webkit-transition: .1s;
-webkit-transition-property: top;
transition-property: top;
}
.angular-multi-slider div.bubble:nth-child(2) {
top: 34px !important;
z-index:9999;
}
.angular-multi-slider div.bubble.active {
display: inline-block;
color: #fff;
font-size:12px;
font-family: 'Arial', sans-serif;
text-align: center;
background-color: rgba(0,0,0,0.75);
border-radius: 8px;
padding: 3px 8px;
}
.angular-multi-slider div.limit {
margin-top: 12px;
color: #000;
font-weight: bold;
}
Multislider.js
'use strict';
angular.module('angularMultiSlider', [])
.directive('multiSlider', function($compile, $timeout) {
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);
}
return {
restrict: 'EA',
require: '?ngModel',
scope: {
floor : '@',
ceiling : '@',
step : '@',
precision : '@',
bubbles : '@',
sliders : '=ngModel'
},
template :
'<div class="bar"></div>' +
'<div class="limit floor">{{ floor }}</div>' +
'<div class="limit ceiling">{{ ceiling }}</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
var sliderStr = '';
angular.forEach(scope.sliders, function(slider, key){
sliderStr += ('<div class="handle">
</div>
<div class="bubble">{{ sliders[' + key.toString()
+ '].title }}{{ sliders[' + key.toString()
+ '].value}}
</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 = [];
//var sliderChildren = sliderControls.children();
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;
if (scope.step === undefined) scope.step = 1;
if (scope.floor === undefined) scope.floor = 0;
if (scope.ceiling === undefined) scope.ceiling = 500;
if (scope.precision === undefined) scope.precision = 0;
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 });
}
offset( handles[key],
pixelsToOffset(percentValue(slider.value)));
offset( bubbles[key],
pixelize(handles[key][0].offsetLeft
- (bubbles[key][0].offsetWidth / 2) + handleHalfWidth));
});
};
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();
}
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();
ngModel.$setDirty();
scope.$apply();
};
var onStart = function (event) {
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]);
});
}
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');
});
}
//added this for tab 1...
updateCalculations();
setHandles();
}, 1);
}
};
// Watch Models based on mode
scope.$watch('sliders', updateDOM);
// Update on Window resize
window.addEventListener('resize', updateDOM);
}
}
});
备注: 我使用的AngularJS版本是1.4.7。 angular-bootstrap的版本是0.14.3。 angular-multi-slider的版本是0.1.1
我已经看了这个一个多小时了,尝试了很多不同的东西,其中 none 已经奏效了。责怪第三方库很容易,但我怀疑这也是由于选项卡的呈现方式(即通过 replace: true
)造成的。您的问题不是我们遇到的第一个用户遇到选项卡内容问题的问题。我们需要为选项卡内容提出最佳做法 - 特别是当用户在内容中放置复杂指令时。
问题是第二个选项卡上的滑块正在渲染并在选项卡内容区域之前点击 multislider.js - updateCaclulations(或计算滑块手柄之间的 space 的任何函数)函数是可见的。所以没有父 space 来计算。 plunk 演示了如何使用 ng-if 仅在选项卡处于活动状态时呈现多滑块。因为 SO 不会让你 post 一个没有代码的答案,这里是:
<uib-tabset>
<uib-tab heading="Tab 1" active="activeTabs[0]">
<multi-slider name="mySlider"
floor="0"
step="1"
precision="2"
ceiling="365"
bubbles="true"
ng-model="app.sliders"
ng-if="activeTabs[0]">
</multi-slider>
</uib-tab>
<uib-tab heading="Tab 2" active="activeTabs[1]">
<section class="col-sm-6 padding-10">
<multi-slider name="mySlider"
floor="0"
step="1"
precision="2"
ceiling="365"
bubbles="true"
ng-model="app.sliders"
ng-if="activeTabs[1]">
</multi-slider>
</section>
</uib-tab>
</uib-tabset>
控制器:
$scope.activeTabs = [true, false];