簡體   English   中英

根據其他字段的值顯示/隱藏表單字段

[英]Show/Hide form fields based on value of other fields

我正在動態生成具有不同字段的表單(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> 

我正在動態生成字段,在多種情況下,我需要根據其他某些字段的值來顯示/隱藏不同的字段。 因此,我不想再寫一次相同的代碼。 為了遵守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(); } }); }); }); 
 [data-dependent] { display: none; } 
 <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> 

該代碼有效,但是它附加了許多事件處理程序。 同樣,它不處理基於多個字段的值可以顯示/隱藏字段的情況。 我找不到解決這個問題的好方法。

我正在尋找一種清潔靈活的解決方案。 如果已經有一個插件可以使用。

您是否聽說過觀察者模式 如果不是,請在此處鏈接,或僅在js設計模式書中進行搜索。 關於觀察者模式的事情是,在一個對象偵聽另一個對象的更改的情況下,它非常有用且模塊化(高效)。

正如我在您的問題中所看到的,並不一定需要觀察者模式,因為僅當單擊或選擇一個對象時才顯示一個對象。 但是,例如,如果您希望僅在選擇兩個單選按鈕時才顯示a,那么您確實需要它。

因為您說過您想要一個干凈/靈活的解決方案中的答案,這是您需要的設計模式;)這是我的嘗試:( 跳過代碼,看看我為您制作的codepen

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( 在這里 ),它是以插件的形式制作的。 您可以將一個發布者附加到一個觀察者,可以將一個具有相同價值的多個發布者附加到一個觀察者,也可以僅將一個發布附加到一個觀察者。 我試圖使其盡可能高效。 我希望這可以幫助您Jashwant :)

(編輯。現在它支持數據發布中的多個字符串,玩得開心!)(編輯。您不必向HTML觀察者添加隨機數據名稱字符串)

我喜歡您的想法,即基於少量控件對元素可見性進行動態處理。 我嘗試做一些,目前您可以根據單選按鈕設置其他元素的可見性並選擇項目。 下面的解決方案假設控制其他元素可見性的元素具有id屬性。 也許出於性能原因,您可以將其更改為新屬性,例如: data-has-dependents ,因此id -attribute僅用於其值。 如果id的元素很多,那么這可能很實用。

如果選擇了兩個不同的值,我還允許一些元素可見。 vehicle逗號分隔列表包含以下值23

<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函數下面的代碼中的Updated

  1. 頁面已加載
  2. 具有ID的選擇元素已更改
  3. 單擊單選按鈕,並且單選按鈕的父級有一個ID

checkDependencies函數中,第一個循環遍歷每個相關數據元素,並獲得數據相關元素的屬性值。 在第二個循環中,獲取每個具有id的元素的值。 最后,在第三和第四循環中,先前找到的從屬數據元素值用於查找匹配的select(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> 

 $('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> 

改變你可以使用的風格

$( 'P')的CSS( “顯示”, “”);

要么

$( 'P')的CSS( “顯示”, “無”)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM