2017-06-23 33 views
0

我有下面的代码,它显示并隐藏使用基本选项链父/子关系的选择菜单。一旦有变化,我需要调用一个函数。如何在多个更改事件中使用jQuery承诺

目前我正在按照下面的说明进行操作,每触发一个事件<select>,然后调用该函数。在现实生活中,这是一个阿贾克斯呼吁,但这与问题无关。

我下面的代码工程。我想要解决的问题是,如何在不依赖更改事件的情况下完成此操作,因为它会不必要地多次触发该功能。我只想简单地在$.each()循环的末尾放置一个函数调用,当父对象被更改时,但由于涉及动画,它将失败,因为有问题的元素有时仍可见/隐藏。我通过在每个slideUp()slideDown()之间放置一个回调来解决这个问题,但这是我最终触发事件多次的确切原因。

我有我要找的答案用了jQuery promise()其中规定一个强烈的感觉:

的.promise()方法返回一个动态生成的承诺,解决一旦某种类型绑定的所有行动收集,排队或不,已经结束。

这正是我想要做的,但我完全被promise()搞糊涂了,它是正确的用法。我明白了,但我可以利用一些帮助理解如何将所有这些更改事件排入一个promise(),然后在全部完成时调用我的函数。

$('select[data-parent="true"]').change(function() { 
 
    var parentValue = +this.value; 
 
    var parentId = $(this).data('parent_id'); 
 
    $('div[data-parent_id="' + parentId + '"]').each(function() { 
 
    var parentValues = $(this).data('parent_values'); 
 
    if (parentValues.indexOf(parentValue) !== -1) { 
 
     $(this).slideDown(1000, function() { 
 
     $(this).find('select').change(); 
 
     }); 
 
    } else { 
 
     $(this).slideUp(1000, function() { 
 
     $(this).find('select').change(); 
 
     }); 
 
    } 
 
    }); 
 
}); 
 
$('select').on('change', function() { 
 
    var results = ''; 
 
    $('div.option').each(function() { 
 
    results += $(this).find('select').prop('name') + ' IS VISIBLE: ' + +$(this).is(':visible') + '<br>'; 
 
    }); 
 
    $('#results').html(results); 
 
});
div { 
 
    padding: 5px 10px; 
 
} 
 

 
div.child { 
 
    display: none 
 
} 
 

 
select { 
 
    width: 200px; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> 
 
<div class="option"> 
 
    <select name="container" data-parent="true" data-parent_id="10"> 
 
    <option value="">--- Select a container---</option> 
 
\t \t <option value="1">Box</option> 
 
\t \t <option value="2">Bag</option> 
 
\t \t <option value="3">Pallet</option> 
 
\t </select> 
 
</div> 
 
<div class="child option" data-parent_id="10" data-parent_values="[1]"> 
 
    <select name="box color"> 
 
\t \t <option value="100">Red</option> 
 
\t \t <option value="200">Blue</option> 
 
\t </select> 
 
</div> 
 
<div class="child option" data-parent_id="10" data-parent_values="[2]"> 
 
    <select name="bag color"> 
 
\t \t <option value="300">Green</option> 
 
\t \t <option value="400">Yellow</option> 
 
\t </select> 
 
</div> 
 
<div class="child option" data-parent_id="10" data-parent_values="[3]"> 
 
    <select name="pallet color"> 
 
\t \t <option value="500">Black</option> 
 
\t \t <option value="600">Yellow</option> 
 
\t </select> 
 
</div> 
 
<div id="results"> 
 
</div>

回答

1

在jQuery动画可以返回承诺.promise()和使用.map代替.each - 该代码可以是简单的:

$('select[data-parent="true"]').change(function() { 
 
    var parentValue = +this.value; 
 
    var parentId = $(this).data('parent_id'); 
 
    $.when.apply($, $('div[data-parent_id="' + parentId + '"]').map(function(i, v) { 
 
     var parentValues = $(this).data('parent_values'); 
 
     if (parentValues.indexOf(parentValue) !== -1) { 
 
      return $(this).slideDown(1000).promise(); 
 
     } else { 
 
      return $(this).slideUp(1000).promise(); 
 
     } 
 
    })).done(function() { 
 
     var results = ''; 
 
     $('div.option').each(function() { 
 
      results += $(this).find('select').prop('name') + ' IS VISIBLE: ' + +$(this).is(':visible') + '<br>'; 
 
     }); 
 
     $('#results').html(results); 
 
    }); 
 
});
div { 
 
    padding: 5px 10px; 
 
} 
 

 
div.child { 
 
    display: none 
 
} 
 

 
select { 
 
    width: 200px; 
 
    margin: 4px; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> 
 
<div class="option"> 
 
    <select name="container" data-parent="true" data-parent_id="10"> 
 
    <option value="">--- Select a container---</option> 
 
\t \t <option value="1">Box</option> 
 
\t \t <option value="2">Bag</option> 
 
\t \t <option value="3">Pallet</option> 
 
\t </select> 
 
</div> 
 
<div class="child option" data-parent_id="10" data-parent_values="[1]"> 
 
    <select name="box color"> 
 
\t \t <option value="100">Red</option> 
 
\t \t <option value="200">Blue</option> 
 
\t </select> 
 
</div> 
 
<div class="child option" data-parent_id="10" data-parent_values="[2]"> 
 
    <select name="bag color"> 
 
\t \t <option value="300">Green</option> 
 
\t \t <option value="400">Yellow</option> 
 
\t </select> 
 
</div> 
 
<div class="child option" data-parent_id="10" data-parent_values="[3]"> 
 
    <select name="pallet color"> 
 
\t \t <option value="500">Black</option> 
 
\t \t <option value="600">Yellow</option> 
 
\t </select> 
 
</div> 
 
<div id="results"> 
 
</div>

+0

谢谢 - 我一直是'map()'的粉丝,它是合适的,这比我想出的更优雅和直观我。 – billynoah

+0

我很惊讶关于这个话题的问答在SO上并不常见..我找到了一些好的线索,但没有像我期望的那么多,因为对此的需求可能始终存在。我认为很多人只是满足于它的作品,并不介意20个事件在他们只需要一个事件时就被触发。 – billynoah

0

实验已经产生了以下解决方案的一个小时。创建一个$.Deferred()对象的数组,并使用$.when来解决它们。棘手的部分来自this answer,它解释了如何将数组传递给$.when。希望这可以帮助别人使用jQuery挣扎递延对象,好像我是:

$('select[data-parent="true"]').change(function() { 
 
    var deferred = []; 
 
    var parentValue = +this.value; 
 
    var parentId = $(this).data('parent_id'); 
 
    $('div[data-parent_id="' + parentId + '"]').each(function(i, v) { 
 
    deferred[i] = $.Deferred(); 
 
    var parentValues = $(this).data('parent_values'); 
 
    if (parentValues.indexOf(parentValue) !== -1) { 
 
     $(this).slideDown(1000, function() { 
 
     deferred[i].resolve(); 
 
     }); 
 
    } else { 
 
     $(this).slideUp(1000, function() { 
 
     deferred[i].resolve(); 
 
     }); 
 
    } 
 
    }); 
 
    $.when.apply($, deferred).done(function() { 
 
    var results = ''; 
 
    $('div.option').each(function() { 
 
     results += $(this).find('select').prop('name') + ' IS VISIBLE: ' + +$(this).is(':visible') + '<br>'; 
 
    }); 
 
    $('#results').html(results); 
 
    }); 
 
});
div { 
 
    padding: 5px 10px; 
 
} 
 

 
div.child { 
 
    display: none 
 
} 
 

 
select { 
 
    width: 200px; 
 
    margin: 4px; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> 
 
<div class="option"> 
 
    <select name="container" data-parent="true" data-parent_id="10"> 
 
    <option value="">--- Select a container---</option> 
 
\t \t <option value="1">Box</option> 
 
\t \t <option value="2">Bag</option> 
 
\t \t <option value="3">Pallet</option> 
 
\t </select> 
 
</div> 
 
<div class="child option" data-parent_id="10" data-parent_values="[1]"> 
 
    <select name="box color"> 
 
\t \t <option value="100">Red</option> 
 
\t \t <option value="200">Blue</option> 
 
\t </select> 
 
</div> 
 
<div class="child option" data-parent_id="10" data-parent_values="[2]"> 
 
    <select name="bag color"> 
 
\t \t <option value="300">Green</option> 
 
\t \t <option value="400">Yellow</option> 
 
\t </select> 
 
</div> 
 
<div class="child option" data-parent_id="10" data-parent_values="[3]"> 
 
    <select name="pallet color"> 
 
\t \t <option value="500">Black</option> 
 
\t \t <option value="600">Yellow</option> 
 
\t </select> 
 
</div> 
 
<div id="results"> 
 
</div>

+1

当然,知道jQuery动画可以“本地”返回承诺 - 并使用.map代替.each - 代码可以进一步简化为https://jsfiddle.net/0ruud9xL/ –

+0

那么这就是最酷的事情我一整天都见过。你应该把它作为另一个答案,我很乐意将它标记为已接受。谢谢! – billynoah

+0

答案补充 - 虽然我没有测试它 - 从头开始​​测试它现在 –