我有以下AngularJS控制器;
app.controller('playerController', ['$scope', '$http', 'playerService', function ($scope, $http, playerService) {
$scope.soundeffects = playerService.getSoundeffects();
function soundeffectCreation() {
var maxrows = 3;
var n = 0;
var buttonTable = "<table class='table text-center'><tr>";
for (var item = 0; item < $scope.soundeffects.length; item++) {
var soundeffect = $scope.soundeffects[item];
var soundeffectName = soundeffect.name;
buttonTable += "<td><label>" + soundeffectName + "</label><button type='button' class='btn btn-default btn-block' id='" + soundeffectName + "'><i class='fa fa-play'></i></button></td>"
if(n == maxrows) {
buttonTable += "</tr><tr>"
n = 0;
}
else{
n++;
}
}
buttonTable += "</tr></table>";
document.getElementById('soundeffects').innerHTML = buttonTable;
for (var item = 0; item < $scope.soundeffects.length; item++) {
var soundeffect = $scope.soundeffects[item];
var soundeffectName = soundeffect.name;
var button = document.getElementById(soundeffectName);
console.log(soundeffect);
console.log(soundeffectName);
console.log(button);
button.addEventListener('click', function () {
console.log(soundeffectName);
})
}
}
soundeffectCreation();
}
它在以下HTML上发挥了作用:
<div id="soundeffects"></div>
使用到目前为止只包含3个项目的JSON数组:
{
"soundeffects": [
{
"name": "Wilhelm Scream",
"video": "r6JK-gRELI0"
},
{
"name": "Fireball",
"video": "AHRf27GPhQc"
},
{
"name": "Mario Jump",
"video": "37-paiEz0mQ"
}
]
}
在playerService中成功检索此JSON。 表中的按钮创建得很好,它们得到各自的标签并正确分配了id,问题出现在第二个for循环中。 (之所以有第二个for循环是因为我无法在实际创建表之前添加eventlisteners。)
addEventListener之外的前三个console.log返回正确的值:Console
三个不同的对象及其各自的名称和视频。 三个不同的名字(Wilhelm Scream,Fireball&amp; Mario Jump)。 三个不同的按钮,其id等于上述名称。
但是,当我单击创建的按钮时,每个按钮都会返回“Mario Jump”,即数组的最后一个值,而不是相应元素的名称。尽管按钮的id是正确的和一切。我出错的任何建议?
ALTERNATIVE
作为替代方案,我尝试将ng-click='$scope.playSoundeffect(" + soundeffect + ")'
放在原始按钮创建器中,但这只会在[Object object]
中产生声音效果。任何有关如何使该方法有效的建议都将受到欢迎。
为海外编辑
在获得更多AngularJS经验之后,我重新制作了整个部分。我删除了整个soundeffectCreation()
函数,并将其替换为以下html:
<div ng-repeat="soundeffect in soundeffects track by $index" class="col-xs-6 col-md-4 col-lg-3">
<div class="text-nowrap"><label>{{soundeffect.name}}</label></div>
<div>
<button class="btn btn-default" ng-click="playSoundeffect(soundeffect)">
<i class="fa fa-play"></i>
</button>
</div>
</div>
答案 0 :(得分:1)
使用let
代替var
for循环:
for (let item = 0; item < $scope.soundeffects.length; item++) {
let soundeffect = $scope.soundeffects[item];
let soundeffectName = soundeffect.name;
let button = document.getElementById(soundeffectName);
console.log(soundeffect);
console.log(soundeffectName);
console.log(button);
button.addEventListener('click', function () {
console.log(soundeffectName);
})
}
问题是每次循环迭代缺少明确的闭包 - 请查看此SO answer以获取for
循环中闭包的详细说明。
不支持let
您还可以使用自调用匿名函数为每次迭代创建新范围:
for (var item = 0; item < $scope.soundeffects.length; item++) {
(function(i) {
var soundeffect = $scope.soundeffects[i];
var soundeffectName = soundeffect.name;
var button = document.getElementById(soundeffectName);
console.log(soundeffect);
console.log(soundeffectName);
console.log(button);
button.addEventListener('click', function () {
console.log(soundeffectName);
})
})(item);
}
答案 1 :(得分:1)
您需要像这样
在关闭中捕获soundeffectName
button.addEventListener('click', function (soundeffectName) {
console.log(soundeffectName);
}.bind(null, soundeffectName))
答案 2 :(得分:0)
你正在处理关闭
var soundeffectName = soundeffect.name;
button.addEventListener('click', function () {
console.log(soundeffectName);
})
soundEffect
是外部作用域的变量,所有侦听器都将保存对外部作用域的引用,并且它们都将指向内存中与上一次迭代的值相同的位置。要在侦听器中保留值的副本,请尝试将代码包装在IIFE中
(function(name){
button.addEventListener('click', function () {
console.log(name);
})
})(soundeffectName)