Why is my ajax request repeating same data from Laravel controller? - javascript

Goal: load more rows from the database to a view using an ajax request when a user clicks the "load more" button. I would like the data to load without a page reload.
Problem: The data being loaded via ajax keeps repeating the same rows on every request and doesn't paginate as per standard request.
Detail: I have a view that loads 4 rows from the database which I paginate using Laravel's built-in pagination. I've added an event listener on a "load more" button which successfully sends the request to the controller, which in turn successfully returns data. The controller returns a partial view of the data I want to display. However this data doesn't seem to increment properly and keeps repeating the records shown on each request. I am not sure what I am missing here, if the problem is in the controller or in the JS?
I am not very experienced with Laravel, PHP and JS since coming from more of a web designer and UI design background and would love to really understand what I am doing wrong here.
PLEASE NO JQUERY EXAMPLES.
Partial view:
#foreach ($products as $product)
<div style="background-color:pink; width: 200px;">
<p>{{ $product->title }}</p>
<img src="/images/product/{{ $product->img }}" alt="{{ $product->title }}" style="width: 50px;">
</div>
#endforeach
Javascript:
(I am updating the button href attribute so the request URL reflects the correct query)
const container = document.querySelector('#sandbox-container');
let button = document.getElementById('load-stuff');
let url = button.getAttribute('href'); // http://127.0.0.1:8000/sandbox?page=2
let pageNum = button.getAttribute('href').substr(35,1);
button.addEventListener('click', (event) => {
event.preventDefault();
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
// if page loads successfully, replace the number at the end of the url with the incremented page number
pageNum++;
newUrl = url.replace(/page=([^d]*)/, `page=${pageNum}`);
button.setAttribute('href', newUrl);
xhr.onload = function() {
if (xhr.status === 200) {
container.insertAdjacentHTML('beforeend', xhr.responseText);
}
else {
console.log(`Request failed, this is the response: ${xhr.responseText}`);
}
};
xhr.send();
})
Controller:
public function sandbox(Request $request)
{
$products = Product::orderBy('title', 'asc')->paginate(4);
if($request->expectsJson()){
return view('sandbox-more', compact('products'));
} else {
return view('sandbox', compact('products'));
}
}

Consider this snippet for your javascript
const container = document.querySelector('#sandbox-container');
let button = document.getElementById('load-stuff');
button.addEventListener('click', (event) => {
event.preventDefault();
const xhr = new XMLHttpRequest();
let url = button.getAttribute('href');
let pageNum = button.getAttribute('data-page-number') || 0;
xhr.open('GET', url, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
// if page loads successfully, replace the number at the end of the url with the incremented page number
pageNum++;
newUrl = url + '?page=' + pageNum;
xhr.onload = function() {
if (xhr.status === 200) {
container.insertAdjacentHTML('beforeend', xhr.responseText);
button.setAttribute('data-page-number', pageNum);
}
else {
console.log(`Request failed, this is the response: ${xhr.responseText}`);
}
};
xhr.send();
})
What I've done here is to have the page number saved to a dedicated custom attribute "data-page-number". Doing "button.getAttribute('href').substr(35,1)" is inefficient. And then check the page number and increment it on the button's click event. Also, only update the "data-page-number" attribute when the request has been successful. I hope this helps

You should regenerate the pagination every time you make a request to get the correct data. Here is a very good example on doing it via jQuery. Should just adjust it to your needs since you are using pure Javascript.

Related

How can I reassign XHR without reloading the page in JavaScript?

This is a PHP Bootstrap CODE I try to dynamically change bootstrap modal body content that can I can easily add or edit product category . Then I submit the entered or changed data to save into database by submitting the form through Ajax .
I use pure JavaScript Ajax request to done this job for me.
For the first time when I click into Create Product Category Everything work fine. But when the first time content add then I try to add anther product the second product will automatically add two times it will increase for the forth time and so on .
I know the problem . But I can't solve it.
how can I reassign or how can I Completely clean Ajax after the task done then after clicking to create new product category I will renew Ajax ?
this is my JavaScript Ajax code :
// get add category
document.getElementById('add_category').addEventListener('click', () => {
var xhr = new XMLHttpRequest();
xhr.open("GET", 'add.php', true);
console.log("add_category")
xhr.onload = function() {
if (this.status == 200) {
document.getElementById('exampleModalLabel').innerHTML = 'Create Product Category';
document.getElementById('modal-body').innerHTML = this.response;
// console.log(this.response)
dynamicChangePicture()
// on change category_name
onChangeCategoryName('category_name');
// add new Category
document.getElementById('save_btn').addEventListener('click', (e) => {
e.preventDefault();
console.log('save_btn')
var xhr = new XMLHttpRequest();
xhr.open('POST', `../includes/functions.php`, true)
xhr.onload = function() {
if (xhr.status == 200) {
console.log(xhr.response)
if (xhr.response == 'category name add successfully! ') {
document.getElementById('close_modal_btn').click();
showMessage(xhr.response, 'Add')
console.log(xhr.responseText)
// document.getElementById('logo_box').innerHTML = `<span class='text-success'>${xhr.response}</span>`;
} else {
showMessage(xhr.response, 'Remove')
document.getElementById('logo_box').innerHTML = `<span class='text-danger'>${xhr.response}</span>`;
}
setTimeout(() => {
document.getElementById('table-body').innerHTML = '';
defaultLoad();
console.log("data Loaded")
}, 5000)
}
}
const formData = new FormData(document.getElementById('add_category_form'))
xhr.send(formData);
})
}
}
xhr.send();
})
even I Change inside xhr variable with the a deferent one it will still have the same problem.

Tinymce Image upload - save to database

I have configured my TinyMCE to use images_upload_url and images_upload_handler to post to a selected image to a server-side page which saves the image to a location on my server. In addition, this server-side page also saves the filename of the image as a record within a database.
I then have another server-side page which reads the database and constructs a JSON list of the images that have been uploaded. This JSON data is then pulled into my Tinymce instance using image_list, so that I can easily reuse previously uploaded images as opposed to having to reupload the same image more than once.
The specific lines of my tiny.init() are:
image_list: 'processes/image-list.php',
image_class_list: [
{title: 'None', value: ''},
{title: 'Full width image', value: 'img-responsive'}
],
images_upload_url: 'processes/upload-image.php',
images_upload_handler: function (blobInfo, success, failure) {
var xhr, formData;
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST', 'processes/upload-image-free.asp');
xhr.onload = function() {
var json;
if (xhr.status != 200) {
failure('HTTP Error: ' + xhr.status);
return;
}
json = JSON.parse(xhr.responseText);
if (!json || typeof json.location != 'string') {
failure('Invalid JSON: ' + xhr.responseText);
return;
}
success(json.location);
};
formData = new FormData();
formData.append('file', blobInfo.blob(), blobInfo.filename());
xhr.send(formData);
},
image_dimensions: false,
All of this works as expected.
What I would like to do is also save a description of the image to the database so this can be outputted as the title within the JSON data of previously uploaded images.
As the upload feature only allows an image to be selected from a file system I cannot utilise the upload feature:
So I thought I could utilise the alternate description field of the image feature/modal but this would have to be done via a JavaScript triggered event that is triggered upon submitting the image feature/modal, that takes the content in the alternative description input field and POST this to a serverside page that can update the database.
Unless there is another way does anybody know how I can target the 'click' on the 'save' button within the image feature to extract the alternate description before the image feature/modal disappears and extract the input field content?
From there I should be able to work out how to get this to a server-side page to update the database.
Many thanks in advance
I have managed to resolve this so posting a solution to help others - though this is more than a hack.
Firstly on my form page after the tiny.init is loaded I am using the following:
document.addEventListener('keyup', logKey);
function logKey(e) {
labels = document.querySelectorAll(".tox-label");
for (i = 0; i < labels.length; ++i) {
if (labels[i].textContent == "Alternative description"){
imageDescription = document.getElementById(labels[i].htmlFor).value;
}
}
};
This loops through all the elements (labels in this case) which have a class of .toxlabel and if the textContent matches "Alternative description" then to capture the value in in a variable called 'imageDescription'.
Then within my tiny.init I have the following:
editor.on('ExecCommand', function(e) {
if (e.command == "mceUpdateImage"){
var http = new XMLHttpRequest();
var params = encodeURI('desc=' + imageDescription);
http.open('POST', 'processes/upload-image-description.asp', true);
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
http.onreadystatechange = function() {//Call a function when the state changes.
if(http.readyState == 4 && http.status == 200) {
console.log(http.responseText);
}
}
http.send(params);
}
});
This code is actioned upon the mceUpdateImage modal closing, it takes the value stored within the imageDescription variable and posts it to a server-side page which updates the database.
I am sure there are cleaner ways but they would require more of a TinyMce understanding.

Ajax xhr onload not being called within django app

I have a Django app with user posts. I am trying to add a 'like' / voting system. I had done this through complete page refreshes through a redirect where the vote was made then redirected back to the same page with the new vote / like total updates. I then was reading about ajax and how I could update part of a page without a full reload.
let up_vote = document.getElementById("up-vote").addEventListener('click', () => {
console.log("clicked");
let xhr = new XMLHttpRequest();
xhr.open('GET', "{% url 'up-vote' %}", true);
console.log(xhr);
xhr.onload = () => {
console.log("inside");
};
console.log("outside");
});
So far my js looks like this. When I click on "up-vote", "clicked" is printed along with the xhr object. However, onload appears to never be called as "inside" is never printed but instead passes straight over to "outside".
I have a feeling that the issue is to do with the URL path but I don't know how to get path properly.
The basic file structure of this app is:
app
|-static/app
|-scripts/*this js file*/
|-images
|-styles
|-templates/app
|-html files
|-views.py *where the request is being made*
|-urls.py
urls.py contains,
urlpatterns = [
...
path('post/<int:pk>/up/', up_vote, name='up-vote'),
...
]
and the views.py contain,
#login_required()
def up_vote(request, pk):
print("HI")
obj = get_object_or_404(Post, pk=pk)
uid = request.user.id
if not obj.votes.exists(uid):
obj.votes.up(uid)
data = {
'votes': obj.votes.count()
}
return JsonResponse(data)
Any help or advice greatly appreciated :)
p.s. I have also tried xhr.onreadystate which is what gives to the thought of the URL path being wrong.
AJAX request (as you might have guessed from its name), is asynchronous, so it will really pass straight to 'outside'.
In addition to that, you have to call xhr.send()
let up_vote = document.getElementById("up-vote").addEventListener('click', () => {
console.log("clicked");
let xhr = new XMLHttpRequest();
xhr.open('GET', "{% url 'up-vote' %}", true);
console.log(xhr);
xhr.onload = () => {
console.log("inside");
};
xhr.send()
console.log("outside");
});
PS: I think your URL/views have issues. Your view and routes requires a pk, but your {% url 'up-vote' %} doesn't pass a pk to it

PHP is shown on wrong page

I'm recently working on a website project. Therefor I have a website.php with all html code, a function.php and saveArray.js . In website.php I'm printing a html table with a button at the bottom. Through the button click I'm getting to the saveArray.js, where I save all the table data in an array.
With this code
var arrString = JSON.stringify(tableData);
var request = new XMLHttpRequest();
request.open('post', 'function.php', true);
request.setRequestHeader('Content-Type', 'application/x-www-form-
urlencoded');
request.send('daten=' + arrString);
I post the JS array to function.php. In function.php I do something with the array and in an if statement I want to show a modal.
The modal itself works, but I want to show it on website.php page. Which doesn't happends, because I'm currently on function.php .
How can I solve this ?
EDIT: In my array is an ID and I want to check if this ID is already in my database or not. Depending on this result I want to show the modal and upload the data if necessary. All the checking is happening in function.php
I suppose you want to inject the string returned (the modal PHP code) by your function in function.php in your current page ('website.php').
To do this, you'll have to inject the response given by the XMLHttpRequest when the request is finished.
Let's suppose we want to add all the contents within
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML =
this.responseText;
}
};
See, You are not handling the response of the request.So handle the response.and restuern the status of the request from function.php and if data is saved the open the model. You need not go to the function.php page. See the code
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// this is response of the request //now check it
//Suppose you returned " data saved" as response from function.php
if(this.responseText='data saved'){
//Open model here
}
}
};
xhttp.open("POST", "function.php", true);
xhttp.send();

Webpage reloading on entering correct values

I've ran into an weird problem. I have created a login page which send data to a PHP page which return some response code like "00000" for ok "404" for not found etc. I have tested my server with Postman tool and found server is working perfectly fine. When my html send data to server server responds with response code. If the response code comes wrong html alert's it. However if I enter correct credentials and when server respond with success , My login page reloads for no reason.
Here's my javascript
function validatelog(){
var user_email_log=document.getElementById("user_email_log").value;
var user_pass_log=document.getElementById("user_pass_log").value;
if (user_email_log&&user_pass_log!=null)
{
var hr = new XMLHttpRequest();
var url = "../logic/login.php";
var vars =
"user_email_log="+user_email_log+"&user_pass_log="+user_pass_log;
hr.open("POST", url, true);
hr.setRequestHeader("Content-type", "application/x-www-form-
urlencoded");
hr.onreadystatechange = function() {
if(hr.readyState == 4 && hr.status == 200) {
var saman = hr.responseText.trim();
if(saman=="00000"){
alert(saman);
}else if (saman == "404"){
alert("Failed with 404");
}
else{
alert(saman);
}
}
}
hr.send(vars);
}
}
And my html looks like this
<input id="user_email_log"/>
<input id="user_pass_log"/>
<button onclick="validatelog();">Log in</button>
Add type="button" to the button:
<button type="button" onclick="validatelog();">Log in</button>
When it is not specified, it is the same as type="submit", and this will cause your page to reload.
if you use jquery you could do this.
$(document).on('click', 'button', function(e) {
e.preventDefault();
$.get('url')
})
I think the page is reloading because that is the default behavior.

Categories