ng-click 事件触发多次
ng-click event triggered multiple times
我有一个模板,可重复用于显示具有不同数据的行。该模板还包含与该行相关的 $scope
函数。
<script id="wineRowTemplateT" type="text/html" style="display: none;">
<div class="row tasting" style="margin-bottom: 15px;">
<div class="col col-10">
<div class="rating" style="display: block; width: 60px; height: 60px; text-align: center; line-height: 60px; font-weight: 700; border: thin solid #ccc; border-radius: 50%; font-size: 1.2em;">{tasting_points}p</div>
</div>
<div class="col col-90">
<div class="row info">
<div class="col col-70">
<h3 style="font-weight: 300; border-bottom: thin solid #000; display: inline-block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
<span ng-click="smGoto('http://dev.thetastingbook.com/p/{house_url}', 'external')" style="font-weight: 600;">{house_name}</span>
<span ng-click="smGoto('http://dev.thetastingbook.com/wine/{house_url}/{wine_url}', 'external')">{wine_name}</span> {wine_vintage}
</h3>
</div>
<div class="col col-30">
<h4 ng-click="showTastingAdjectivesModal($event)" data-tasting-id="{tasting_id}" data-wine-id="{wine_id}" style="font-weight: 300; text-transform: uppercase; text-decoration: underline;">Show tasting note</h4>
</div>
</div>
</div>
</div>
</script>
有问题的函数是 showTastingAdjectivesModal()
在我的测试用例中,我从模板创建了六行。当我尝试点击其中一行中的 Show Tasting Note 时,它会触发六次。 tastingId 和 wineId 来自正确的行,只是它们都被触发了多次(六次),我不知道是什么原因造成的。
这是我的 showTastingAdjectivesModal() 函数:
$scope.showTastingAdjectivesModal = function (cEvent) {
console.log("showNoteModal called");
var $this = $(cEvent.toElement);
var tastingId = $this.data("tastingId");
var wineId = $this.data("wineId");
Tasting.getTastedWineAdjectives(tastingId, wineId)
.then(function(adjectives){
console.log("Got adjectives", JSON.stringify(adjectives));
adjectives.forEach(function(adj){
var type = adj.type;
if(type == "drink")
type = "conclusion";
$(".tasting-adjective-row[data-type='"+type+"']").find(".adjectives").append(adj.name + ", ");
});
$scope.noteModal.show();
});
};
我手上的 console.log
每次点击它都会打印 6 次。
附带说明一下,此代码是 运行 在 iOS 设备上使用带有 Ionic/AngularJS 的 Cordova。
谁能告诉我哪里做错了?
模板的用法如下:
var res = obj.res;
var stats = obj.stats;
section = {abbr: "", proper: ""};
tastingDate = moment(tasting.tasting_date);
if (tastingDate.isAfter(moment().startOf("isoweek")) || tastingDate.isSame(moment().startOf("isoweek"))) {
section.abbr = "week";
section.proper = "This Week";
} else if (tastingDate.isAfter(moment().subtract(1, "weeks").startOf("isoweek")) || tastingDate.isSame(moment().subtract(1, "weeks").startOf("isoweek"))) {
section.abbr = "lastweek";
section.proper = "Last Week";
} else {
section.abbr = tastingDate.format("W");
section.proper = "Week " + tastingDate.format("W");
}
var wineRowTemplate = $("#wineRowTemplateT").html();
wineRowTemplate = wineRowTemplate.split("{tasting_id}").join(tasting.id);
wineRowTemplate = wineRowTemplate.split("{wine_id}").join(res.id);
wineRowTemplate = wineRowTemplate.split("{tasting_points}").join(tasting.score);
wineRowTemplate = wineRowTemplate.split("{house_name}").join(res.house_name);
wineRowTemplate = wineRowTemplate.split("{house_url}").join(res.winehouse_url_name);
wineRowTemplate = wineRowTemplate.split("{wine_name}").join(res.name);
wineRowTemplate = wineRowTemplate.split("{wine_url}").join(res.wine_url_name);
wineRowTemplate = wineRowTemplate.split("{wine_vintage}").join(res.vintage);
wineRowTemplate = wineRowTemplate.split("{last_tasted}").join(tastingDate.fromNow());
wineRowTemplate = wineRowTemplate.split("{overall_total}").join(stats.total);
wineRowTemplate = wineRowTemplate.split("{overall_average}").join(stats.average);
wineRowTemplate = wineRowTemplate.split("{overall_best}").join(stats.highest);
wineRowTemplate = wineRowTemplate.split("{overall_lowest}").join(stats.lowest);
wineRowTemplate = wineRowTemplate.split("{tb_point}").join(parseInt(res.tb_points, 10).toFixed(2));
wineRowTemplate = wineRowTemplate.split("{wine_note}").join(tasting.note);
if (!$sections.find(".section[data-section='" + section.abbr + "']").length) {
var sectionTemplate = $("#sectionTemplate").html();
sectionTemplate = sectionTemplate.split("{section_name_abbr}").join(section.abbr);
sectionTemplate = sectionTemplate.split("{section_name_proper}").join(section.proper);
$sections.append(sectionTemplate);
}
console.log("[TASTING] Inserting data to view for wine ID", tasting.wine_id);
$compile($sections.find(".section[data-section='" + section.abbr + "'] .tastings").prepend(wineRowTemplate))($scope);
更新: 我注意到如果例如我单击 DOM 中的第一行 ng-click,该函数仅触发一次,但如果我单击,例如DOM 中的第二个函数被触发两次。因此,出于某种原因,每个连续行的绑定都会增加对该行 ng-click 的绑定。我检查了我的 html 结构以确定它不是某些 missing/unnecessary 结束标记,但事实并非如此。
我发现了问题,这是您最意想不到的地方。问题落在我如何使用 $compile
$compile($sections.find(".section[data-section='" + section.abbr + "'] .tastings").prepend(wineRowTemplate))($scope);
将它包裹在 $section(行的父级)周围,为每个连续的行添加一个额外的点击侦听器。通过将它放在前置的 wineRowTemplate 周围解决了这个问题
$sections.find(".section[data-section='" + section.abbr + "'] .tastings").prepend($compile(wineRowTemplate)($scope));
我有一个模板,可重复用于显示具有不同数据的行。该模板还包含与该行相关的 $scope
函数。
<script id="wineRowTemplateT" type="text/html" style="display: none;">
<div class="row tasting" style="margin-bottom: 15px;">
<div class="col col-10">
<div class="rating" style="display: block; width: 60px; height: 60px; text-align: center; line-height: 60px; font-weight: 700; border: thin solid #ccc; border-radius: 50%; font-size: 1.2em;">{tasting_points}p</div>
</div>
<div class="col col-90">
<div class="row info">
<div class="col col-70">
<h3 style="font-weight: 300; border-bottom: thin solid #000; display: inline-block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
<span ng-click="smGoto('http://dev.thetastingbook.com/p/{house_url}', 'external')" style="font-weight: 600;">{house_name}</span>
<span ng-click="smGoto('http://dev.thetastingbook.com/wine/{house_url}/{wine_url}', 'external')">{wine_name}</span> {wine_vintage}
</h3>
</div>
<div class="col col-30">
<h4 ng-click="showTastingAdjectivesModal($event)" data-tasting-id="{tasting_id}" data-wine-id="{wine_id}" style="font-weight: 300; text-transform: uppercase; text-decoration: underline;">Show tasting note</h4>
</div>
</div>
</div>
</div>
</script>
有问题的函数是 showTastingAdjectivesModal()
在我的测试用例中,我从模板创建了六行。当我尝试点击其中一行中的 Show Tasting Note 时,它会触发六次。 tastingId 和 wineId 来自正确的行,只是它们都被触发了多次(六次),我不知道是什么原因造成的。
这是我的 showTastingAdjectivesModal() 函数:
$scope.showTastingAdjectivesModal = function (cEvent) {
console.log("showNoteModal called");
var $this = $(cEvent.toElement);
var tastingId = $this.data("tastingId");
var wineId = $this.data("wineId");
Tasting.getTastedWineAdjectives(tastingId, wineId)
.then(function(adjectives){
console.log("Got adjectives", JSON.stringify(adjectives));
adjectives.forEach(function(adj){
var type = adj.type;
if(type == "drink")
type = "conclusion";
$(".tasting-adjective-row[data-type='"+type+"']").find(".adjectives").append(adj.name + ", ");
});
$scope.noteModal.show();
});
};
我手上的 console.log
每次点击它都会打印 6 次。
附带说明一下,此代码是 运行 在 iOS 设备上使用带有 Ionic/AngularJS 的 Cordova。
谁能告诉我哪里做错了?
模板的用法如下:
var res = obj.res;
var stats = obj.stats;
section = {abbr: "", proper: ""};
tastingDate = moment(tasting.tasting_date);
if (tastingDate.isAfter(moment().startOf("isoweek")) || tastingDate.isSame(moment().startOf("isoweek"))) {
section.abbr = "week";
section.proper = "This Week";
} else if (tastingDate.isAfter(moment().subtract(1, "weeks").startOf("isoweek")) || tastingDate.isSame(moment().subtract(1, "weeks").startOf("isoweek"))) {
section.abbr = "lastweek";
section.proper = "Last Week";
} else {
section.abbr = tastingDate.format("W");
section.proper = "Week " + tastingDate.format("W");
}
var wineRowTemplate = $("#wineRowTemplateT").html();
wineRowTemplate = wineRowTemplate.split("{tasting_id}").join(tasting.id);
wineRowTemplate = wineRowTemplate.split("{wine_id}").join(res.id);
wineRowTemplate = wineRowTemplate.split("{tasting_points}").join(tasting.score);
wineRowTemplate = wineRowTemplate.split("{house_name}").join(res.house_name);
wineRowTemplate = wineRowTemplate.split("{house_url}").join(res.winehouse_url_name);
wineRowTemplate = wineRowTemplate.split("{wine_name}").join(res.name);
wineRowTemplate = wineRowTemplate.split("{wine_url}").join(res.wine_url_name);
wineRowTemplate = wineRowTemplate.split("{wine_vintage}").join(res.vintage);
wineRowTemplate = wineRowTemplate.split("{last_tasted}").join(tastingDate.fromNow());
wineRowTemplate = wineRowTemplate.split("{overall_total}").join(stats.total);
wineRowTemplate = wineRowTemplate.split("{overall_average}").join(stats.average);
wineRowTemplate = wineRowTemplate.split("{overall_best}").join(stats.highest);
wineRowTemplate = wineRowTemplate.split("{overall_lowest}").join(stats.lowest);
wineRowTemplate = wineRowTemplate.split("{tb_point}").join(parseInt(res.tb_points, 10).toFixed(2));
wineRowTemplate = wineRowTemplate.split("{wine_note}").join(tasting.note);
if (!$sections.find(".section[data-section='" + section.abbr + "']").length) {
var sectionTemplate = $("#sectionTemplate").html();
sectionTemplate = sectionTemplate.split("{section_name_abbr}").join(section.abbr);
sectionTemplate = sectionTemplate.split("{section_name_proper}").join(section.proper);
$sections.append(sectionTemplate);
}
console.log("[TASTING] Inserting data to view for wine ID", tasting.wine_id);
$compile($sections.find(".section[data-section='" + section.abbr + "'] .tastings").prepend(wineRowTemplate))($scope);
更新: 我注意到如果例如我单击 DOM 中的第一行 ng-click,该函数仅触发一次,但如果我单击,例如DOM 中的第二个函数被触发两次。因此,出于某种原因,每个连续行的绑定都会增加对该行 ng-click 的绑定。我检查了我的 html 结构以确定它不是某些 missing/unnecessary 结束标记,但事实并非如此。
我发现了问题,这是您最意想不到的地方。问题落在我如何使用 $compile
$compile($sections.find(".section[data-section='" + section.abbr + "'] .tastings").prepend(wineRowTemplate))($scope);
将它包裹在 $section(行的父级)周围,为每个连续的行添加一个额外的点击侦听器。通过将它放在前置的 wineRowTemplate 周围解决了这个问题
$sections.find(".section[data-section='" + section.abbr + "'] .tastings").prepend($compile(wineRowTemplate)($scope));