Laravel 5 没有HTML表单的AJAX排序顺序数据(jQuery Sortable)


Laravel 5 AJAX Sort Order data (jQuery Sortable) with no HTML form

我要尝试使用 Laravel 5 在我的新网站的帮助中心内存储每篇文章的排序顺序,并且在使其工作时遇到一些麻烦。我正在使用jQuery UI的.sortable来排列页面上的元素,并且由于整个站点中将有多个区域可排序的部分,因此我的jQuery脚本是以一种"一个脚本适用于所有"的方式构建的。因此,使用 data-* 属性和路由名称引用。

这是我到目前为止的代码:

路线.php

Route::post('admin/help-centre/category/{category_id}/section/{section_id}/article/sort-order', 'AdminHelpCentreArticleController@sortOrder');

管理员帮助中心文章控制器.php

public function sortOrder($category_id, $section_id)
{
    /* Return ------------------------------------- */
        return [
            'category_id' => $category_id,
            'section_id' => $section_id
        ];
}

show.blade.php (管理文章列表)

<ul id="help-center-articles-sort" class="sortable">
    @foreach ($helpCentreArticles as $helpCentreArticle)
        <li class="sortable-element" data-sortable-element-id="{{ $helpCentreArticle->id }}">
            <a href="{{ action('AdminHelpCentreArticleController@show', array($helpCentreCategory->id, $helpCentreSection->id, $helpCentreArticle->id)) }}" target="_self">{{ $helpCentreArticle->title }}</a>
        </li>
    @endforeach
</ul>
<a href="{{ $helpCentreSection->id }}/article/sort-order" target="_self" class="button bm-remove w-full sortable-save" data-sortable-id="help-center-articles-sort">Save Order</a>

脚本.js(包括 CSRF 令牌_token

var csrfToken = $('meta[name="csrf-token"]').attr('content');
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    if (options.type.toLowerCase() === 'post')
    {
        options.data += options.data?'&':''; // add leading ampersand if `data` is non-empty
        options.data += '_token=' + csrfToken; // add _token entry
    }
});
$(document).ready(function() {
    $('.sortable').sortable();
    $('.sortable-save').on('click', function(e) {
        e.preventDefault();
        var route = $(this).attr('href'),
            sortableID = $(this).attr('data-sortable-id');
        var data = $('#' + sortableID + ' .sortable-element').map(function() { 
            return $(this).attr('data-sortable-element-id');
        }).get();
        $.ajax({
            type: 'POST',
            url: route,
            dataType: 'json',
            data: { id_array: data },
            success: function(data) {
                console.log(data);
            }, error: function(data) {
                console.log(data);
            },
        });
    });
});

到目前为止,一切都在控制台中的返回响应方面工作,这是Object {category_id: "1", section_id: "1"} .但无论我怎么尝试,我似乎都无法通过data映射到控制器来使用它。

我已经尝试了很多猜测,因为我在 Laravel 5 中找不到一个像样的 AJAX 教程,并且我已经尝试了诸如向 sortOrder() 方法添加 $data 参数之类的事情,我已经尝试了Input::all()Request::all但它都返回错误(我猜是因为它不是实际形式?

一旦我有了要传递到控制器的数据,我就可以轻松地将排序顺序保存到数据库中。但是我不能完全达到那个阶段,有什么想法吗?

编辑

可能应该注意到,我确实有一个HelpCentreArticle模型和一个HelpCentreArticleRequest请求,以下是每个文件中的一些代码,以防它们也需要:

帮助中心文章.php

class HelpCentreArticle extends Model {
    protected $fillable = [
        'category_id',
        'section_id',
        'title',
        'content',
        'excerpt',
        'is_visible',
        'sort_order',
        'created_by',
        'updated_by',
    ];
}

帮助中心文章请求.php

class HelpCentreArticleRequest extends Request {        
    /* Authorization ------------------------------ */
        public function authorize()
        {
            return true;
        }

    /* Validation rules --------------------------- */
        public function rules()
        {
            $rules = [
                'title' => 'required|min:3',
                'content' => 'required|min:10',
            ];
            return $rules;
        }
}

我不确定是否需要将HelpCentreSectionRequest $request添加为 sortOrder() 方法的最后一个参数,所以我可以使用$request->all()但它只是在控制台日志中返回一个422 (Unprocessable Entity)

因此,似乎正确的方法是使用 Input::get('id_array'); 而不是 $_POST['id_array']; ,我尝试过,但是当我最初尝试这样做时,我没有在控制器顶部包含use Input;,因为我认为这已经可以访问,但事实并非如此。

添加use Input; 并使用Input::get();现在按预期工作。

以下是更新的代码:

管理员帮助中心文章控制器.php

public function sortOrder($category_id, $section_id)
{
    /* Query Select ------------------------------- */
        $helpCentreCategory = HelpCentreCategory::findOrFail($category_id);
        $helpCentreSection = HelpCentreSection::findOrFail($section_id);

    /* Variables ---------------------------------- */
        $id_array = Input::get('id_array');
        $sort_order = 1;

    /* Query Update ------------------------------- */
        foreach($id_array as $id) {
            $helpCentreArticle = HelpCentreArticle::where('id', $id)->first();
            $helpCentreArticle->sort_order = $sort_order;
            $helpCentreArticle->save();
            $sort_order++;
        }

    /* Return ------------------------------------- */
        return ['success' => true];
}

然后,您可以显然访问 jQuery 中if else语句的success来操作页面。

我用Laravel排序的UI实现

索引刀片.php

...
@foreach($photos as $photo)
<tr data-sortable="{{ $photo->pivot->position }}" data-id="{{ $restaurant->id }}" data-photo-id="{{ $photo->pivot->photo_id }}">
    <td>
        <i class="fa fa-sort" aria-hidden="true"></i>
    </td>
...
</tr>
@endforeach
<script type="text/javascript">
$("#sortable-ui tbody").sortable({
    helper: fixHelper,
    update: function(event, ui) {
        $("#sortable-ui tbody tr").each(function(index){
            console.log($(this).data('id')+', '+(index+1));
            $.ajax({
                url: '{{ route('owner.photo.update.position') }}',
                type: 'POST',
                data: 'restaurant_id='+$(this).data('id')+'&photo_id='+$(this).data('photo-id')+'&position='+(index+1)
            })
            .done(function (response) {
                console.log(response);
            })
            .fail(function (jqXhr) {
                console.log(jqXhr);
            });
        });
    }
}).disableSelection();
</script>

脚本.js

$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

AjaxController.php

public function updatePhotoPosition(Request $request)
{
    $restaurant = $this->restaurantRepository->getById($request->get('restaurant_id'));
    $photoId = $request->get('photo_id');
    $photo = $restaurant
        ->photos()
        ->wherePivot('photo_id', $photoId)
        ->first();
    $photo->pivot->position = $request->get('position');
    $photo->pivot->save();
}