Javascript 如何使其他指令在uib选项卡元素中工作
在呈现选项卡后,是否可以使用uib选项卡指令的回调函数刷新内部指令? 我试图找到第三方指令问题的根源,当我在angular bootstrap提供的uib tab指令中使用该指令时,会出现该指令。第三方指令已发布,该问题于年首次报告 一个用例是可用的。单击第二个选项卡,您将看到内部滑块的所有控制柄都位于其他控制柄之上(即宽度=0px)。然后单击其中一个控制柄,它将正确显示。即使在遵循您关于中作用域的建议后,该问题仍然存在 角度应用程序Javascript 如何使其他指令在uib选项卡元素中工作,javascript,angularjs,angularjs-bootstrap,Javascript,Angularjs,Angularjs Bootstrap,在呈现选项卡后,是否可以使用uib选项卡指令的回调函数刷新内部指令? 我试图找到第三方指令问题的根源,当我在angular bootstrap提供的uib tab指令中使用该指令时,会出现该指令。第三方指令已发布,该问题于年首次报告 一个用例是可用的。单击第二个选项卡,您将看到内部滑块的所有控制柄都位于其他控制柄之上(即宽度=0px)。然后单击其中一个控制柄,它将正确显示。即使在遵循您关于中作用域的建议后,该问题仍然存在 角度应用程序 'use strict'; angular.module(
'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>
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);
}
}
});
“严格使用”;
angular.module('angularMultiSlider',[])
.directive('multiSlider',函数($compile,$timeout){
var事件={
鼠标:{
开始:“mousedown”,
移动:“鼠标移动”,
结束:“鼠标”
},
触摸:{
开始:“touchstart”,
移动:“触摸移动”,
结束:'触摸结束'
}
};
函数roundStep(值、精度、步长、楼层){
var余数=(值-下限)%步长;
var STEPDVALUE=余数>(步骤/2)?
值+步长-余数:值-余数;
var小数=数学功率(10,精度);
var roundedValue=步进值*小数/小数;
返回parseFloat(roundedValue.toFixed(precision));
}
功能偏移(元素、位置){
返回元素.css({
左:位置
});
}
函数像素化(位置){
返回parseInt(位置)+“px”;
}
函数包含(值){
if(isNaN(value))返回值;
返回Math.min(Math.max(0,值),100);
}
返回{
限制:“EA”,
要求:“?ngModel”,
范围:{
楼层:“@”,
上限:“@”,
步骤:“@”,
精度:'@',
气泡:“@”,
滑块:'=ngModel'
},
模板:
'' +
“{{floor}}”+
“{{天花板}}”,
链接:功能(范围、元素、属性、模型){
if(!ngModel)return;//如果没有ng模型,则不执行任何操作
//基本副本以查看滑块是否返回到原始状态
原始变量;
ngModel.$render=function(){
原始=角度复制(范围滑块);
};
addClass('angular-multi-slider');
//DOM组件
var sliderStr='';
angular.forEach(scope.sliders,函数(slider,key){
滑块TR+=('
{{滑块['+key.toString()
+'].title}{{sliders['+key.toString()
+'].value}
');
});
var sliderControls=angular.element(sliderStr);
元素。追加(滑块控件);
$compile(幻灯片控件)(范围);
var children=element.children();
var bar=angular.element(子元素[0]),
ngDocument=角度元素(文档),
floorBubble=角度元素(子元素[1]),
Ceilubble=angular.element(子元素[2]),
气泡=[],
句柄=[];
//var sliderChildren=sliderControls.children();
angular.forEach(scope.sliders,函数(slider,key){
手柄。推(角度元素(子项[(键*2)+3]);
气泡推(角度元素(子元素[(键*2)+4]);
});
//用于计算的控制尺寸
var handleHalfWidth=0,
条形宽度=0,
minOffset=0,
maxOffset=0,
最小值=0,
maxValue=0,
valueRange=0,
偏移范围=0;
如果(scope.step==未定义)scope.step=1;
如果(scope.floor==未定义)scope.floor=0;
如果(scope.天花==未定义)scope.天花=500;
如果(scope.precision==未定义)scope.precision=0;
如果(scope.bubbles==未定义)scope.bubbles=false;
var bindingsSet=false;
var updateCalculations=函数(){
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,函数(slider)){
slider.value=roundStep(parseFloat(slider.value)、parseInt(scope.precision),
parseFloat(scope.step),parseFloat(scope.floor));
});
handleHalfWidth=句柄[0][0]。偏移网络宽度/2;
barWidth=bar[0]。偏移网络宽度;
最小偏移=0;
maxOffset=barWidth-句柄[0][0]。offsetWidth;
minValue=parseFloat(范围楼层);
maxValue=parseFloat(范围上限);
valueRange=最大值-最小值;
偏移量范围=最大偏移量-最小偏移量;
};
var updateDOM=函数(){
更新计算();
var percentOffset=函数(偏移){
返回包含(((偏移-最小偏移)/偏移范围)*100);
};
var percentValue=函数(值){
返回包含(((值-最小值)/值范围)*100);
};
var pixelsToOffset=函数(百分比){
返回像素化(百分比*偏移范围/100);
};
var setHandles=函数(){
偏移量(ceilBubble,像素化(barWidth-ceilBubble[0].offsetWidth));
angular.forEach(scope.sliders,函数(slider,key){
如果(滑块颜色){
句柄[key].css({“background color”:slider.color});
}
偏移量(句柄[键],
像素偏移(百分比值(slider.value));
偏移量(气泡[键],
像素化(句柄[key][0]。偏移左侧
'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);
}
}
});
<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];