JuZDePeche
JuZDePeche

Reputation: 789

Transform repetitive JQuery code into clean code

So I have this code but I tought it was too repetitive, anyone has an idea how I could do that? When a upload a new image, I want a new image box to show up. My solution works, but what if I would like to have 1000 new images? I can't just type one at the time. What could I do to optimise this problem?

HTML:

<div class="wrapper">
    <div class="box box_image" id="box_image_1">
        <div class="js--image-preview"></div>
        <div class="upload-options">
            <label>
                <input type="file" class="image-upload" id="image1" data-show='box_image_2' name="IgniteFormObject.Image1" accept="image/*" enctype="multipart/form-data" />
            </label>
        </div>
    </div>
    <div class="box box_image" id="box_image_2">
        <div class="js--image-preview"></div>
        <div class="upload-options">
            <label>
                <input type="file" class="image-upload" id="image2" data-show='box_image_3' name="IgniteFormObject.Image2" accept="image/*" enctype="multipart/form-data" />
            </label>
        </div>
    </div>
    <div class="box box_image" id="box_image_3">
        <div class="js--image-preview"></div>
        <div class="upload-options">
            <label>
                <input type="file" class="image-upload" id="image3" data-show='box_image_4' name="IgniteFormObject.Image3" accept="image/*" enctype="multipart/form-data" />
            </label>
        </div>
    </div>
    <div class="box box_image" id="box_image_4">
        <div class="js--image-preview"></div>
        <div class="upload-options">
            <label>
                <input type="file" class="image-upload" id="image4" data-show='box_image_5' name="IgniteFormObject.Image4" accept="image/*" enctype="multipart/form-data" />
            </label>
        </div>
    </div>
    <div class="box box_image" id="box_image_5">
        <div class="js--image-preview"></div>
        <div class="upload-options">
            <label>
                <input type="file" class="image-upload" id="image5" name="IgniteFormObject.Image5" accept="image/*" enctype="multipart/form-data" />
            </label>
        </div>
    </div>
</div>

Javascript:

When an image is uploaded, this JQuery is called.

$('#image1').change(function (ev) {
    $("#box_image_2").show();
});

$('#image2').change(function (ev) {
    $("#box_image_3").show();
});

$('#image3').change(function (ev) {
    $("#box_image_4").show();
});

$('#image4').change(function (ev) {
    $("#box_image_5").show();
});

Upvotes: 1

Views: 130

Answers (5)

Louys Patrice Bessette
Louys Patrice Bessette

Reputation: 33933

Strictly based on your markup and how you had unique ids for each elements...

The key is to retreive that id from the parent container and increment by one to show the next.

// Hide all containers except the first, on load (possibly already achieved via CSS)
$("[id^='box_image_']").not(":first").hide();

// Change handler
$("[id^='image']").change(function(ev) {

  // Retreive the index part of the container's id
  var parent_box_image_id = $(this).closest("[id^='box_image_']").attr("id").split("box_image_")[1];
  console.log(parent_box_image_id);
  
  // Increment by one
  parent_box_image_id++;

  // Show the next one!
  $("#box_image_"+parent_box_image_id).show();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="wrapper">
  <div class="box box_image" id="box_image_1">
    <div class="js--image-preview"></div>
    <div class="upload-options">
      <label>
          <input type="file" class="image-upload" id="image1" data-show='box_image_2' name="IgniteFormObject.Image1" accept="image/*" enctype="multipart/form-data" />
      </label>
    </div>
  </div>
  <div class="box box_image" id="box_image_2">
    <div class="js--image-preview"></div>
    <div class="upload-options">
      <label>
        <input type="file" class="image-upload" id="image2" data-show='box_image_3' name="IgniteFormObject.Image2" accept="image/*" enctype="multipart/form-data" />
      </label>
    </div>
  </div>
  <div class="box box_image" id="box_image_3">
    <div class="js--image-preview"></div>
    <div class="upload-options">
      <label>
        <input type="file" class="image-upload" id="image3" data-show='box_image_4' name="IgniteFormObject.Image3" accept="image/*" enctype="multipart/form-data" />
      </label>
    </div>
  </div>
  <div class="box box_image" id="box_image_4">
    <div class="js--image-preview"></div>
    <div class="upload-options">
      <label>
        <input type="file" class="image-upload" id="image4" data-show='box_image_5' name="IgniteFormObject.Image4" accept="image/*" enctype="multipart/form-data" />
      </label>
    </div>
  </div>
  <div class="box box_image" id="box_image_5">
    <div class="js--image-preview"></div>
    <div class="upload-options">
      <label>
        <input type="file" class="image-upload" id="image5" name="IgniteFormObject.Image5" accept="image/*" enctype="multipart/form-data" />
      </label>
    </div>
  </div>
</div>


But there could be another way to do the same more efficiently... Like squarely forgetting about the ids and use classes... Have a look at this other snippet below. ;)

// Hide all containers except the first, on load (possibly already achieved via CSS)
$(".box_image").not(":first").hide();

// Change handler
$(".image-upload").change(function(ev) {
  $(this).closest(".box_image").next().show();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="wrapper">
  <div class="box box_image" class="box_image">
    <div class="js--image-preview"></div>
    <div class="upload-options">
      <label>
          <input type="file" class="image-upload" name="IgniteFormObject[]" accept="image/*" enctype="multipart/form-data" />
      </label>
    </div>
  </div>
  <div class="box box_image" class="box_image">
    <div class="js--image-preview"></div>
    <div class="upload-options">
      <label>
        <input type="file" class="image-upload" name="IgniteFormObject[]" accept="image/*" enctype="multipart/form-data" />
      </label>
    </div>
  </div>
  <div class="box box_image" class="box_image">
    <div class="js--image-preview"></div>
    <div class="upload-options">
      <label>
        <input type="file" class="image-upload" name="IgniteFormObject[]" accept="image/*" enctype="multipart/form-data" />
      </label>
    </div>
  </div>
  <div class="box box_image" class="box_image">
    <div class="js--image-preview"></div>
    <div class="upload-options">
      <label>
        <input type="file" class="image-upload" name="IgniteFormObject[]" accept="image/*" enctype="multipart/form-data" />
      </label>
    </div>
  </div>
  <div class="box box_image" class="box_image">
    <div class="js--image-preview"></div>
    <div class="upload-options">
      <label>
        <input type="file" class="image-upload" name="IgniteFormObject[]" accept="image/*" enctype="multipart/form-data" />
      </label>
    </div>
  </div>
</div>

Upvotes: 0

Maheer Ali
Maheer Ali

Reputation: 36574

You can try this method using for loop.

  • Create a for loop
  • Inside the loop set change function to image${i}.
  • And inside the change function call show() on box_image_${i+1}

I also used Template Literals in my code

for(let i = 1;i<=4;i++){
   $(`#image${i}`).change(function (ev) {
      $(`#box_image_${i+1}`).show();
   })
}

Upvotes: 1

Sergo Kupreishvili
Sergo Kupreishvili

Reputation: 462

You can simply use classes like this:

$('.image').change(function (ev) {
    $(this).next(".box_image").show();
});

Upvotes: 1

brk
brk

Reputation: 50291

You can use data attribute and multiple selector. In the data attribute pass the id of the element which you want to show & on change get that attribute

$('#image1,#image2,#image3,#image4').on('change', function(ev) {
  let toShow = $(this).data('show');
  console.log(toShow);
  // $('#'+toShow).show();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id='image1' type='checkbox' data-show='box_image_2'>
<input id='image2' type='checkbox' data-show='box_image_3'>
<input id='image3' type='checkbox' data-show='box_image_4'>
<input id='image4' type='checkbox' data-show='box_image_5'>

You can also use wildcard selector where id begins with image

$('input[id^="image"]').on('change', function(ev) {
  let toShow = $(this).data('show');
  console.log(toShow);
  // $('#'+toShow).show();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id='image1' type='checkbox' data-show='box_image_2'>
<input id='image2' type='checkbox' data-show='box_image_3'>
<input id='image3' type='checkbox' data-show='box_image_4'>
<input id='image4' type='checkbox' data-show='box_image_5'>

Upvotes: 3

circusdei
circusdei

Reputation: 1967

Stick it in a loop?

for(var i = 1; i <= 4; i++){
    $('#image'+i).change(function (ev) {
        $("#box_image_"+(i+1)).show();
    });

}

Upvotes: 0

Related Questions