Delete / Destroy using a link and Laravel 5 - javascript

I could have sworn I had this working at one point but now I'm pulling my hair out trying to figure out why it won't. I found this great script which inserts a hidden form next to a delete link and then submits the form with the necessary token. I posted a message on the git site but no response.
I've set it up exactly as it suggests and looking through the DOM I can see the form is there, inserted. I've done some alerts to make sure it sees the token correctly but every time I get:
TokenMismatchException in VerifyCsrfToken.php line 46:
If I put an old standard Laravel delete form it works fine, I just can't seem to get this script to work like it should. No other javascript errors or issues that I can find.
Here's the script with the code at the top that I added to my page:
<a href="posts/2" data-method="delete"> <---- We want to send an HTTP DELETE request
- Or, request confirmation in the process -
<a href="posts/2" data-method="delete" data-confirm="Are you sure?">
Add this to your view:
<script>
window.csrfToken = '<?php echo csrf_token(); ?>';
</script>
<script src="/js/deleteHandler.js"></script>
*/
(function() {
var laravel = {
initialize: function() {
this.registerEvents();
},
registerEvents: function() {
$('body').on('click', 'a[data-method]', this.handleMethod);
},
handleMethod: function(e) {
var link = $(this);
var httpMethod = link.data('method').toUpperCase();
var form;
// If the data-method attribute is not PUT or DELETE,
// then we don't know what to do. Just ignore.
if ( $.inArray(httpMethod, ['PUT', 'DELETE']) === - 1 ) {
return;
}
// Allow user to optionally provide data-confirm="Are you sure?"
if ( link.data('confirm') ) {
if ( ! laravel.verifyConfirm(link) ) {
return false;
}
}
form = laravel.createForm(link);
form.submit();
e.preventDefault();
},
verifyConfirm: function(link) {
return confirm(link.data('confirm'));
},
createForm: function(link) {
var form =
$('<form>', {
'method': 'POST',
'action': link.attr('href')
});
var token =
$('<input>', {
'name': '_token',
'type': 'hidden',
'value': window.csrfToken
});
var hiddenInput =
$('<input>', {
'name': '_method',
'type': 'hidden',
'value': link.data('method')
});
return form.append(token, hiddenInput)
.appendTo('body');
}
};
laravel.initialize();
})();

As haakym suggested, one solution is Unobtrusive JavaScript. While implementing that I realized I had an old version of a delete handler in another js file that was conflicting with my deleteHandler.
As usual many ways to achieve the same solution. Thanks for the input haakym.

Related

toggle button coded with javascript in blade file cannot save status in database

in my blade file (written in PHP with a javascript section) I am trying to update an SQLite database field depending on the status of like, unlike button.
I tried to use some code I found on the pusher website (realtime-likes-laravel), but the snip that is supposed to update the DB is not working, the button changes status but it does not keep the status (when I refresh it the status is back to like and it does not keep unlike active).
I believe that the issue is the lack of connection with the DB, unfortunately, I am not a Java dev, so I am not sure how to do it properly.
This is my button in the Blade file
id }}">Like
This is my js section where I toggle
<script>
var toggleButtonText = {
Like: function(button) {
button.textContent = "Unlike";
},
Unlike: function(button) {
button.textContent = "Like";
}
};
var actOnPushB = function (event) {
var action = event.target.textContent;
toggleButtonText[action](event.target);
};
</script>
the page shows the button and the button toggles without any issue, but when I refresh the button is back to like status, also the DB is not updated.
I need the field likes_count in my database table answer to increment from 0 to 1 when liked and from 1 to 0 when unliked.
Ok, I worked with a friend who is a JS dev and he helped me to understand how to do the like / unlike buttons.
#section('js')
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script>
$(document).ready(function() {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
/* selector is like CSS selectors, it recalls the class automatically when it finds it in the code */
/*
* <div id="content"></div> --> $('#content')
* <input data-id="4" /> --> $('input[data-id="4"]')
*
* */
$('.like-button').click(function () {
var button = $(this);
var status = parseInt(button.attr('data-status'));
if(status==0) {
button.html('Unlike');
status = 1;
}
else{
button.html('Like');
status = 0;
}
$.ajax({
type: 'post',
url: 'toggleLike',
data: {answer_id:button.attr('data-id'), status:status},
success: function(data){
button.attr('data-status', status);
}
});
});
});
</script>
#endsection
in the PHP part, I added this to reference the page that will be used for the toggle
</a>
<button class="like-button" data-status="{{$answer->likes_count}}" data-id="{{ $answer->id }}">#if($answer->likes_count>0){{'Unlike'}}#else{{'Like'}}#endif</button>
</div>
then in the controller I added the function to handle the button toggling.
public function like(Request $request, $id)
{
$action = $request->get('action');
switch ($action) {
case 'Like':
Answer::where('id', $id)->increment('likes_count');
break;
case 'Unlike':
Answer::where('id', $id)->decrement('likes_count');
break;
}
return '';
}
the last part was to add to the web routes the following line :
Route::post('/question/toggleLike', 'AnswerController#toggleLike')->name('answers.toggleLike');
and that was it.
Do not judge if this code is useful or not, it was for homework so only the logged-in user can answer the questions, create the questions and like the answers he gave to his own question.

Previous data being added rather than replaced with current editing data

Trying to create a simple crud operation using edit and delete. Currently on edit functionality.
Functionality works like this:
1) user clicks on edit icon, bootstrap modal opens up with form information that is fetched from ajax request containing users id. Forms value fields are auto populated based on fetched ajax request.
2) User can edit the auto populating form fields editing the users information and a separate ajax request goes out that edits the users record.
Problem:
This all works how I wanted to but I noticed a small bug that I'm stuck on to where when I go edit a users information, hit send and then close out of the modal to open and edit another users information and hit send again, the previous forms data is added onto the data I'm currently editing and I don't want that. I just want to open up the modal and edit and send the current users data that I'm on.
In addition, I also noticed If I keep trying to edit multiple users information, multiple ajax requests are sent each time I try and edit another record. I tried looking up my problem and I think it's because of my events bubbling up in which I tried e.stopPropagation; and return false; and it did nothing to solve my problem. I feel like I'm close but there is something that I'm missing.
If you need my HTML code as well I'll be happy to show that.
Here is my code:
$(document).on('click', 'i.fas.fa-edit', function(userId){
emailField.value = 'Please wait...!';
fullnameField.value = 'Please wait...!';
areaField.value = 'Please wait...!';
personField.value = 'Please wait...!';
// By Default
adminAccess.checked = false;
personField.style.display = 'block';
adminAccess.addEventListener('click', function(){
if(adminAccess.checked == true) {
areaField.style.display = "none";
} else {
personField.style.display = "block";
}
});
var usersId = {
usersId: userId.target.id
}
// Select user data
$.ajax({
method: 'POST',
url: 'select-user-action.php',
data: usersId,
success: function(data){
var parseData = JSON.parse(data);
parseData.forEach(function(element){
emailField.value = element.email;
fullnameField.value = element.name;
areaField.value = element.areaField;
personField.value = element.personField;
});
}
});
});
$('#editModal').on('show.bs.modal', function () {
submitForm.addEventListener('submit', function(e){
// prevent form from submitting
e.preventDefault();
var editData = {
"email": emailField.value,
"fullName": fullnameField.value,
"areaField": areaField.value,
"personField": personField.value
};
// Previous data is being added onto current edited data.. This is what I'm stuck on.
console.log(editData);
// $.ajax({
// method: 'POST',
// url: 'edit-user-action.php',
// data: editData,
// success: function(data){
// console.log(data);
// }
// });
// this didnt work
return false;
});
});

Ajax requests getting appended on multiple hits

In case the user fills some invalid data, an ajax request is fired and error message is displayed. Now when the user again corrects the data/or enters invalid data again, 2 requests are fired, the next time 3 and it keeps on adding up.
This is probably because of the parsley js library. If I remove parsley code it works fine. Any idea?
Here is the ajax code
$('#upload-profile-button').on('click', function(e) {
$("#upload-profile-form").parsley().validate();
$("#upload-profile-form").parsley().on('form:validate', function (formInstance) {
var isFormValid = formInstance.isValid();
if(isFormValid){
e.preventDefault();
$('#upload-profile-button').html('Uploading...');
var fd = new FormData($("#upload-profile-form")[0]);
$.ajax({
type : 'POST',
url : '/mbatch/batch/uploadBatch',
data : fd,
processData : false,
contentType : false,
beforeSend : function() {
},
success : function(response) {
if (response.data.fetchTpodSuccess == true) {
window.location.href= "/mbatch/batch/listBatch";
} else {
new PNotify({
title: 'Notice',
text: response.message,
type: 'error',
styling: 'bootstrap3'
});
$('#upload-profile-button').html('Submit');
}
},
error : function(data) {
new PNotify({
title: 'Notice',
text: JSON.parse(data.responseText).message,
type: 'error',
styling: 'bootstrap3'
});
$('#upload-profile-button').html('Submit');
}
});
}
});
});
Here is the HTML code snippet
<button id="upload-profile-button" type="button"
class="btn btn-primary">Submit</button>
Any leads would be highly appreciated.
I just found out the solution.
This was because I was using data-parsley-validate in the form tag as well
and in the js as well
<form id="upload-profile-form" data-parsley-validate enctype="multipart/form-data"
name = "uploadBatchForm"
class="form-horizontal form-label-left"
>
Parsley looks at all data-parsley-validate occurrences in DOM on document load and automatically binds them if valid.
Once a form or field instance is bound by Parsley, doing $('#form').parsley(options); will update the existing options but not replace them.
Source - http://parsleyjs.org/doc/index.html
Maybe you render your script after each call, so it could append your click function to the click event multiple times.
If this is the case, first try to unbind your click event before appending one like this:
$('#upload-profile-button').unbind('click').on('click',...

Building query string GET vars dynamically

I'm head below water on this, using Laravel I have a search page of which ajax calls a url and updates the html for filter by the way of html links which contain get vars ($(this).attr('href'); which contains ?var=test sent via ajax) to return filtered results. As ajax this doesn't update the url I'm using history.replaceState to update that.
Now here's my issue, the links which be shown as buttons (using BS) - so my link href will include the ?thisbuttonvar=whatever BUT if that get var already exists then the link href should not include ?thisbuttonvar=whatever it should remove it
I have created a function to try to handle this as follows (sorry I can't get it to paste properly):
function href_append_query($param) {
parse_str($_SERVER["QUERY_STRING"], $query_array);
if (array_key_exists(current(array_keys($param)), $query_array))
{
$key = current(array_keys($param));
if ($param[$key] == $query_array[$key])
{
unset($query_array[$key]);
}
}
else
{
$query_array = $query_array + $param;
}
$query = http_build_query($query_array);
return '?' . $query; }
The issue with this is when I do a
#foreach ($category->subCategories()->get() as $sub_category)
<li><a class="search-filter" href=<?=href_append_query(['sub_category' => $sub_category->sub_category_url])?>>{!! $sub_category->sub_category !!}</a></li>
It works for the first link, but all the rest of my href's come back the same (as the first one that enters the function)
Can anyone assist in getting this function to work so the foreach link has the appropriate href OR an entirely different "easier" way all together :)
My jQuery if it helps paint a better picture
$(document).on("click", '.search-filter', function(e) {
e.preventDefault();
$('#spinner-modal').modal('show');
$('#spinner-modal p').html('<b>Searching,</b> please wait...<br />');
query = $(this).attr('href');
history.replaceState(null, null, query);
$.ajax({
type: "GET",
url : query,
success : function(data, status){
$('#job-results').html(data);
$('#spinner-modal').modal('hide');
},
error : function(status){
console.log(status);
},
});
});

Troubles Submitting Form programmatically

I have a simple page that takes a form and makes a jsonp ajax request and formats the response and displays it on the page, this is all fine, but I wanted to add it so that if the form was populated (via php $_GET variables) then the form would auto-submit on page load but what happens instead is that the page constantly refreshes despite the submit function returning false.
Submit Button (just to show it doesn't have an id like submit or anything)
<button type="submit" id="check" class="btn btn-success">Check</button>
jQuery
$(document).ready(function() {
$('#my_form').on('submit', function() {
var valid = 1;
$('#my_form .required').each(function() {
if ($(this).val() == '') {
$(this).parents('.form-group').addClass('has-error');
valid = 0;
} else {
$(this).parents('.form-group').removeClass('has-error');
}
});
if (valid === 1) {
$.ajax({
url: '/some_url',
data: $('#my_form').serialize(),
type: 'GET',
cache: false,
dataType: 'jsonp',
success: function(data) {
var html = 'do something with data';
$('#results').html(html);
},
error: function() {
$('#results').html('An error occurred, please try again');
}
});
} else {
$('#results').html('Please fill in all required fields');
}
return false;
});
});
The part I added just after the $(document).ready(function(){ and before the submit was:
if ($('#input_1').val() != '' || $('#input_2').val() != '') {
// $('#check').trigger('click');
$('#my_form').submit();
}
Both those lines have the same effect but I am doing the same in another project and it works fine, as far as I can see, the only difference is the jQuery version, I'm using 1.11 for this page.
Update
Apologies, I seem to have answered my own question, I thought that since the programmatic submit was the first thing in $(document).ready(function(){ then maybe it was the case that the actual submit function wasn't being reached before the event was triggered so I simply moved that block after the submitfunction and it now works fine.
url: ''
it seems like you are sending your ajax request to nothing.
just an additional: if you want to submit your form through jquery without using AJAX, try
$("#myForm").submit();
it will send your form to the action attribute of the form, then redirect the page there.

Categories