我正在动态生成包含不同字段的表单(textbox,textarea,select,radio / checkbox)。
我想显示/隐藏某些字段,具体取决于在其他某些字段中选择的内容。
一个简单的案例可以是:
$('select').change(function () {
if($(this).val() === '1') {
$('p').show();
}
else {
$('p').hide();
}
});

p {
display: none;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<select>
<option value="0">Bike</option>
<option value="1">Car</option>
</select>
<p>Left / right hand drive ?
Left: <input type="radio" value="left" name="dir" />
Right: <input type="radio" value="right" name="dir" />
</p>
&#13;
我正在动态生成字段,并且有多种情况,我需要根据其他一些字段的值显示/隐藏不同的字段。所以,我不想再次编写相同的代码。再次。为了遵守DRY原则,我想创建某种通用函数(可能是一个插件)来处理所有这些场景。
我的基本(工作)想法是:
$('[data-dependent]').each(function () {
var $ele = $(this);
var dependsOn = $ele.data('dependent');
$.each(dependsOn, function (target, value) {
$(target).on('change', function () {
if ($(this).val() === value) {
$ele.show();
} else {
$ele.hide();
}
});
});
});
&#13;
[data-dependent] {
display: none;
}
&#13;
<select id="vehicle">
<option value="0">Bike</option>
<option value="1">Car</option>
</select>
<p data-dependent='{"#vehicle": "1" }'>Left / right hand drive ? Left:
<input type="radio" value="left" name="dir" />Right:
<input type="radio" value="right" name="dir" />
</p>
&#13;
此代码有效,但它附带了许多事件处理程序。此外,它不处理基于多于1个字段的值显示/隐藏字段的情况。我无法找到解决这个问题的好方法。
我正在寻找一个干净的&amp;灵活的方案。如果已经有了这个插件,那也可以。
答案 0 :(得分:4)
你听说过 The Observer Pattern 吗?如果没有,link here或者只是在js设计模式书中搜索它。关于观察者模式的事情是,在这些情况下,它非常有用且模块化(且高效),其中对象侦听另一个对象的更改。
正如我在你的问题中看到的那样,观察者模式并不是必需的,因为只有当单击一个对象时才显示对象。但是,如果您希望仅在选择两个单选按钮时显示a,那么您真的需要它。
因为你说你想要一个干净/灵活的解决方案,你需要的设计模式答案;)这是我的尝试: (skip the code and see the codepen i made for you)
HTML:
<!--
1.what is data-publish?
if data-publish gets clicked or changed(depends wheter is input or select option), it notifies every element in DOM with data-observe with the same value as our clicked data-publish.
2.what is data-observe?
data-observe="4 5" observes the DOM elements with data-publish="4" & data-publish="5" for a change. data-observe="4 5" gets display:block only when data-publish="4" & data-publish="5" are selected(it can be the case where data-publish="4 5", and it works the same)
3. what is data-name?
data-name is a unique name of a DOM element which as data-observe attribute. this is set at page load, js insert in DOM a random string to data-name
-->
<p>combinations:(note, at page load, nothing is selected)</p>
<p>1 & 1</p>
<p>2 & 2</p>
<p>1 & 1 -> & 7 </p>
<p>1 & 1 & 10 & 10 -> & 7</p>
<select>
<option selected></option>
<option data-publish="1">pub 1</option>
<option data-publish="2">pub 2</option>
<option data-publish="3">pub 3</option>
</select>
<select>
<option selected></option>
<option data-publish="4">pub 4</option>
<option data-publish="1">pub 1</option>
<option data-publish="5">pub 5</option>
</select>
<select>
<option selected></option>
<option data-publish="10">pub 10</option>
<option data-publish="11">pub 11</option>
<option data-publish="12">pub 12</option>
</select>
<select>
<option selected></option>
<option data-publish="10 2">pub 10 & 2</option>
<option data-publish="13">pub 13</option>
<option data-publish="14">pub 14</option>
</select>
<p data-observe="1">(triggered by two 1)
pub 7<input type="checkbox" data-publish="7">
pub 8<input type="checkbox" data-publish="8">
pub 9<input type="checkbox" data-publish="9">
</p>
<p data-observe="2">triggered by two 2</p>
<p data-observe="1 7">i am triggered by two 1, one 7</p>
<p data-observe="1 7 10">i am triggered by two 1, one 7, two 10</p>
CSS:
[data-observe] {
display: none;
}
Javascript:
/*
* @author: Ali Cerrahoglu
* @thing: awesome thing
* @use: no defaults...so version 1.0.0
it's a simple pub-sub which shows divs based on select options and radio/checkbox inputs
*/
// revealing module pattern
var ObserverPlugin = (function(){
// here will be stored every DOM object which has
// data-observe attr and data-name attr (data-name will be served
// as a key , which will store another object with a reference to the DOM object
// how many object does it observe)
var observers = {};
var publishers = [];
// observer pattern & revealing module pattern
var observer = (function(){
var topics = {};
var publish = function(topic, reference) {
// if there is no topic on the publish call, well get out !
if (!topics[topic]) {
return false;
}
// self invoked funciton, which calls the function passed when
// the topic was subscribed (if more then one function was published on the same topic
// then call each one of them)
(function(){
var subscribers = topics[topic],
len = subscribers ? subscribers.length : 0;
while (len--) {
subscribers[len].func(topic, reference);
}
})();
};
var subscribe = function(topic, func) {
if (!topics[topic]) {
topics[topic] = [];
}
topics[topic].push({
func: func
});
};
return {
subscribe: subscribe,
publish: publish,
topics: topics
}
})();
// creates random string, used to make data-name random for observers
var _makeRandomString = function() {
var text = "";
var possible = "abcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < 5; i++ ) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
// verifies if eleme existis in array, if not, returns false
var _isInside = function( elem, array ) {
return array.indexOf(elem) > -1;
}
// topic is the topic
// reference is a reference to the DOM object clicked
var _observerFunction = function(topic, reference) {
var number = reference.attr('data-value');
var topics = topic.toString().split(' ');
var length = topics.length;
for( var key in observers ) {
for( var i = 0; i < length; i +=1 ) {
if( _isInside( topics[i], observers[key].topicsObserved ) ) {
// it exists
observers[key].sum += Number(number);
// 'number' is a string, so we have to convert it back to number
}
}
if( observers[key].sum == 0 ) {
// it is 0, so show that goddam DOM obj ! :))
// again, put here 'var' for clarity
// does not affect the code
var display = 'block';
}
else {
// it is not 0, so hide it
var display = 'none';
}
observers[key].reference.css('display', display);
}
// change value to -1 or 1
if( number == '-1' ) {
reference.attr('data-value', '1');
}
else {
reference.attr('data-value', '-1');
}
}
/*
* lets say we have 3 DOM objects with data-publish="1"
and 2 DOM objects with data-publish="2"
and one with data-observe="1 2";
so data-observe has to be called 5 times in order for him to be shown on the page;
each DOM object with data-publish will be added at runtime a data-value attribute
which will be -1 or 1. each time it is clicked or changed, it changes to the opposite.
this serves as data-observes will have a property named sum, which will be in the previous case 5
5 gets calculated with -1, or 1 when clicked data-publish DOM object.
So if i click first at data-publish="1" , 5 becomes 4. if i click again the same data-publish, becomes 5.
when sum property becomes 0, the data-observe is shown.
this function calculates how many data-publish="1" exists and so on
(it also does the other stuff needed for publishers)
*/
var _managePublishers = function() {
$('[data-publish]').each(function(){
var el = $(this);
// adds that value data, remember it? :D
el.attr('data-value', '-1');
// trim in case data-publish = "1 2 3" and store in an array
var publisher = el.data('publish').toString();
// we subscripe 'publisher' topic, but we check each string in topic
// here is tricky. if one publishers has more than one topic inside data-publish
// then we subscribe topic, but we check for topic's substring in publishers
var topics = publisher.split(' ');
if( !observer.topics[publisher] ) {
// we subscribe data-publish topic, becouse when we click it we want to fire something, no?
observer.subscribe( publisher, _observerFunction );
}
// but here in publishers we add only the substrings
for( var key in topics ) {
if( publishers[topics[key]] ) {
// the publisher exists
publishers[topics[key]] += 1;
}
else {
// the publisher doesn't exist
publishers[topics[key]] = 1;
}
}
});
}
// gets the observers, calculates sum, caches their reference
var _manageObservers = function() {
$('[data-observe]').each(function(){
var el = $(this);
// create random data-name
el.attr('data-name', _makeRandomString());
var datas = el.data('observe').toString().split(' '); // make an array again if we have multiple attachments
observers[el.data('name')] = (function(){
var sum = (function(){
var sum2 = 0;
// if datas[key] is found in publishers array, add it to sum
for( var key in datas ) {
var temp = publishers[datas[key]];
if( temp ) {
sum2 += temp;
}
}
return sum2;
})();
var reference = el; // caching, so it is faster !
var topicsObserved = datas;
// we need this when a user clicks data-publish, we need to see which DOM obj. are observing this.
// i really like revealing module pattern...i got used to it
return {
sum: sum,
reference: reference,
topicsObserved: topicsObserved
}
})();
})
}
var init = function() {
_managePublishers();
_manageObservers();
$('[data-publish]').on( 'click', function(){
observer.publish( $(this).data('publish'), $(this) );
});
$('select').on('change', function(){
var cache = $(this);
// if in this select there is an option which has value 1(there is chance that it triggered a succesfull publish) we publish that too
observer.publish( cache.find('[data-value="1"]').data('publish'), cache.find('[data-value="1"]') );
var el = cache.find('[data-publish]:selected');
observer.publish( el.data('publish'), el );
})
}
return {
init: init,
// in case you want to add after page load
// warning: i didn't test these methods. maybe it can be a bug somewhere
// it is not in my scope to test these, as i won't need for this example any adding after page load
publish: observer.publish,
subscribe: observer.subscribe
}
})();
ObserverPlugin.init();
所以是的,这就是它。你可以再次看到我的codepen(here) 我是以插件的形式制作的。您可以向多个发布者附加观察者,您可以将具有相同值的多个发布者附加到一个观察者,或者您只需将一个发布者附加到一个观察者。我试图让它尽可能高效。我希望这可以帮助你Jashwant:)
(编辑。现在它支持数据发布中的多个字符串,玩得开心!) (编辑。您不必将随机数据名称字符串添加到HTML观察者)
答案 1 :(得分:2)
我喜欢你基于少量控件对元素可见性进行动态处理的想法。我尝试制作一些,目前你可以根据radiobuttons和选择项目设置其他元素的可见性。下面的解决方案假设控制其他元素可见性的元素具有id
- 属性。也许,出于性能原因,您可以将其更改为新属性,例如:data-has-dependents
,因此id
- 属性仅用于其值。如果有很多具有id的元素,那么这可能是实用的。
如果选择了两个不同的值,我也允许一些元素可见。 vehicle
以逗号分隔了以下值2
和3
的列表:
<p data-dependent='{"vehicle": "2,3" }'>Rocket engine type ? Gas turbine
<input type="radio" value="gasturbine" name="enginetype" />Aerojet Rocketdyne
<input type="radio" value="aerojet" name="enginetype" />
</p>
因此,如果用户选择平面或航天飞机,则上面的单选按钮可见。
如果选择车辆冰淇淋车或沙漠型冰淇淋,也可以看到冰淇淋场的类型:
<p data-dependent='{"vehicle": "4", "dessert": "icecream" }'>Type of Ice Cream? Vanilla:
<input type="radio" value="vanilla" name="icecream" />Strawberry Ice cream:
<input type="radio" value="strawberry" name="icecream" />Coffee Ice cream:
<input type="radio" value="coffee" name="icecream" />
</p>
更新,在下面的代码中,checkDependencies
函数在以下某个实例发生后使用:
在checkDependencies
函数中,第一个循环遍历每个依赖数据元素,并获得依赖于数据的元素的属性值。在第二个循环中,获得具有id的每个元素的值。最后,在第三和第四循环中,先前找到的从属数据元素值用于找到匹配的选择(2.)或单选按钮的父元素(3)。更准确地说,第三个循环用于允许多个键和一个键。依赖数据元素的值,例如:data-dependent='{"vehicle": "4", "dessert": "icecream" }'
。例如,第四循环允许从属元素具有一个键的两个值。 data-dependent='{"vehicle": "2,3" }'
。因此,第三和第四循环是为了灵活性。
我认为可能有比这更复杂的答案+我认为像AngularJS这样基于MVC的JavaScript框架在这种情况下可能非常实用。
checkDependencies();
$("select[id]").on('change', function() {
checkDependencies();
});
$("[id] > :radio").on('click', function() {
checkDependencies();
});
function checkDependencies() {
$("[data-dependent]").each(function() {
$dependent = $(this);
var data = $(this).data("dependent");
var keyCount = Object.keys(data).length;
var checkedCount = 0;
var setVisible = false;
var dependentValues = $.map(data, function(value, index) {
return value;
});
$("[id]").each(function() {
var hasRadioButtons = $(this).find(":radio").length;
var elementId = $(this).attr("id");
var elementValue;
if (hasRadioButtons) {
elementValue = $(this).find(":checked").val()
} else {
elementValue = $(this).val();
}
for (i = 0; i < keyCount; i++) {
var dependentId = Object.keys(data)[i];
//if multiple values for one key
var values = dependentValues[i].split(",");
for (j = 0; j < values.length; j++) {
var dependentValue = values[j];
if (elementId === dependentId) {
//check if value selected
if (elementValue === dependentValue) {
checkedCount += 1;
setVisible = true;
$dependent.show();
//found element, exit inner loop
break;
} else {
//hide if not previously set visible
if (!setVisible)
$dependent.hide();
//if all element dependencies found exit inner loop
if (keyCount === checkedCount)
break;
}
}
}
}
});
});
}
[data-dependent] {
display: none;
}
#dessert {
margin-left: 20px;
display: inline
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<select id="vehicle">
<option value="0">Bike</option>
<option value="1">Car</option>
<option value="2">Plane</option>
<option value="3">Space shuttle</option>
<option value="4">Ice Cream Truck</option>
</select>
<p id="dessert">Dessert: Sweets
<input type="radio" value="sweets" name="dessert" />Ice cream
<input type="radio" value="icecream" name="dessert" />Cake
<input type="radio" value="cake" name="dessert" />
</p>
<p data-dependent='{"vehicle": "0" }'>Bike brand ? Trek
<input type="radio" value="trek" name="bike" />Giant
<input type="radio" value="gt" name="bike" />Cannondale
<input type="radio" value="cannondale" name="bike" />
</p>
<p data-dependent='{"vehicle": "1" }'>Car's fuel type ? Petrol
<input type="radio" value="petrol" name="fueltype" />Diesel
<input type="radio" value="diesel" name="fueltype" />Biodiesel
<input type="radio" value="biodiesel" name="fueltype" />Hybrid
<input type="radio" value="hybrid" name="fueltype" />
</p>
<p data-dependent='{"vehicle": "2,3" }'>Rocket engine type ? Gas turbine
<input type="radio" value="gasturbine" name="enginetype" />Aerojet Rocketdyne
<input type="radio" value="aerojet" name="enginetype" />
</p>
<p data-dependent='{"vehicle": "1" }'>Left / right hand drive? Left:
<input type="radio" value="left" name="dir" />Right:
<input type="radio" value="right" name="dir" />
</p>
<select data-dependent='{"dessert": "sweets" }'>
<option value="0">Jelly beans</option>
<option value="1">Haribo gummy bears</option>
<option value="2">Fruit candy</option>
</select>
<p data-dependent='{"vehicle": "4", "dessert": "icecream" }'>Type of Ice Cream? Vanilla:
<input type="radio" value="vanilla" name="icecream" />Strawberry Ice cream:
<input type="radio" value="strawberry" name="icecream" />Coffee Ice cream:
<input type="radio" value="coffee" name="icecream" />
</p>
<p data-dependent='{"dessert": "cake" }'>Type of cake? Chocolate Cake:
<input type="radio" value="chokocake" name="cake" />Cheesecake:
<input type="radio" value="cheesecake" name="cake" />Carrot Cake:
<input type="radio" value="carrotcake" name="cake" />
</p>
答案 2 :(得分:0)
$('select').change(function () {
if($(this).val() === '1') {
$('p').show();
}
else {
$('p').hide();
}
});
p {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<select>
<option value="0">Bike</option>
<option value="1">Car</option>
</select>
<p>Left / right hand drive ?
Left: <input type="radio" value="left" name="dir" />
Right: <input type="radio" value="right" name="dir" />
</p>
答案 3 :(得分:-1)
更改您可以使用的样式
。$( 'P')的CSS( “显示”, “”);
或
$( 'P')的CSS( “显示”, “无”);