I have a list of similar <div>
elements created with a for
loop. For each of these <div>
elements, I have a button to edit information. Every time this edit button is clicked, a pop-up opens containing a Dropzone box (using the Dropzone library). Now, to load images related to each <div>
, I change the input value associated with the image ID using jQuery.
However, I need to read the changed ID from the input and use it in the Dropzone’s init
function. The issue is that the Dropzone was created before changing the input value, and during the initial page load, it has an empty value. I want to re-run the Dropzone init
function with the same configuration as the previous one after each click on the edit button.
I will now post the code snippets for reference.
HTML File:
@foreach($steps as $step)
<div class="row card p-3 mb-3 d-flex justify-content-center">
<div class="col-12 row justify-content-between align-self-center mb-2">
<div class="col-6 p-0">
<button type="button" class="btn update_step" title="update"
data-toggle="modal" data-target="#update_step_modal"
step_number="{{$step->number}}"
route="{{route('panel.contents.clusters.steps.update', [$content->id,
$cluster->id, $step->id])}}">
<span class="mdi mdi-18px mdi-square-edit-outline"></span>
</button>
</div>
</div>
<div class="col-12 row justify-content-center align-self-center mb-2">
<p class="col-12 step_description_p">{{$step->description}}</p>
<div class="col-6 justify-content-center pt-4">
<input class="step_cover_id" value="{{$step->cover_id}}" hidden>
<img src="{{$step->cover_image}}">
</div>
</div>
</div>
@endforeach
Modal HTML File:
<div class="modal fade" id="update_step_modal" tabindex="-1" role="dialog" aria-
labelledby="update_step_modal" aria-hidden="true" data-keyboard="false" data-
backdrop="static">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="col-12 row justify-content-center align-self-center">
<form action="" method="POST" id="update_step_form">
@method('PATCH')
@csrf
<textarea name="description" id="update_step_description"></textarea>
<input name="cover_id" id="update_step_cover_id" hidden>
<input name="video_id" id="update_step_video_id" hidden>
</form>
</div>
<div class="col-12 row justify-content-center align-self-center mb-2">
<div class="col-6" id="update_step_cover_div">
<form action="{{url('panel/upload')}}" method="POST"
class="dropzone" id="update_step_cover_form">
@csrf
<input name="type" value="step_cover" hidden />
<input name="content_id" value="{{$content->id}}" hidden />
<input name="cluster_id" value="{{$cluster->id}}" hidden />
<div class="dz-message" data-dz-message>
<span class="m-dropzone__msg-desc">some messages</span>
</div>
</form>
</div>
</div>
<div class="d-flex justify-content-center">
<button type="button" class="btn" id="step_update_button">
<span class="ladda-label">update</span>
<span class="ladda-spinner"></span>
</button>
</div>
</div>
</div>
</div>
</div>
JavaScript File:
$('.update_step').on('click', function () {
let step_number = $(this).attr('step_number')
let route = $(this).attr('route')
$('#edited_step_number').text(step_number)
$('#update_step_form').attr('action', route)
let parent = $(this).parent().parent().parent();
let description = parent.find('.step_description_p').text();
let cover_id = parent.find('.step_cover_id').val();
let video_id = parent.find('.step_video_id').val();
$('#update_step_description').val(description).change();
$('#update_step_cover_id').val(cover_id).change();
$('#update_step_video_id').val(video_id).change();
});
Dropzone.options.updateStepCoverForm = {
paramName: "file",
uploadMultiple: false,
acceptedFiles: "image/*,",
maxFiles: 1,
headers: {
'X-CSRF-Token': $('input[name="_token"]').val(),
'Accept': 'application/json'
},
addRemoveLinks: true,
init: function() {
let coverDropzone = this;
let id = $('#update_step_cover_id').val()
if(id !== ''){
$.ajax({
url: '/panel/fetch_file/' + id,
type: 'get',
dataType: 'json',
success: function (response) {
var mockFile = {name: response.data.file_name, size: response.data.size};
coverDropzone.emit("addedfile", mockFile);
coverDropzone.emit("thumbnail", mockFile, response.data.file_path);
coverDropzone.emit("complete", mockFile);
coverDropzone.options.maxFiles = 0;
}
});
}
this.on("removedfile", file => {
let id = $('#update_step_cover_id').val()
remove_file_function(id, "update_cover")
});
},
accept: function(file, done) {
done();
},
success: function (file, response) {
$('#update_step_cover_id').val(response.data.id).change();
},
error: function (file, response) {
error_function(file, response)
}
};
Reinitializing Dropzone to Reflect New Input Values
You are dealing with the challenge of updating the Dropzone component after modifying the cover_id
input value. The issue here is that the Dropzone component reads the input field value only during its initial setup. If you change the input value later, such as when clicking the update_step
button, the Dropzone won’t recognize this change unless you reinitialize it.
-
Dynamically create the Dropzone component: Instead of sticking to Dropzone’s declarative setup via
Dropzone.options.updateStepCoverForm
, you have the option to dynamically craft and dismantle the Dropzone component as needed. -
Reinitialize Dropzone on Button click: Each time you press the
update_step
button once you’ve configured the input values you go ahead and remove the previous Dropzone (if there’s one) and then proceed to generate a fresh one. This approach makes sure that the updated input value is recognized by the newly created Dropzone’sinit
function.
Updated Code:
// Remove this static configuration
// Dropzone.options.updateStepCoverForm = { ... };
// Variable of the current Dropzone instance
let coverDropzone;
$('.update_step').on('click', function() {
// TODO: [your previous code here]
// After setting the new input values reinitialize Dropzone
initializeDropzone();
});
function initializeDropzone() {
// If there is already an existing Dropzone instance it gets destroyed
if (coverDropzone) {
coverDropzone.destroy();
}
// Creates a new Dropzone instance
coverDropzone = new Dropzone("#update_step_cover_form", {
paramName: "file",
uploadMultiple: false,
acceptedFiles: "image/*,",
maxFiles: 1,
headers: {
'X-CSRF-Token': $('input[name="_token"]').val(),
'Accept': 'application/json'
},
addRemoveLinks: true,
init: function() {
// TODO: [put your existing init function code here]
},
accept: function(file, done) {
done();
},
success: function(file, response) {
$('#update_step_cover_id').val(response.data.id).change();
},
error: function(file, response) {
error_function(file, response);
}
});
}
initializeDropzone();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Update:
It’s probable that the problem you’re mentioning occurs because, even though you’ve destroyed and reinitialized the Dropzone instance, the DOM elements (i.e., the file previews that were previously fetched) created by the previous instance may still persist.
To address this issue, you can manually eliminate the previews when you destroy the Dropzone instance.
Below is an altered rendition of your code that should handle the clearing of previews:
Your modified code:
$('.update_step').on('click', function () {
...
... // Your previous code stays here
// Destroys previous Dropzone instance
if (Dropzone.instances.length > 0) {
const dropzoneInstance = Dropzone.forElement("#update_step_cover_form");
// Clears the previews
dropzoneInstance.removeAllFiles(true);
dropzoneInstance.destroy();
}
// Reinitializes the Dropzone with updated configurations
new Dropzone("#update_step_cover_form", {
...
... // The rest of your Dropzone configurations stay here
});
});
Why not use a class name instead of an ID so you can have multiples on the same page?
Because every time this page is loaded, an API is called for each image (in some stages, video) and this increases the page load. This is while with this work, only one or two APE calls may be made. @ChrisBarr
Maybe reinitialize Dropzone on button click?
How can I do that? @AztecCodes
@NegarJavadzadeh When you hit the
update_step
button, once you’ve configured the input values, you remove the previous Dropzone (if it’s there), and then proceed to construct a fresh one. This ensures that the revised input value is picked up by the init function of the new Dropzone.Show 2 more comments