Tìm hiểu Laravel (P11) - Loading tags with select2 and ajax
Bài đăng này đã không được cập nhật trong 7 năm
Indexs
- Phần 1: Cài đặt
- Phần 2: Form đăng nhập
- Phần 3: Send Mail
- Phần 4: Error page
- Phần 5: Application Structure
- Phần 6: Logging
- Phần 7: Routing
- Phần 8: Middleware
- Phần 9: Controller
- Phần 10: HTTP Requests
- Theo như kế hoạch thì mình dự tình phần này sẽ tìm hiểu về
HTTP Responses
. Nhưng lý thuyết hoài cũng chán nên bài này sẽ mang hơi hướng thực hành hơn chút. AE vừa đọc vừa làm thử xem sao nhé, vấn đề thực chất là không khó nhưng đến khi bắt tay vào làm thì mình khá lúng túng và mất kha khá thời gian để giải quyết.
1. Input và Output
Input:
- Như tiêu đề đã nêu
Loading tags with select2 and ajax
là một phần trong task sửa bài post mình đã nhận, cụ thể như sau:- Sự dụng thư viện Select2 hiển thị tags của bài viết
- Nếu user nhập tag chưa có thì create mới
- Độ dài mỗi tag tối đa 15 ký tự
- Một post có tối đa 5 tag
Output:
- Update được tags cho bài viết.
2. Giải pháp
- Database: có 3 bảng
- Bảng Post sẽ có trường id, title, content,..
- Bảng Tag có id, tag_name,..
- Bảng TagPost có id, post_id, tag_id
- Ý tưởng:
- Ở màn hình edit, từ post ta sẽ lấy ra được list các tags của post để hiển thị ra.
- Khi user sửa tags ta sẽ gửi danh sách các tags sau khi sửa lên server gọi đây là mảng
$newTags
: - Từ post ta sẽ lấy được list các tag của post trước khi update tạm gọi đây là mảng
$oldTags
. - So sánh 2 mảng trên để lấy ra các tag mới thêm vào (đặt là:
$addTags
) và các tag đã xóa đi (gọi là:$delTags
). - Từ mảng
$delTags
ta sẽ xóa các record tương ứng trong bảng TagPost, còn mảng$addTags
sẽ có 2 trường hợp. Nếu tag mới thêm đã có trong bảngTag
thì chỉ cẩn insert bảng ghi mới vào bảngTagPost
, còn nếu chưa có thì đồng thời ta phải tạo bản ghi mới cho bảngTag
.
- Thực hiện:
- Trên view ta cần tạo form edit với input tags như sau:
<select multiple="true" name="tags[]" id="tag" class="form-control select2"> @foreach($post->tags as $tagName) <option value="{{ $tagId }}" selected="selected">{{ $tagName }}</option> @endforeach </select>
- Tất nhiên là để hiển thị được tag ta cần include thư viện
Select2
bạn nhé:
@section('style') {!! Html::style('js/plugins/select2/select2.css') !!} @endsection @section('script') {!! Html::script('js/plugins/select2/select2.full.min.js') !!} {!! Html::script('/js/post_edit.js') !!} @endsection
- Tất nhiên là để hiển thị được tag ta cần include thư viện
- Trong file
post_edit.js
ta sẽ viết ajax để load các tags trong bảngTag
ra theo input user nhập vào kiểu autocompletevar baseUrl = window.location.protocol + '//' + window.location.host; $('#tag').select2({ multiple: true, tags: true, tokenSeparators: [',', ' '], ajax: { url: baseUrl + '/posts/getTags/', dataType: 'json', data: function (params) { return { q: $.trim(params.term) }; }, processResults: function (data) { return { results: data }; }, cache: true }, });
- Phía controller ta sẽ viết hàm lấy ra các tag đã có sẵn theo input nhập vào như sau:
public function getTags(Request $request) { $input = $request->q; if (empty($input)) { return response()->json([]); } $tags = DB::table('tag')->where('tag_name', 'like', $input . '%')->get(); $formattedTags = []; foreach ($tags as $tag) { $formattedTags[] = ['id' => $tag->tag_name, 'text' => $tag->tag_name]; } return response()->json($formattedTags); }
- Đến đây ta đã hiển thị được ra các tag của Post và suggest được các tag đã có sẵn trong database khi user nhập input. Tiếp theo trong hàm update post ta sẽ lấy ra 2 mảng
$delTags
và$addTags
như sau:$oldTags = $post->tags; // danh sách tag cũ trước khi edit, mảng này có dạng [$id => $tagName, ..] $newTags = isset($request->input['tags']) ? $request->input['tags'] : []; // danh sách các tag sau khi người dùng đã sửa, mảng có dạng [$tagName1, $tagName2,..] $delTags = array_diff($oldTags, $newTags); // mảng các tag cần xóa $addTags = array_diff($newTags, $oldTags); // mảng các tag cần thêm vào
- Như vậy ta đã có được 2 mảng cần thiết, với mỗi tag trong bảng $delTags ta sẽ tìm ra id của tag ta dùng
$tagId = array_search($tagName, $oldTags)
và xóa record ở bảngTagTopic
. Tương tự với mảng$addTags
ta duyệt từng tag nếu tag đã có trong bảngTag
thì chỉ cần insert vào bảngTagTopic
, còn chưa thì insert cả vào bảngTag
nữa. - Để giới hạn số lượng tag của bài viết và độ dài của mỗi tag, ta cần thêm đoạn js sau vào file post_edit.js
$('#tag').change(function() { var value = $(this).val(); if (value.length > 5) { $('#tag option:last').remove(); } value.forEach(function(tag) { if (tag.length > 15) { $('#tag option:last').remove(); } }); });
- Hoặc là bạn chỉ cần thêm 2 parameter của
Select2
sau:maximumInputLength: 15, maximumSelectionLength: 5,
- Trong trường hợp form submit bị lỗi, mà bạn vẫn muốn giữ các tag vừa sửa thì bạn cần sửa lại HTML như sau:
<select multiple="true" name="tags[]" id="tag" class="form-control select2"> @if (old('tags')) @foreach(old('tags') as $tag) <option value="{{ $tag }}" selected="selected">{{ $tag }}</option> @endforeach @else @foreach($topic->tags as $tagName) <option value="{{ $tagName }}" selected="selected">{{ $tagName }}</option> @endforeach @endif </select>
- Trên view ta cần tạo form edit với input tags như sau:
Tài liệu tham khảo Laravel HTTP Responses Select2
All rights reserved