简体   繁体   中英

Appending and detaching dynamically created inputs

I have two radio buttons:

  • fixed_price_option ( Selected by default.)
  • variable_price_option ( Disabled by default)

I also have two types of inputs:

  • fixed_price_input ( Visable by default. Only one occurance.)
  • variable_price_input (Not present in code as it has to be added dynamically. One or more occurances.)

When fixed_price_option is selected an input called fixed_price_input should be visable and included when later running .serialize().

When fixed_price_option is selected no variable_price_input ´s should be visible or included when later running .serialize().

variable_price_option should only be selectable when the difference between two date inputs are more than 12 months. (this I have solved)

When variable_price_option is selected there should be one more variable_price_input ´s visable as there are whole years between the two date inputs (ie durationMonths + 1). They also need to be included when later running .serialize() so they need to have names like price_year_1 , price_year_2 , price_year_3 and so on, depending on how many whole years there are between the two date inputs.

When variable_price_option is selected fixed_price_input should not be visible or included when later running .serialize().

I have supplied the code as far as I have come. The missing logic needs to be put in the event handler at the bottom of the js code.

Any suggestions on how to solve this?

-- UPDATE --

My question needed clarification:

What I'm struggling with is to toggle the existence of the two types of inputs ( fixed_price_input and variable_price_input ) depending on which radio button is checked. Hiding/showing them isn't enough because I'm going to use .serialize() at a later point. Should I use .detach() and .append() somehow?

I'm also struggling with how to create one more variable_price_input 's than there are years between the start and end date. Should I use <template> or .clone() somehow?

 $(document).ready(function() { $("#inputStartDate, #inputEndDate").change(function() { if ($('#inputStartDate').val() && $('#inputEndDate').val()) { var startDate = moment($('#inputStartDate').val()); var endDate = moment($('#inputEndDate').val()); var durationMonths = endDate.diff(startDate, 'months'); $('#durationMonths').text(durationMonths); var durationYears = endDate.diff(startDate, 'years'); $('#durationYears').text(durationYears); if (duration > 12) { $('#variablePriceOption').prop("disabled", false); } else { $('#variablePriceOption').prop("disabled", true); } } }); $('#variablePriceOption, #fixedPriceOption').change(function() { if (this.value == 'fixedPrice') { //Logic needed } else if (this.value == 'variablePrice') { //Logic needed } }); });
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment-with-locales.min.js"></script> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.0/css/bootstrap.min.css" rel="stylesheet" /> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.0/js/bootstrap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script> <div class="container"> <div class="row mt-3"> <div class="col"> <div class="form-group"> <label for="inputStartDate">Start date</label> <input type="date" class="form-control" id="inputStartDate" name="land_contract_start_date"> </div> </div> <div class="col"> <div class="form-group"> <label for="inputEndDate">End date</label> <input type="date" class="form-control" id="inputEndDate" name="land_contract_end_date"> </div> </div> </div> <div class="text-center">Months between selected dates = <span id="durationMonths"></span>. Years between selected dates = <span id="durationYears"></span>. </div> <div class="form-group"> <label for="inputPriceModel">Price model</label> <div id="inputPriceModel"> <div class="form-check"> <input class="form-check-input" type="radio" name="inputPriceModel" id="fixedPriceOption" value="fixedPrice" required checked="checked"> <label class="form-check-label" for="fixedPriceOption"> Fixed price </label> </div> <div class="form-check"> <input class="form-check-input" type="radio" name="inputPriceModel" id="variablePriceOption" value="variablePrice" disabled="disabled"> <label class="form-check-label" for="variablePriceOption"> Variable price </label> </div> </div> </div> <div class="form-group fixedPriceModelFormGroup"> <label for="fixed_price_input">Fixed price amount</label> <div class="input-group"> <input type="number" class="form-control" id="fixed_price_input" name="land_contract_fixed_annual_price"> <div class="input-group-append"> <span class="input-group-text">$</span> </div> </div> </div> </div>

This should help get you started as far as variable pricing inputs showing for each # of year difference of the calendar dates. The code could be broken out into other functions for handling the display/hiding of elements, etc. You need to move your <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> code above your other JS references to get rid of the errors you're seeing for bootstrap .

Also, your duration variable should be durationMonths for comparing > 12, as duration is undefined . durationYears should be moved outside the change function of the calendar dates so you can reference it in your other processing functions. I added Math.abs() to the date calculations to ensure you're dealing with a positive integer for comparisons.

Using the disabled attribute on the inputs that are hidden will allow you to serialize the visible form data and ensure you won't get hidden inputs (variable pricing fields, etc) as part of the serialization data.

As @Twisty mentioned in the comments on your post, you will want to use .detach() or some sort of way to store the variable pricing input values if you toggle back and forth between Fixed/Variable options ( localStorage , sessionStorage also options for storing data), if you want to maintain any values placed in the variable/fixed inputs . You will need to remove the .empty() usage on the input fields in my example as well, if you intend to store the data values of the inputs.

The loop function handleVariablePricing for determining how many variable pricing inputs should show would need to hook into the stored data functionality to ensure you are creating the same amount of fields with previously entered values, and not adding additional new fields on top of the existing fields/values.

 $(document).ready(function() { var durationYears = 0; $("#inputStartDate, #inputEndDate").change(function() { if ($('#inputStartDate').val() && $('#inputEndDate').val()) { var startDate = moment($('#inputStartDate').val()); var endDate = moment($('#inputEndDate').val()); var durationMonths = Math.abs(endDate.diff(startDate, 'months')); $('#durationMonths').text(durationMonths); // maintain value outside of change function durationYears = Math.abs(endDate.diff(startDate, 'years')); $('#durationYears').text(durationYears); if (durationMonths > 12) { $('#variablePriceOption').prop("disabled", false); } else { $('#variablePriceOption').prop("disabled", true); } // If dates changed, update variable inputs shown if ($('#variablePriceOption').is(':checked')) { if (durationMonths > 12) { $('#variable_price_input_1').val(''); $('.duration-years-input').remove(); handleVariablePricing(); } else { $('#fixedPriceOption').click(); } } } }); $('#variablePriceOption, #fixedPriceOption').change(function() { if (this.value == 'fixedPrice') { $('.variablePriceModelFormGroup').removeClass('d-block').addClass('d-none'); $('.variablePriceModelFormGroup input').each(function() { $(this).val('').attr('disabled', true); }); $('.fixedPriceModelFormGroup input').prop('disabled', false); $('.fixedPriceModelFormGroup').removeClass('d-none').addClass('d-block'); $('.duration-years-input').remove(); } else if (this.value == 'variablePrice') { $('.fixedPriceModelFormGroup').removeClass('d-block').addClass('d-none'); $('.fixedPriceModelFormGroup input').val('').attr('disabled', true); $('#variable_price_input_1').prop('disabled', false); $('.variablePriceModelFormGroup').removeClass('d-none').addClass('d-block'); handleVariablePricing(); } }); /** * Creates inputs for variable pricing.. **/ var handleVariablePricing = function() { $rowClone = $('.row-main').clone(); for (var i = 2; i <= durationYears + 1; i++) { $rowClone.prop('class', 'duration-years-input'); $rowClone.find('label').text('Price Year ' + i); $rowClone.find('input').prop('id', 'variable_price_input_' + i); $rowClone.find('input').prop('name', 'land_contract_variable_annual_price_' + i); if ($('.duration-years-input').length === 0) { $('.row-main').after($rowClone); } else { $('.duration-years-input').last().after($rowClone); } $rowClone = $('.duration-years-input').last().clone(); } }; $('button').click(function() { console.log($('#test-form').serialize()); }); });
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment-with-locales.min.js"></script> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.0/css/bootstrap.min.css" rel="stylesheet" /> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.0/js/bootstrap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script> <div class="container"> <form id="test-form"> <div class="row mt-3"> <div class="col"> <div class="form-group"> <label for="inputStartDate">Start date</label> <input type="date" class="form-control" id="inputStartDate" name="land_contract_start_date"> </div> </div> <div class="col"> <div class="form-group"> <label for="inputEndDate">End date</label> <input type="date" class="form-control" id="inputEndDate" name="land_contract_end_date"> </div> </div> </div> <div class="text-center">Months between selected dates = <span id="durationMonths"></span>. Years between selected dates = <span id="durationYears"></span>. </div> <div class="form-group"> <label for="inputPriceModel">Price model</label> <div id="inputPriceModel"> <div class="form-check"> <input class="form-check-input" type="radio" name="inputPriceModel" id="fixedPriceOption" value="fixedPrice" required checked="checked"> <label class="form-check-label" for="fixedPriceOption"> Fixed price </label> </div> <div class="form-check"> <input class="form-check-input" type="radio" name="inputPriceModel" id="variablePriceOption" value="variablePrice" disabled="disabled"> <label class="form-check-label" for="variablePriceOption"> Variable price </label> </div> </div> </div> <div class="form-group fixedPriceModelFormGroup"> <label for="fixed_price_input">Fixed price amount</label> <div class="input-group"> <input type="number" class="form-control" id="fixed_price_input" name="land_contract_fixed_annual_price"> <div class="input-group-append"> <span class="input-group-text">$</span> </div> </div> </div> <div class="form-group variablePriceModelFormGroup d-none"> <div class="row-main"> <label for="variable_price_input">Price Year 1</label> <div class="input-group"> <input type="number" class="form-control" id="variable_price_input_1" name="land_contract_variable_annual_price_1" disabled="disabled"> <div class="input-group-append"> <span class="input-group-text">$</span> </div> </div> </div> </div> </form> <button>Serialize</button> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM