搜尋

首頁  >  問答  >  主體

為什麼在此 Laravel 應用程式中 AJAX 呼叫失敗?

我正在 Laravel 8 中開發一個部落格應用程式

ArticlesController 控制器我有這個方法來顯示單篇文章及其註解

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,
                ])
            );
    }

}

在視圖中我有這樣的評論清單:

<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>

與文章相關的路線:

// 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');

目標

我想用「無限滾動」取代評論分頁。

為此目的,我有:

/* 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();
 });

問題

造訪https://larablog.com/show/deserunt-qui-exeritationem?page=2 時正確顯示第2 頁的評論,Chrome 控制台顯示這些500(內部伺服器錯誤)錯誤:

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...

該錯誤可以追溯到到 ArticlesController 中第 70 行的錯誤訊息 - $article = Article::firstWhere('slug', $slug):

#嘗試取得非物件的屬性「id」。

這很奇怪,因為 $article = Article::firstWhere('slug', $slug) 在沒有 Ajax 的情況下工作正常

問題

  1. 是什麼原因導致此錯誤?
  2. 最簡單的修復方法是什麼?

P粉779565855P粉779565855270 天前318

全部回覆(2)我來回復

  • P粉253518620

    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) ,並在它確實為空時處理邊緣情況。

    回覆
    0
  • P粉121447292

    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')
            sssccc
        @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;
            });
        }
    });

    回覆
    0
  • 取消回覆