EnhanceTo ensures that every added element is distinct while making use of the identical jQuery

I'm curious if it's feasible to make each new div unique on each appendTo call but still utilize the same jQuery functionality.

As shown in the markup below, every new div shares the same jQuery code and therefore doesn't work independently.

In my JavaScript, I'm selecting the ID to trigger each function.

I attempted to simply add + 1, etc at the end of each ID, but that changes the ID name causing the newly created DIV not to work.

I've considered using DataAttributes, but then I'd still face the issue of having to create multiple functions all performing the same task.

Any suggestions or solutions?

Thank you

$(function() {
  var test = $('#p_test');
  var i = $('#p_test .upl_drop').length + 1;

  $('#addtest').on('click', function() {
    $('<div class="file-input"><div class="input-file-container upl_drop"><label for="p_test" class="input-file-trigger">Select a file...<input type="file" id="p_test" name="p_test_' + i + '" value=""class="input-file"></label></div><span class="remtest">Remove</span><p class="file-return"></p></div>').appendTo(test);
    i++;
  });


  $('body').on('click', '.remtest', function(e) {
    if (i > 2) {
      $(this).closest('.file-input').remove();
      i--;
    }
  });
});


var input = document.getElementById( 'file-upload' );
var infoArea = document.getElementById( 'file-upload-filename' );

input.addEventListener( 'change', showFileName );

function showFileName( event ) {

  // the change event gives us the input it occurred in
  var input = event.srcElement;

  // the input has an array of files in the `files` property, each one has a name that you can use. We're just using the name here.
  var fileName = input.files[0].name;

  // use fileName however fits your app best, i.e. add it into a div
  textContent = 'File name: ' + fileName;

  $("#input-file-trigger").text(function () {
      return $(this).text().replace("Select a file...", textContent);
  });
}
/*
#### Drag & Drop Box ####
*/

.p_test{
  display: inline-block;
}

.upl_drop{
  border: 2px dashed #000;
  margin: 0px 0px 15px 0px;
}

.btn--add p{
  cursor: pointer;
}

.input-file-container {
  position: relative;
  width: auto;
}
.input-file-trigger {
  display: block;
  padding: 14px 45px;
  background: #ffffff;
  color: #1899cd;
  font-size: 1em;
  cursor: pointer;
}
.input-file {
  position: absolute;
  top: 0; left: 0;
  width: 225px;
  opacity: 0;
  padding: 14px 0;
  cursor: pointer;
}
 .input-file:hover + .input-file-trigger,
 .input-file:focus + .input-file-trigger,
 .input-file-trigger:hover,
 .input-file-trigger:focus {
  background: #1899cd;
  color: #ffffff;

}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="p_test" id="p_test">
  <div class="file-input">
    <div class="input-file-container upl_drop">
      <input class="input-file" id="file-upload" type="file">
      <label tabindex="0" for="file-upload" id="input-file-trigger" class="input-file-trigger">Select a file...</label>
    </div>
    <div id="file-upload-filename"></div>
  </div>
  <button class="btn--add" id="addtest">
          Add
  </button>
</div>

Answer №1

Avoid using incremental id attributes as they can be difficult to maintain and add unnecessary complexity to the logic.

Instead, it is recommended to use common classes along with DOM traversal to establish relationships between elements, especially those triggering events.

In this scenario, you can utilize closest() to locate the parent container with the class .file-input, and then use find() to target specific elements within that container based on their class. Consider the following example:

$(function() {
  var $test = $('#p_test');

  $('#addtest').on('click', function() {
    var $lastGroup = $test.find('.file-input:last');
    var $clone = $lastGroup.clone();
    $clone.find('.input-file-trigger').text('Select a file...');
    $clone.insertAfter($lastGroup);
  });

  $test.on('click', '.remtest', function(e) {
    if ($('.file-input').length > 1) 
      $(this).closest('.file-input').remove();
  }).on('change', '.input-file', function(e) {
    if (!this.files)
      return;
      
    var $container = $(this).closest('.file-input');
    $container.find(".input-file-trigger").text('File name: ' + this.files[0].name);
  });
});
.p_test {
  display: inline-block;
}

.upl_drop {
  border: 2px dashed #000;
  margin: 0px 0px 15px 0px;
}

.btn--add p {
  cursor: pointer;
}

.input-file-container {
  position: relative;
  width: auto;
}

.input-file-trigger {
  display: block;
  padding: 14px 45px;
  background: #ffffff;
  color: #1899cd;
  font-size: 1em;
  cursor: pointer;
}

.input-file {
  position: absolute;
  top: 0;
  left: 0;
  width: 225px;
  opacity: 0;
  padding: 14px 0;
  cursor: pointer;
}

.input-file:hover+.input-file-trigger,
.input-file:focus+.input-file-trigger,
.input-file-trigger:hover,
.input-file-trigger:focus {
  background: #1899cd;
  color: #ffffff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="p_test" id="p_test">
  <div class="file-input">
    <div class="input-file-container upl_drop">
      <input class="input-file" type="file">
      <label tabindex="0" for="file-upload" class="input-file-trigger">Select a file...</label>
    </div>
    <div class="file-upload-filename"></div>
  </div>
  <button class="btn--add" id="addtest">Add</button>
</div>

I have also made some optimizations to the code. The script now creates a clone of the last available .file-input container when the Add button is clicked. This separation of HTML and JS improves maintainability and updates in the future.

Additionally, I replaced plain JS event handlers with jQuery for consistency and ease of writing code since jQuery is already included on the page.

Lastly, note that there is no need to pass a function to text() when replacing existing content. Simply providing the new text suffices.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing jQuery to handle string manipulation via AJAX POST requests

I have been working on developing a checkbox-based filter operation for a website. This feature includes multiple checkboxes that filter a list of records based on different parameters, similar to the implementation found here. So far, I have made progress ...

Tips for modifying the appearance of this input document

Hey there, I have this input element created in React: <span className="btn-file" type='button'> <div style={{display:'flex',justifyContent:'space-around'}}> <span style ...

Eliminate all key-value pairs from an array of objects except for the specified key-value pair

I've got an array filled with objects const myArr = [ {k1: 1, k2: 1, k3: 3, k4: 4}, {k1: 1, k2: 2, k3: 3, k4: 4}, {k1: 1, k2: 2, k3: 3, k4: 4}, {k1: 1, k2: 2, k3: 3, k4: 4} ] I'm attempting to filter these objects, although I don&apos ...

Tips for repairing a horizontal line at the bottom of the <TD> tag and placing text on top

I am working with an HTML table that contains a single TR tag and two TD tags. Each TD has two HR tags creating horizontal lines, along with some text. I am looking for a way to keep the text aligned at the top of the TD and the horizontal line at the bott ...

Add a dollar sign to the output value of the jQuery UI slider to display currency symbols

I have been working on a slider feature that successfully displays values to the user. However, I am looking to modify it so that the displayed values always have a "$" symbol in front of them. $("#slider").slider({ min: 0, ...

Retrieving selected checkbox value using Bootstrap and jQuery

Hi there! I am currently working on a form where I need to check if a checkbox is selected, and if it is, I want to pass that data into a hidden field as the value for my form submission. The code snippet below shows what I have so far: ### Update User Pr ...

Switch out one picture for another by hovering over it

Looking for a way to replace the holder-01-small.png image with one of the same dimensions on hover without altering the HTML code. Here is the code snippet: <div class="mix category-1"> <a href="img/holder-01-large.png" class="photo"> <i ...

Issue with Bootstrap 4: Dropdown menu extends beyond the edge of the screen towards the right side

I'm having trouble with the dropdown items extending off the page. I've tried a few solutions from BS3 but they don't seem to be working for me. I suspect it might have something to do with the ml-auto class. (please disregard the if-else st ...

What steps can be taken to avoid an abundance of JS event handlers in React?

Issue A problem arises when an application needs to determine the inner size of the window. The recommended React pattern involves registering an event listener using a one-time effect hook. Despite appearing to add the event listener only once, multiple ...

Ways to prevent a single element from being included in the selection of the entire

Here is my question: I am facing an issue with a context menu that should only disappear when clicking outside of a specific row within that menu. The element I want to exclude, with the id "except", is buried deep within multiple parent elements in my co ...

Enhance the readability and writability of the properties of JavaScript objects

I'm curious if there's a way to make existing properties of JavaScript objects immutable after they've been assigned. Essentially, what I want is to lock in the current properties of an object but still allow new ones to be added. Can exis ...

A guide to personalizing the woocommerce 'best-selling items' widget

WooCommerce widgets are great, but I'm struggling to customize the styling. Can anyone lend a hand? ...

Steps to dynamically modify a class upon clicking

Imagine having a sequence of div elements: <div id='d-1' class='hidden'>this one<br /> <button onclick='next();'>Go to Next</button> </div> <div id='d-2' class='show'&g ...

Is it possible for me to send transactions asynchronously using polkadot-js?

After thoroughly going through the official documentation, I stumbled upon a page discussing how to transfer using polkadot-js const transfer = api.tx.balances.transfer(BOB, 12345); const hash = await transfer.signAndSend(alice); I am curious if it' ...

Refreshing or loading hidden divs with jQuery buttons when they are revealed

I am looking for a solution to optimize my series of buttons that show and hide divs. Specifically, I want the data in each hidden div to only load once the corresponding button is pressed. In other words, the hidden divs should refresh or load their data ...

A comprehensive guide to effectively formatting Recharts in React: addressing alignment and size management!

While attempting to style two graphs as floating cards, I am encountering difficulties in controlling the sizing and centering of the graphs. Specifically, I am having trouble with the pie chart in this example. To address this issue, I am passing paramete ...

Assistance with Ajax for content loading

Greetings, I am encountering an issue with the following code snippet (located in a js file named ajax.js) $(function(){ $("#loading").hide(); $("ul#nav a").click(function(){ page = "content/"+$(this).attr('href') ...

Tips for utilizing maps in a react component within a Next.js application

I received an array of data from the backend that I need to display on a React component. home.js import Head from "next/head"; import Header from "../src/components/Header"; import * as React from 'react'; import { styled } ...

The AJAX request functions properly when triggered by the .click() method, however, it encounters issues with

This particular code snippet is effective: <form id="myform" action="" method=""> <input type="email" class="form-control" name="inputEmail" id="inputEmail" placeholder="Email address"> <input type="password" class="form-control" na ...

Using jQuery to loop through a collection

I have a page that displays a list of posts. When a user clicks on the show comments button for a particular post, the comments associated with that post become visible. This functionality is achieved by using this and then searching based on the click loc ...