Laravel commenting with ajax - ajax

So I have a laravel commenting system which lets me conment using ajax. My current setup is simple. I have a field for comments and then my route is as follows:
Route::post(‘comment/{post_id}’, ‘CommentController#insert’);
And in my ajax url, I have given the same route with the post_id. I am giving the post id because I wanted to add the post id to my post_id column in my comments table. Also my ajax is in line.
Now my question is, I do not know how to add replies to a comment. I have to insert the comment_id to my replies table comment_id column because comment and replies are related. What confuses me is, if I created a lot of reply forms with a foreach loop for each comment, how can I pass all those comment ID to the ajax?
Say for an example this is my route for storing replies
Route::post(‘replies/{comment_id}’, ‘ReplyController#insert’);
This won’t be like comments that I will be passing only value for the parameter (post_id). This reply will have a lot of values for one parameter right? So how can I proceed with this. I am new to ajax and I am having a hard time trying to get the logic of this. Like I mentioned before, the confusion is that each reply will have a separate comment_id that I need to pass to the route parameter.

you should pass like below:
Route::post('/comment/{comment_id}/replies','ReplyController#insert');

You can try like this
View (here $comments and $comment->replies are assumed, you may have different)
<div class="post-comments">
<p>Comments</p>
#foreach($comments as $comment)
<p>{{$comment->text}}<p>
<label>Replies:</label>
<ul>
#foreach($comment->replies as $reply)
<li>{{$reply->text}}</li>
#endforeach
<form name="replyForm">
<input name="reply" />
<button type="button" onclick="replyComment('/comment/{{$comment->id}}/reply', this.form.reply)">Reply</button>
</form>
</ul>
#endforeach
</div>
Javascript
function replyComment(url, input){
console.log(url);
console.log(input.value);
//call ajax with this url and input value
}
Route
Route::post('comment/{comment_id}/reply', 'ReplyController#insert);

<input type="submit" style="float: right;" class="btn btn-primary" value="Comment" id="comment" data-url="/comment/{{$comment->id}}/replies" data-token="{{ csrf_token() }}" data-comment_id="{{$comment->id}}" >
assuming that you are fetching the $comment from controller.
even if you are adding button there is no need to add the <form>.

You have to pass post_id during reply .
Route like :
Route::`post(‘replies/{post_id}/{comment_id}’, ‘ReplyController#insert’);`
Then sort it those comment by inserting time .

Related

Laravel 9 - Submitting a form to a route leads to /null and doesn't do anything

I'm using soft deletes and trying to make a function to restore the deleted row. Really everything to do with submitting the form doesn't work, even deleting...
My tags are within a forelse loop, maybe that's the cause??
Route is (this is above my resource route):
Route::post('/post/restore/{id}', [PostController::class, 'restore'])
->name('post.restore');
Controller is:
public function restore($id)
{
dd($id);
}
Form/view is:
<form action="{{route('post.restore', $post->id)}}" method="POST">
#csrf
<button type="submit" class="dropdown-item popup" data-confirm="Would you like to restore?">Restore</button>
</form>
After submitting, it just takes me to:
domainURL/post/null
and gives a 404 error
Any advice?? I also tried it without the {id} at the end of the route, same results
I think you are using the wrong syntax for route function, instead of this:
route('post.restore', $post->id)
you should use it like this:
route('post.restore', ['id' => $post->id])
you can read more here as well.
I figured it out... my "would you like to restore?" javascript function was breaking the form. I was using javascript to popup a confirmation message before submitting and during that process it lost the ID
I got rid of that and it works fine
Thank you!

my delete query is not working in laravel

I am trying delete database data in Laravel. but this is not working my way.
my view page is
{{url('/deleteReview/'.$Review->id)}}
my web is
Route::post('/deleteReview/{id}','adminController#deleteReview');
my controller delete function is
public function deleteReview($id){
$deleteReview = Review::find($id);
$deleteReview->delete();
return redirect('/manageReview');
}
Are you trying to delete the review by opening the page /deleteReview/<id> in your browser? If so, this would be a GET request, so change the route to a get route:
Route::get('/deleteReview/{id}','adminController#deleteReview');
Please note as per the comments that a GET request should never change data server side. If data is changed using a GET request then there is a risk that spiders or browser prefetch will delete the data.
The correct way to do this in Laravel is using a POST request and use Form Method Spoofing to simulate a DELETE request. Your route entry would then look like this:
Route::delete('/deleteReview/{id}','adminController#deleteReview');
And your form would look like this:
<form action="/deleteReview/{{ $Review->id }}" method="POST">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>
At Controller you should first set Validation for ID that you have to Delete. Create your own customize request handler such as DeleteRequest.
Once you get ID at Controller then used this code
public function deleteReview(DeleteRequest $id){
DB::table('reviews')->where('id', $id)->delete();
return redirect('/manageReview');
}
I hope it will work.

Laravel - route("resource.destroy") calls "resource.show"

This is the web.php
Route::group(['middleware' => 'auth'],
function () {
Route::get('letters/getRows', 'LetterController#getRows')->name('letters.getRows');
Route::get('letters/{letter}/A4', 'LetterController#A4')->name('letters.A4');
Route::get('letters/{letter}/A5', 'LetterController#A5')->name('letters.A5');
Route::resource('letters', 'LetterController');
}
);
I created a link as follow
"<a class='mx-2 h5' href='".route('letters.destroy', $entity->id)."'><i class='icon-remove-circle'></i></a>".
where the $entity->id is the id of the letter. The problem is, it links to show method not the destroy method. What can I do?
Using a form like this
{{ Form::open(array('route' => array('letters.destroy', $entity->id), 'method' => 'delete')) }}
<button type="submit" >Delete Account</button>
{{ Form::close() }}
may solve the problem but I want to use a tag not a form.
update
In the php artisan route:list, the url of destroy and show are the same
thanks
When you use the Route::resource method it will create, among others, a route to DESTROY a resource like this: /letters/:id/ and another route to EDIT the resource: /letters/:id, and one more to SHOW /letters/:id
They all look the same. However, the difference is in the HTTP method/verb used to reach each route.
If you look to the output if php artisan route:list, you will find the list of HTTP methods used. Something like:
GET|HEAD | letters/{letter} | letters.show
PUT|PATCH | letters/{letter} | letters.update
DELETE | letters/{letter} | letters.destroy
Therefore, to show a letter, you use a GET method, to edit a letter, use PUT method, and to destroy/delete, you use a DELETE method.
When you use an a tag, the browser will use the GET method, thus will reach the letters.show route. Html forms, can use POST or GET. Finally to use the DELETE http method, you need a form with hidden input named _method and the value="delete inside the form. Check the docs for more details.
There is also a note about this in LaravelCollective package documentations
Note: Since HTML forms only support POST and GET, PUT and DELETE methods will be spoofed by automatically adding a _method hidden field to your form.
Finally, if you must use an anchor tag <a>, you could use javascript to listen to the click event and submit a form with DELETE method.
Update to add an example:
You can find an example of using an anchor tag to submit the form, in the default app layout in the framework here
And this is a modified version to submit a delete request:
<a class="dropdown-item" href="#"
onclick="event.preventDefault();
document.getElementById('destroy-form').submit();">
{{ __('DELETE') }}
</a>
<form id="destroy-form" action="{{ route('letters.destroy', $entity) }}" method="POST" style="display: none;">
#method('DELETE')
#csrf
</form>
You cant. If you want to make a DELETE request you need to spoof it via a form (method POST, _method DELETE) or use Javascript.
Hyperlinks will cause new requests which will be GET requests. That is just how the web works.

Laravel: Render queried Data whith Blade functions

Currently I'm getting some data from the database and after that I want to render it within my Blade template.
In my queried data I have blade functions like url('/foo') combined with some html. And here is the problem.
When I'm using {!! $child->description !!} the HTML is rendered correctly, but my Blade function won't work:
Function: url('/foo)
Output: http://myurl.de/url('/foo')
When I'm using the "normal" Syntax like {{ $child->description }} the generated URL is correct (http://myurl.de/foo), but the HTML is not rendered.
So my question is:
How can I use my queried Blade function within rendered HTML? ^^
/Edit
Okay, perhaps my question is too abstract. So I want to show you my problem based on my example. (generated template image - only on german, sorry)
Every form is a database entry like:
categoryName
categoryParent
...
categoryDescription
As you can see on my image, the categoryDescription is the small text under my first input field with the small button.
I want to use this script abstract as possible so that I can fill the entry with every content I want to fill in.
In this case my content is:
lore ipsum <a class="btn btn-primary btn-sm pull-right" href="url('foo')">dolor</a>
As you can see there is the mentioned Blade-function (url) and the HTML.
{!! !!} - this dont escapse string so if u have something from database like,
something it would output it like that.
While in other hand {{ }} this would give you just "something" without , it is used to protect you from injections.
Maybe blade error.{{}}
lore ipsum <a class="btn btn-primary btn-sm pull-right" href="{{url('foo')}}">dolor</a>
Laravel Blade

Laravel 4 - Update Div Using Ajax

I'm using Laravel 4 and am trying to update a (#articles) div with the new articles that are retrieved from an ajax request. When I inspect the page and view the Network section, I can see the POST requests being fired off and it's not showing any errors (eg, articles appear to be returned). However, unfortunately, the #articles div is not being updated with the new information. Yet, if I do a browser refresh, the new articles are displayed.
Routes.php
Route::any("/dashboard/latest_sa", [
"as" => "dashboard/latest_sa",
"uses" => "DashboardController#latest_sa"
]);
controllers/DashboardController.php
Class DashboardController extends \BaseController
{
...
protected function latest_sa()
{
if( Request::ajax() )
{
// called via ajax
$articles = Articles::orderBy('published_at', 'desc')->paginate(20);
return json_decode($articles);
}
else
{
// fresh page load
$articles = Articles::orderBy('published_at', 'desc')->paginate(20);
return $articles;
}
}
...
}
app/views/dashboard/default.blade.php
...
#section("content")
// defined in /public/js/main.js
<script type="text/javascript">
callServer();
</script>
<div class="col-xs-4 col-sm-4 col-md-4 col-lg-4">
<h4>Latest Articles</h4>
<div class="articles">
<ul>
#foreach ($articles as $article)
<li>
<img src="{{ $article->user_image }}" alt="{{ $article->article_title }}" />
{{ $article->article_title }}
<div class="details">
<span class="author">{{ $article->author_name }}</span>
<span class="created">{{ Helpers::time_ago($article->published_at) }}</span>
<span class="symbol">{{ $article->symbol_title }}</span>
</div>
</li>
#endforeach
</ul>
</div>
{{ $articles->links() }}
</div>
...
/public/js/main.js
function callServer()
{
setInterval(function(){
$.ajax({
type: "POST",
url: "dashboard/latest_sa",
success:function(articles)
{
$(".articles").html(articles);
}
});
},5000);
}
JS is hardly my strong suit, so I'm not sure what I'm doing wrong here.
And, for clarity sake, the reason why I'm trying to update all of the articles in the div is so that the Helpers::time_ago method also gets called, instead of just fetching the new articles. This way, it properly shows how long ago the article was published (eg, less than a minute ago, a minute ago, a hour ago, a day ago, etc) without refreshing the page. Essentially, I'm trying to kill two birds with one stone; update the div with the most recent articles, and update the remaining article's published_at attribute using my Helpers::time_ago method. If there is a more effective / efficient way of doing this, feel free to correct me. This seems rather crude, but since it's only for personal use and will never be used for commercial purposes, it suits my needs (not that that excuses bad code).
Nonetheless, from my fairly basic understanding, the JS should be doing the following steps:
1) Fire a POST request off to the /dashboard/latest_sa route
2) Execute the DashboardController#latest_sa action
3) Return a DB collection of all $articles ordered by the latest published date, and paginated
4) Pass the $articles collection back to the JS success attribute (as articles)
5) Fire the anonymous function, with the articles collection as an argument
6) Update the corresponding inner HTML with the results from the articles collection
The logic sounds right, so I'm pretty sure this is going to be a human error (98% of the time it is, after all. lol). Hopefully, someone here will be able to see the (probably glaring) problem in the logic and point me in the right direction.
In the meantime, I'm going to keep toying around with it.
I look forward to your thoughts, ideas, and suggestions. TIA.
EDIT:
Well, I found one of the problems; the articles div is a class, and in the JS I'm referring to it as an id. I fixed that, and now after the timeInterval, the article's div is "updated" but no results are being displayed (none, zippo, nadda).
Yet, if I directly access the /dashboard/latest_sa URI I get the valid JSON response that I'm expecting. So, albeit I am closer, I am still missing something.
EDIT 2:
Okay, in the controller, I made some changes which can be seen above, where I am now doing a json_decode on the $articles, before returning them to be passed into the view. With that in place, the articles are showing back up again after the timeInterval has elapsed, however, the new articles and the published_at for the existing articles are not being updated. After reviewing Inspect -> Network, it shows that the server is responding with a 500 Internal Server Error from the ajax POST request.
Hrm... Seems like I'm going in circles. Sounds like a good time to take a break and go for a walk. ;)
EDIT 3:
Well, I modified my Helpers class and added in the following method to check if the $article is a json object.
public static function isJson($string)
{
json_decode($string);
return (json_last_error() == JSON_ERROR_NONE);
}
app/views/dashboard/index.blade.php
#foreach ($articles as $article)
<?php
if( Helpers::isJson($article) )
{
$article = json_decode($article);
// dd($article) // when uncommented it returns a valid PHP object
}
?>
<!-- Iterate over the article object and output the data as shown above... -->
#endforeach
As you can see, (for the time being) inside of my view's foreach($articles as $article), I run Helpers::isJson($article) as a test and decode the object if it is json. This has enabled me to get passed the 500 Internal Server Error message, populate the articles div with the results on the initial load, and after the ajax POST request is fired off, I'm getting back a server response of 200 OK according to Inspect -> Network. However, after it updates the div, it doesn't show any articles.
Around, and around I go... I think it's time I take that break I keep murmuring about. ;)
Any thoughts, suggestions and / or ideas are greatly welcomed and appreciated.
At first, you should know that, when you return a collection from the controller/route, the response automatically turns in to a json response so, you don't need to use json_decode() and it won't work, instead, you may try something like this (from your controller for ajax):
$articles = Articles::orderBy('published_at', 'desc')->paginate(20);
return View::make('defaultAjax')->with('articles', $articles);
Since building the HTML in the client side using the json data received from server side would be tough for you so, you may return HTML from the server with the generated view instead of json, so you may try something like this in your success handler:
success:function(articles) {
$(".articles").html(articles);
}
Now create a view for ajax response without extending the template like this:
//defaultAjax.blade.php used in the controller for ajax response
<ul>
#foreach ($articles as $article)
<li>
<img src="{{ $article->user_image }}" alt="{{ $article->article_title }}" />
{{ $article->article_title }}
<div class="details">
<span class="author">{{ $article->author_name }}</span>
<span class="created">{{ Helpers::time_ago($article->published_at) }}</span>
<span class="symbol">{{ $article->symbol_title }}</span>
</div>
</li>
#endforeach
</ul>
{{ $articles->links() }}
Notice, there is no #extendds() or #section(), just plain partial view, so it'll be rendered without the template and you can insert the ul inside the .articles div. That's it.
$("#articles").html(articles); ->> $(".articles").html(articles);

Resources