How can I make dynamic Ajax requests with Laravel - javascript

I'm creating a social network site using Laravel. I have a page that load all the posts created by users the currentUser follows. I have a comment section on each post. I want a user to be able to comment on any post without the page reloading so the user doesn't have to re-scroll through the page.
I have everything working fine without ajax (minus the reloading page). I'm able to post comments, the page reloads and the new comment is displayed. However, when I try to use Ajax I've been running into problems.
Here is my code.
Here is the view of the comment-box. It contains a section where I loop through each comment and display them. At the end is the type field so a user can post a new comment:
<div class="comment-box-container ajax-refresh">
<div class="comment-box">
#if ($type->comments)
#foreach ($type->comments as $comment)
<div class="user-comment-box">
<div class="user-comment">
<p class="comment">
<!-- starts off with users name in blue followed by their comment-->
<span class="tag-user">{{ $comment->owner->first_name }} {{ $comment->owner->last_name }} </span>{{ $comment->body }}
</p>
<!-- Show when the user posted comments-->
<div class="com-details">
<div class="com-time-container">
{{ $comment->created_at->diffForHumans() }} ยท
</div>
</div>
</div><!--user-comment end-->
</div><!--user-comment-box end-->
#endforeach
#endif
<!--type box-->
<div class="type-comment">
<div class="type-box">
{{ Form::open(['data-remote', 'route' => ['commentPost', $id], 'class' => 'comments_create-form']) }}
{{ Form::hidden('user_id', $currentUser->id) }}
{{ Form::hidden($idType, $id) }}
{{--{{ Form::hidden('user_id', $currentUser->id) }}--}}
{{ Form::textarea('body', null, ['class' =>'type-box d-light-solid-bg', 'placeholder' => 'Write a comment...', 'rows' => '1']) }}
{{ Form::close() }}
</div><!--type-box end-->
</div><!--type-comment-->
</div><!--comment-box end-->
The user submit the form for the comment type box by pressing the "enter/return" key. Here is the JS for that
<script>
$('.comments_create-form').on('keydown', function(e) {
if (e.keyCode == 13) {
e.preventDefault();
$(this).submit();
}
});
</script>
Here is my Ajax
(function(){
$('form[data-remote]').on('submit', function(e){
var form = $(this);
var method = form.find('input[name="_method"]').val() || 'POST';
var url = form.prop('action');
$.ajax({
type: method,
url: url,
data: form.serialize(),
success: function(data) {
var tmp = $('<div>');
tmp.html(data);
$('.ajax-refresh').html(tmp.find('.ajax-refresh').html());
$('.type-box').html(tmp.find('.type-box').html());
tmp.destroy();
}
});
e.preventDefault();
});
})();
I'm running into a few problems with this code. The comment gets displayed on ever single post until I manually refresh the page then it only shows on the correct post. I feel like every post's comment-box will need it's own unique ID to solve this, but I do not know how to do this with Laravel and make the JavaScript work.
also,
After I submit one comment I can no longer submit a second one because my "submit on enter/return key" functionally is no longer working. My cursor just moves to a new line, and I'm not able to post another comment.
Does anyone know a way to fix these problems?
EDIT
Here is my ajax so far
(function(){
$(document).on('submit', 'form[data-remote]', function(e){
e.preventDefault();
var form = $(this)
var target = form.closest('div.ajax-refresh');
var method = form.find('input[name="_method"]').val() || 'POST';
var url = form.prop('action');
$.ajax({
type: method,
url: url,
data: form.serialize(),
success: function(data) {
var tmp = $('<div>');
tmp.html(data);
target.html( tmp.find('.ajax-refresh').html() );
target.find('.type-box').html( tmp.find('.type-box').html() );
tmp.destroy();
}
});
});
})();

Please use the following to fix the issue:
$(document).on('submit', 'form[data-remote]', function(e){
e.preventDefault();
var form = $(this),
var target = form.closest('div.ajax-refresh');
var method = form.find('in......
......
.....
tmp.html(data);
target.html( tmp.find('.ajax-refresh').html() );
target.find('.type-box').html( tmp.find('.type-box').html() );
tmp.destroy();
}
});
});
The variable target will help you target just the right div to add the ajax response to.
Further, you would have to just reset the relevant form rather than replace the form markup. Otherwise each form will work only once.
UPDATE
The above code has been updated to use a delegated submit event -- $(document).on('submit', '.selector', ...) instead of $('.selector').on('submit', .....) since the form content is being replaced after each comment.
UPDATE 2
The following delegated keydown event should enable you to submit by pressing the enter key:
$(document).on('keydown', '.comments_create-form', function(e) {
if (e.keyCode == 13) {
e.preventDefault();
$(this).submit();
}
});

Related

Updating Like Button Without Page Refresh

I'm working on a Like button. It's working fine. After Like button completes it's functionality I'm trying to update the button text (Like to Liked) without refreshing the page, but problem is that It's updating the every single Like button on the webpage (until I refresh the page) not just the one I clicked on . . .
Here's that success function in AJAX call,
$('.like-click').click(function(e){
e.preventDefault();
var this_ = $(this);
var quesURL = this_.attr('like-href');
$.ajax({
url: quesURL,
method: 'GET',
data: {},
success: function (data) {
var like_text = $(data).find('.like-click').html();
$('.like-click').html(like_text);
}
})
});
Here's the HTML code,
{% for data in datas %}
...
<a class="like-click" like-href="...">{% if user in Likes %}Liked{% else %}Like{% endif %}</a>
...
{% endfor %}
How can I update the button I clicked, not all of them ?
You have saved your clicked element in var this_, so you have to just update that element text only via replacing $('.like-click').html(like_text); to $(this_).html(like_text);
So it will not update each button text.
that's happened because you firing all button with having 'like-click' class
$('.like-click').click(function(e){
e.preventDefault();
var this_ = $(this);
var quesURL = this_.attr('like-href');
$.ajax({
url: quesURL,
method: 'GET',
data: {},
success: function (data) {
if(this_.html()=='like'){
this_.html('liked');
}else{
this_.html('like');
}
}
})
});
Why you use AJAX for this? You are not pulling "Like" or "Liked" from database. Do it with simple handler:
$(function(){
$('button').click(
function(){
$(".button div").toggle();
}
)
});
<button type="button" class="button like-click">
<div>Like</div>
<div style="display: none">Liked</div>
</button>
And note, that selecting button / a element by class="like-click" is probably not what you need (it would affect all elements by that class), so better asing them ids that are unique and comes from your {% for data in datas %} loop
UPDATE:
Because you dont have a dislike, it could be done in same manner as in my above example:
<button type="button" class="button" id="btn">
<div class="like">Like</div>
<div style="display: none" class="like">Liked</div>
<div class="count" id="current"> 1 </div>
<div style="display: none" class="count" id="clicked"> </div>
</button>
$('#btn').click(function() {
$('#btn #clicked').html(parseInt($('#current').text()) + 1);
$('#btn .like').toggle();
$('#btn .count').toggle();
})

Capturing onClick event when submitting a form

I created a form which collects data to either launch an external process (bash script) or to make a database query (using queryBuilder). Since both procedure could take some time, I would like to update the submit button, as soon as it is clicked, with a message (like 'Processing..., please wait') or an icon (like the animated icons of FontAwesome). Here is the function I set in my Controller class (Symfony2):
public function inputAction(Request $request)
{
$form = $this->createForm(new InputType());
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
$data = $form->getData();
$cmd = '... my command using $data and taking some time ... ';
$process = new Process($cmd);
$process->setTimeout(120);
$process->run();
// Alternative DB query
// $qb = $this->getDoctrine()->getManager()
// ->createQueryBuilder();
// $query = $qb->select('COUNT(p)')
// ->add('from','myBundle:Ec p')
// ->add('where', 'p.ec LIKE :ec')
// ->setParameter('ec', $data['..'].'%')
// ->getQuery();
//
// $result = $query->getSingleScalarResult();
return $this->redirectToRoute('_input');
}
return $this->render('myBundle:Default:form.html.twig', array(
'form' => $form->createView(),
));
}
I thus added a JQuery call in my template
{% extends 'myBundle:Default:input.html.twig' %}
{% form_theme form 'bootstrap_3_layout.html.twig' %}
{% block form %}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script>
$(function() {
$('.btn-default').on('click', function() {
$(this).prepend('<i class="fa fa-refresh fa-spin"></i> ');
});
});
</script>
{%endblock %}
But the message or the icon is not displayed when the button is clicked. It is only displayed if I stop the process in the browser. I also tried the 'submit' event, with no more success, while 'mouseover' is perfectly working.
EDIT 1
Following the advice from #Micha, when I modified JS like that:
$(function() {
$('.btn-default').attr('prepend', 'false')
$('.btn-default').on('click', function(e) {
if($('.btn-default').attr('prepend') == 'false'){
e.preventDefault();
$('.btn-default').attr('prepend','true');
$(this).prepend('<i class="fa fa-refresh fa-spin"></i> ');
$(this).trigger('click');
}
});
});
I see that the DOM is updated and the query (or the process) launched, but the prepend text or icon is not actually displayed in the browser.
How about preventDefault() and then submit() the form from in the click function?
<script>
$(function() {
$('.btn-default').on('click', function(event) {
event.PreventDefault();
$(this).prepend('<i class="fa fa-refresh fa-spin"></i> ');
$(#my-form).submit();
});
});
</script>
Hope this helps.
The problem I was facing is apparently only occurring with Safari. My original code (and most of the proposed solutions by #Micha and #chris-rogers) are perfectly working in Chrome and Firefox.

How can I improve my Ajax?

I'm trying to figure out if what I'm doing is the right way. I have a comment form and when it gets clicked I'm appending the comment into a div element through Ajax. When the page is refreshed then of course that would disappear and instead of it I have a foreach loop that runs and echos the comments. Since they both have the same CSS attributes they look the same to the user. The reason I'm doing it this way is because the foreach loop gets updated only after a refresh. Is there a better way? Can I update the page directly from the database without refresh? I basically need that every time a user clicks on the comment button that the foreach loop will run again but I couldn't find how to do it. I feel like I'm covering a gun shot with bandage the way I do it at the moment.
Loop:
#foreach($comment as $comments)
#if($comments->image_id == $image->id)
<div id="{{$comments->id}}" class="col-md-5 ajaxrules">
<div class="deletecomment">
<i class="fa fa-trash-o"></i>
</div>
<div class="col-md-2">
<img src="{{$comments->user_avatar}}" class="img-circle buddy">
</div>
<div class="hello col-md-10">
<h4>{!! $image->user_name !!}</h4>
<p class="left">{!!$comments->body!!} </p>
</div>
</div>
#endif
#endforeach
//Where I append the comments through Ajax until the refresh that replaces it with the loop
<div class="man">
</div>
Ajax:
<script>
$(document).ready(function(){
$('.send-form').click(function(e){
e.preventDefault();
var username = "{{ $username }}";
var one = $('textarea[id="{{$image->id}}"]').val();
var value = "{{$image->id}}";
var begin = '<div class="col-md-5 addavatar">'+'<div class="deletecomment">'+'<i class="fa fa-trash-o">'+'</i>'+'</div>'+'<div class="col-md-2">'+'<img src="{{$profile}}" class="img-circle">'+'</div>'+'<div class="hello col-md-10">'+'<h4>' + username +'</h4>'+'<p>'+one+'</p>'+'</div>'+'</div>';
if(one.length > 0){
console.log(username);
$('textarea[id="{{$image->id}}"]').val('');
$.ajax({
url: 'comment',
type: "post",
beforeSend: function (xhr) {
var token = $('meta[name="csrf_token"]').attr('content');
if (token) {
return xhr.setRequestHeader('X-CSRF-TOKEN', token);
}
},
data: {'id': value, 'comment': one},
success:function(data){
$( ".man" ).append([begin]);
},error:function(){
console.log("error!!!!");
}
});
}
});
});
</script>
You are killing yourself.
Manipulate the DOM via javascript code like you do it's really hard work!
You are not suppose to write html inside javascript strings, there must be another way!
And there is... Welcome to AngularJS!
In angular you can write your html and assign a javascript controller to it, perform ajax request and after the ajax complete you can bind the returned data to the html automatically! That means the angular refresh your html and do all the work for you. Even perform loop of let's say, row in a table, etc...

$('#notificationClick').click not working

so I'm trying to make this works here is the jquery+php.
When I try to trigle the click in jquery it doesnt even does the "alert()".
PHP(Updated):
$MSG_Notification_sql = mysqli_query($Connection, "SELECT * FROM notifications WHERE user_id='".$bzInfo['id']."'");
while ($MSG_Notification_row = mysqli_fetch_array($MSG_Notification_sql)){
$MSG_Notification_rows[] = $MSG_Notification_row;
}
foreach ($MSG_Notification_rows as $MSG_Notification_row){
$bzWhen = date('d-m-Y H:m:i', strtotime($MSG_Notification_row['when']));
echo '<form method="POST">
<div class="notificationClick notification-messages info">
<div class="user-profile">
<img src="assets/img/profiles/d.jpg" alt="" data-src="assets/img/profiles/d.jpg" data-src-retina="assets/img/profiles/d2x.jpg" width="35" height="35">
</div>
<div class="message-wrapper">
<div class="heading"> '.$MSG_Notification_row['title'].'</div>
<div class="description"> '.$MSG_Notification_row['description'].' </div>
<div class="date pull-left"> '.$bzWhen.'</div>
</div>
<input name="notificationID" value="'.$MSG_Notification_row['id'].'" style="display: none" />
<div class="clearfix"></div>
</div>
</form>';
}
Javascript(Updated):
$(document).ready(function(){
$('.notificationClick').click(function(event){
alert('Ok');
// get the form data
// there are many ways to get this data using jQuery (you can use the class or id also)
var formData = $('#notificationClick').serialize();
// process the form
$.ajax({
type : 'POST', // define the type of HTTP verb we want to use (POST for our form)
url : '../../class/notifications/msgs_del.php', // the url where we want to POST
data : formData, // our data object
dataType : 'json' // what type of data do we expect back from the server
})
// using the done promise callback
.done(function(data) {
// log data to the console so we can see
console.log(data);
window.location = '/?page=messages&sub=inbox&bx=preview&id='+ data.notificationID +'';
});
event.preventDefault();
});
});
Can anybody help me please? I'm trying to complete this but nothing :(
First as the others say, ids need to be singular. So use the class you already have. Now inside, you need to use the current form that you clicked on, not all the forms.
$('.notification-messages').click(function(event){ //<-- change to class
var formData = $(this).closest("form").serialize(); //change to this
...
If you are loading these dynamically, you need to use event delegation
$(document).on("click", '.notification-messages', function(event){
var formData = $(this).closest("form").serialize();
...
You can concatenate the timestamp to your id to make it unique (separated by an _ if you like) and change your selector for the click event to $('[id*="notificationClick_"]')
On the other hand, you might want to use a class instead, that's what it's there for:
$(".notification-messages")
You're using ID, you can only bind click to 1 id not multiple ids.
You should use the class to bind the .click function.

Form not submitting, jquery load, submit

I am very confused as to how to write the code in javascript/jquery to allow for the proper submission of my form. I currently have a function to handle an on-click event, which loads the proper form. However, the form fails to submit successfully. I am using the .submit() function, but I think I am missing something here. I believe the URL I would have to place in that function would be the one being dynamically loaded in the onclick function. Is there a reasonable way to transfer this information? Or am I mistaken?
I have already confirmed that the correct URL is loaded and that the form behaves as intended if the URL is accessed manually. This issue seems to be unique to loading the URL
from select_my_book.html (the url to be loaded)
<form action="" method="POST" id="submitForm">
{% csrf_token %}
<!-- Code to render form elements -->
<input type="submit" value = "Buy" id="submit">
</form>
from get_my_book.html (the current url with the tabs/jumbotron)
{% for course in userprofile.courses.all%}
<div class="minicoursenav">
<a class='course_link' data='{{ course.pk }}' href='#' type="submit">
{{ course.name }}
</a>
</div>
{% endfor %}
from activate.js
function selectConditionURL(criterion, condition){
var url = "/books/select_my_book/"
return(url+ condition + "/" + criterion + "/")
}
function selectCourseURL(criterion){
var url = "/books/select_my_book/best_price/";
return (url + criterion + "/");
}
$('.course_link').click(function(e) {
e.preventDefault();
var course_pk = $(this).attr('data');
/*alert( course_pk );*/
var url = selectCourseURL(course_pk);
/*alert( url );*/
$("#best_price").load(url);
$("#very_good").load(selectConditionURL(course_pk, "very_good_condition"));
$("#good").load(selectConditionURL(course_pk, "good_condition"));
$("#fine").load(selectConditionURL(course_pk, "fine_condition"));
return false;
})
$(document).ready(function() {
$("#submitForm").submit(function(e) {
e.preventDefault();
$.ajax({
type: "POST",
/* NOT SURE WHAT SHOULD GO HERE */
success: function(response) {
console.log(response)
}
});
return false;
})
})

Categories