【发布时间】:2015-04-09 05:21:27
【问题描述】:
我创建了一个自定义指令来呈现问题的滑块(本质上是包装 jquery ui 滑块)。该指令接受一个 ngModel 并在用户使用滑块时更新它,并且有一个 $watch 附加到父模型(传递给指令的 ngModel 只是父模型的一部分)。该指令在一个页面上有多个实例。
我遇到了手表问题,因为手表似乎总是出现在页面上的最后一个问题上。因此,例如一个有 10 个问题的页面,使用问题 1 上的滑块 - 触发最后一个问题(问题 10)的手表。我认为该问题与指令/隔离范围和/或监视功能有关,但我无法解决。
this.app.directive('questionslider', () => {
var onChangeEvent = (event, ui) => {
updateModel(ui.value);
};
var onSlideEvent = (event, ui) => {
updateUi(event, ui);
};
var updateUi = (event, ui) => {
$(ui.handle).find(".ff-handle-glyph > div").css("top", (ui.value) * - 10);
}
var updateModel = (newValue) => {
// find value in values list...
angular.forEach(isolatedScope.model.PossibleValues, function(value) {
if (parseInt(value.Name) === newValue) {
isolatedScope.$apply(function() {
isolatedScope.model.Value = value;
});
}
});
};
var isolatedScope: any;
return {
restrict: 'AE',
replace: true,
template: '<div></div>',
scope: {
model: '=ngModel',
},
link: function(scope, element, attrs, ctrl) {
isolatedScope = scope;
scope.$watch(ngModelCtrl, function() {
// use provided defaultValue if model is empty
var value = isolatedScope.model.Value === null ? isolatedScope.model.DefaultValue : isolatedScope.model.Value;
element.slider({
min: 0,
max: isolatedScope.model.PossibleValues.length,
value: value.Name,
change: onChangeEvent,
slide: onSlideEvent
});
}
}
};
};
在控制器中添加手表的代码
this.$scope.questions.forEach(function(question) {
this.$scope.$watch(
function() { return question; },
function(newVal, oldVal) { this.updateQuestion(newVal, oldVal) },
true
);
});
UpdateQuestion 函数(现在只是输出当前问题)
function updateQuestion(newVal, oldVal) {
// prevent event on initial load
if (newVal === oldVal) {
return;
}
console.log(newVal);
}
ng-repeat 标记实例化问题滑块
<div data-ng-repeat="question in Questions">
<h4>{{question.QuestionText}}</h4>
<p>{{question.RangeMinText}}</p>
<questionslider ng-model="question"></questionslider>
<p>{{question.RangeMaxText}}</p>
</div>
问题 JSON 看起来像这样
{
"DefaultValue": {
"Id": "5",
"Name": "5"
},
"Id": "1",
"IsAnswered": false,
"PossibleValues": [
{
"Id": "1",
"Name": "1"
},
{
"Id": "2",
"Name": "2"
},
{
"Id": "3",
"Name": "3"
},
{
"Id": "4",
"Name": "4"
},
{
"Id": "5",
"Name": "5"
},
{
"Id": "6",
"Name": "6"
},
{
"Id": "7",
"Name": "7"
},
{
"Id": "8",
"Name": "8"
},
{
"Id": "9",
"Name": "9"
},
{
"Id": "10",
"Name": "10"
}
],
"QuestionText": "hows it haning?",
"RangeMaxText": "not good",
"RangeMinText": "Very good",
"Type": 0,
"Value": null
}
],
"Title": "Question title",
"Type": 0
}
所以问题是,无论我使用滑块指令更新哪个问题,它始终是传递给 updateQuestion 的最后一个页面。
更新 我尝试使用 $watchCollection,但似乎没有触发该事件。
this.$scope.$watchCollection(
'questions',
function (newVal, oldVal) {
// prevent event on initial load
if (newVal === oldVal) {
return;
}
for (var i = 0; i < newVal.length; i++) {
if (newVal[i] != oldVal[i]) {
this.$log.info("update : " + newVal.Id);
}
}
}
);
我也试过
function() { return questions; }
作为第一个表达式。还是没有运气。
也许对每个问题使用单独的控制器是我唯一的选择,但这似乎是一种解决方法。
更新 所以我尝试为每个问题使用单独的控制器,在控制器中为每个问题添加一个手表,奇怪的是,即使这样也重现了相同的场景。它仍然是页面上传递给 watch 函数的最后一个问题。
标记
<div data-ng-repeat="question in Questions" data-ng-controller="QuestionInstanceController">
<h4>{{question.QuestionText}}</h4>
<p>{{question.RangeMinText}}</p>
<questionslider ng-model="question"></questionslider>
<p>{{question.RangeMaxText}}</p>
</div>
控制器代码
app.controller('QuestionInstanceController', function($scope) {
console.log($scope.question); // outputs correct question here!
$scope.$watch(
function() { return $scope.question; },
function(newValue, oldValue) {
console.log(newValue); // always outputs last question on page
},
true);
}
}
这一定与我的自定义指令有关,当页面上有多个实例时,我是否会以某种方式覆盖以前的实例?
【问题讨论】:
-
你能从 HTML 视图中放一些示例吗?
-
我还建议在指令的隔离范围“ngModel”中命名一个值的形式很差,而且令人困惑。
-
嗨迈克尔,我添加了标记。我认为 ngModel 是这种类型的最佳实践,因为它正在更新,但这并不是因为它是一个孤立的范围,对吗?
-
我说的是在您的指令中将“范围:{ngModel:'='}”命名为 ngModel。还有“scope.ngModel.Value === null”。您正在使用 ngModel 作为范围变量的名称。不过,您应该在视图中使用 ng-model 指令。我会尽力为你解决这个问题。
-
TypeScript 不够清晰,我无法理解。我不知道你在 $watch 里做什么。我真的无法提供进一步的帮助,因为这不在 Javascript 中,而且我怀疑你的代码中我无法识别的东西是罪魁祸首。对不起。
标签: angularjs angularjs-directive angular-ngmodel