Issue
I am using Flask for my website and wanted buttons to render without reloading the url, so I haphazardly copied some JQuery/AJax code and- while it works great for desktop- it is causing me issues on mobile. The buttons will not change value on mobile. I submit which value was clicked to my flask module, and return values to update the button based on what was clicked. Here is my code, starting at the forms I submit until the end of the script:
<body id="page-top">
<header class="masthead">
<div class="text-center">
<h6 class="text-white-50 mx-auto mb-3">Which song is better?</h6>
<div class="container mt-5">
<form id="songForm" data-sb-form-id="none" autocomplete="off">
<div class="row">
<div class="col-6 mb-3">
<img id="pic1" src="{{images[0]}}" class="img-fluid"/>
<input autocomplete="off" id="button1" type="submit" value="{{playlist_tracks[0]}}" class="btn text-wrap btn-primary mt-3 button-smaller" name="song"/>
</div>
<div class="col-6 mb-3">
<img id="pic2" src="{{images[1]}}" class="img-fluid"/>
<input autocomplete="off" id="button2" type="submit" value="{{playlist_tracks[1]}}" class="btn text-wrap btn-primary mt-3 button-smaller custom-button" name="song"/>
</div>
</div>
</div>
</div>
</form>
</header>
<!-- Include jQuery -->
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<script>
$(document).ready(function () {
$("#songForm").submit(function (event) {
console.log("Form submitted!");
console.log("{{id}}");
event.preventDefault(); // Prevent the form from submitting in the traditional way
var selectedSong = $(document.activeElement).val();
// Get the form data
var formData = new FormData();
formData.append('song', selectedSong);
$.ajax({
data: formData,
url: "{{id}}",
processData: false,
contentType: false,
type: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest'
},
success: function (response, status, xhr) {
console.log("Form Data:", formData);
console.log("Response:", response);
if (response.redirect_url) {
// Redirect to the specified URL
console.log("REDIRECT TRIGGERED");
window.location.href = response.redirect_url;
return; // Add a return statement to exit the function after redirection
}
// Check if redirect_url exists in the response
else {
// Continue with your existing logic
console.log("Updating buttons...");
// Check if compare_songs exists and is an array
if (Array.isArray(response.compare_songs) && response.compare_songs.length >= 2) {
// Assuming you have button IDs 'button1' and 'button2'
$('#button1').val(response.compare_songs[0]);
$('#button2').val(response.compare_songs[1]);
$('#pic1').val(response.images[0]);
$('#pic2').val(response.images[1]);
console.log("Buttons updated!");
} else {
console.error("Invalid or missing compare_songs in the response");
}
}
// Check for a 302 status code
if (xhr.status === 302) {
// Extract the new URL from the headers
var newUrl = xhr.getResponseHeader('Location');
// Use the following line only if you want to redirect using a GET request
window.location.href = newUrl;
}
},
});
});
});
</script>
I have tried several suggestions from the internet around the on.click method, but must be implementing it wrong. Not sure where to go from here without sitting down and learning a whole new language (which I guess I should do eventually...)
Solution
On a mobile browser (or touchscreen) "clicks" are simulated by the browser based on user touch events. However, sometimes the browser can incorrectly simulates a click and it may not be triggering the submit function. You can try explicitly handling form submission when the user touches the submit button:
$(document).on('click touchstart', '#button1, #button2', function(event) {
// submit function
});
Also if you want to change the src
of an img element, you should use prop
instead of val
. Val is meant to be used to set the value of a user input field. Prop is meant to be used to set a specific value for a property or attribute on an html element.
$('#pic1').prop('src', response.images[0]);
$('#pic2').prop('src', response.images[1]);
Edit:
To prevent click
and touchstart
both being called at the same time, you can bind only the applicable event:
var isTouchDevice = 'ontouchstart' in document.documentElement;
$(document).on(isTouchDevice ? 'touchstart' : 'click', '#button1, #button2', function(event) {
// submit function here
});
or you can introduce a debounce:
var lastEventTime = 0;
$(document).on('click touchstart', '#button1, #button2', function(event) {
var currentTime = new Date().getTime();
if (currentTime - lastEventTime < 500) {
return;
}
lastEventTime = currentTime;
// submit form
});
Answered By - Jacob
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.