Heim > Fragen und Antworten > Hauptteil
Ich entwickle eine Blog-Anwendung in Laravel 8.
ArticlesController Controller Ich habe diese Methode, um einen einzelnen Artikel und seine Kommentare anzuzeigen:
class ArticlesController extends FrontendController { // More code public function show($slug) { // Single article $article = Article::firstWhere('slug', $slug); $old_article = Article::where('id', '<', $article->id)->orderBy('id', 'DESC')->first(); $new_article = Article::where('id', '>', $article->id)->orderBy('id', 'ASC')->first(); // Comments $commentsQuery = Comment::where(['article_id' => $article->id, 'approved' => 1])->orderBy('id', 'desc'); $comments = $commentsQuery->paginate(10); $comments_count = $commentsQuery->count(); return view('themes/' . $this->theme_directory . '/templates/single', array_merge($this->data, [ 'categories' => $this->article_categories, 'article' => $article, 'old_article' => $old_article, 'new_article' => $new_article, 'comments' => $comments, 'comments_count' => $comments_count, 'tagline' => $article->title, ]) ); } }
In der Ansicht habe ich eine Liste mit Kommentaren wie diese:
<div id="commentsList"> <ol class="commentlist {{ boolval($is_infinitescroll) ? 'infinite-scroll' : '' }}"> @foreach ($comments as $comment) <li class="depth-1 comment"> <div class="comment__avatar"> <img class="avatar" src="{{ asset('images/avatars/' . $comment->user->avatar) }}" alt="" width="50" height="50"> </div> <div class="comment__content"> <div class="comment__info"> <div class="comment__author">{{ $comment->user->first_name }} {{ $comment->user->last_name }}</div> <div class="comment__meta"> <div class="comment__time">{{ date('jS M Y', strtotime($comment->created_at)) }}</div> <div class="comment__reply"> <a class="comment-reply-link" href="#0">Reply</a> </div> </div> </div> <div class="comment__text"> <p>{{ $comment->body }}</p> </div> </div> </li> @endforeach </ol> <div class="ajax-load text-center is-hidden"> loading... </div> </div>
Routen zum Artikel:
// Article routes Route::get('/', [ArticlesController::class, 'index'])->name('homepage'); Route::get('/category/{category_id}', [ArticlesController::class, 'category'])->name('category'); Route::get('/author/{user_id}', [ArticlesController::class, 'author'])->name('author'); Route::get('/show/{slug}', [ArticlesController::class, 'show'])->name('show');
Ich möchte die Kommentarpaginierung durch „unendliches Scrollen“ ersetzen.
Zu diesem Zweck habe ich:
/* Infinite comments */ function infiniteComments() { var page = 1; $(window).scroll(function() { if ($(window).scrollTop() + $(window).height() >= $(document).height() - $('.s-footer').height()) { page++; loadMoreData(page); } }); } function loadMoreData(page){ var base_url = window.location.href.split('?')[0]; $.ajax({ url: `${base_url}?page=${page}`, type: "get", beforeSend: function() { $('.ajax-load').show(); } }) .done(function(data) { if (data.html == "") { $('.ajax-load').hide(); return; } $('.ajax-load').hide(); $(".infinite-scroll").append(data.html); }) .fail(function(jqXHR, ajaxOptions, thrownError) { console.log('The server is not responding...'); }); } $(document).ready(function(){ infiniteComments(); });
Kommentare auf Seite 2 werden beim Besuch https://larablog.com/show/deserunt-qui-exeritationem?page=2
korrekt angezeigt, die Chrome-Konsole zeigt diese 500 (Interner Serverfehler) Fehler:
https://larablog.com/show/deserunt-qui-exercitationem?page=65 500 (Internal Server Error) The server is not responding... https://larablog.com/show/deserunt-qui-exercitationem?page=76 500 (Internal Server Error) The server is not responding...
Der Fehler kann auf die Fehlermeldung in Zeile 70 im ArticlesController zurückgeführt werden - :$article = Article::firstWhere('slug', $slug)
Es wird versucht, die Eigenschaft „id“ eines Nicht-Objekts abzurufen.Das ist seltsam, weil
$article = Article::firstWhere('slug', $slug)
ohne Ajax gut funktioniert.
P粉2535186202024-02-18 10:55:43
firstWhere
返回符合传递条件的第一条记录,默认为 null
。所以,你的行
$article = Article::firstWhere('slug', $slug);
将返回 slug
与 $slug
匹配的第一篇文章,如果不存在这样的记录,则返回 null
。现在,每当您引用 $article->id
时,您都会认为 $article
是一个正确的 Article
并且您想知道其 id
的值。如果没有匹配的文章,这将产生您遇到的错误。
因此,明智的做法是在 $article
初始化后检查 empty($article)
,并在它确实为空时处理边缘情况。
P粉1214472922024-02-18 10:00:05
这是我的解决方案:
在 routes\web.php
中添加了这个新路由:
Route::post('/load_comments', [ArticlesController::class, 'get_comments_ajax'])->name('load_comments');
在 ArticlesController 中:
/** * AJAX Call for Loading extra comments * * @param Request $request * * @return void */ public function get_comments_ajax( Request $request ) { if ( ! $request->ajax() ) { // Redirect to Home Page or just BOMB OUT! exit(); } $more_comments_to_display = TRUE; /** @todo - 5 - This should\could be a setting */ $article_id = $request->post( 'article_id' ); $page_number = $request->post( 'page' ); $offset = $this->comments_per_page * $page_number; $data['comments'] = $this->get_commentQuery( $article_id, $this->comments_per_page, $offset )->get(); $content = ''; if ( $data['comments']->count() ) { $content .= view('themes/' . $this->theme_directory . '/partials/comments-list', array_merge( $data, [ 'is_infinitescroll' => $this->is_infinitescroll ]) ); } else { $more_comments_to_display = FALSE; } echo json_encode( [ 'html' => $content, 'page' => $page_number, 'more_comments_to_display' => $more_comments_to_display, 'article_id' => $article_id ] ); exit(); } /** * get_commentQuery * * @param int $article_id * @param int $limit * @param int $offset * * @return object */ private function get_commentQuery( int $article_id, int $limit = 0, int $offset = 0 ): object { $commentQuery = Comment::where( [ 'article_id' => $article_id, 'approved' => 1 ] )->orderBy( 'id', $this->comments_orderby_direction ); if ( $offset > 0 ) { $commentQuery = $commentQuery->offset( $offset ); } if ( $limit > 0 ) { $commentQuery = $commentQuery->limit( $limit ); } return $commentQuery; }
如果评论超过 10 条,我只会加载 Ajax 脚本:
@if ($is_infinitescroll && $comments_count > $comments_per_page) @section('custom_js_files') @endsection @endif
$(document).ready(function () { let flagMoreCommentsToDisplay = true; let flagCommentsBlockNewRequest = false; let domInfiniteScroll = $(".infinite-scroll"); infiniteComments(); function infiniteComments() { let page = 0; $(window).scroll(function () { if (flagCommentsBlockNewRequest === false) { if ($(window).scrollTop() + $(window).height() >= $(document).height() - $('.s-footer').height()) { if (flagMoreCommentsToDisplay) { flagCommentsBlockNewRequest = true; page++; loadMoreData(page); } } } }); } function loadMoreData(page) { let base_url = window.location.origin $.ajax({ url: base_url + '/load_comments', type: 'POST', dataType: 'json', data: {'_token': token, 'page': page, 'article_id': article_id}, beforeSend: function () { $('.ajax-load').show(); } }) .done(function (data) { $('.ajax-load').hide(); let commentHtml = data.html; flagMoreCommentsToDisplay = data.more_comments_to_display; if (flagMoreCommentsToDisplay) { if (commentHtml !== '') { domInfiniteScroll.append(commentHtml); } } flagCommentsBlockNewRequest = false; }) .fail(function () { flagCommentsBlockNewRequest = false; }); } });