I'm working with Lumen, Vuejs and Axios. Users who are signed in can post something, and other users can like and comment on it. What I want to do is to make it obvious that someone liked the post. But I'm not able to switch the button after someone liked it.
This is my Vuejs Code:
<button class="btn btn-light" #click="likes(item.id)"><i class="far fa-heart"></i></button>
<button class="btn btn-light" #click="likes(item.id)"><i class="fas fa-heart"></i></button>
likes(id){
const axiosConfig = {
headers: {
Authorization: localStorage.getItem('token')
}
};
const postData = {
posts_id: id,
likes: true
};
axios.post('http://lumen.local/like', postData, axiosConfig)
.then(response => {
this.getPosts();
})
.catch(error => {
console.log(error)
});
},
And this is my lumen Code:
$post_query = Posts::with('comments')
->with('comments.owner')
->with('likes.isLiked')
->withCount('likes')
->where('user_id', $user->id)
->orderBy('id', 'desc')
->limit($request->limit)
->get();
I tried to make another function where I can get the user_id of the logged in user, so I can change the button with vue-if
public function checkLike(Request $request)
{
$user_name= $request->username;
$user = User::where('username', $user_name)->first();
$post_id = $request->posts_id;
$post = Posts::find($post_id);
$like = Likes::where('posts_id', $post_id)
->where('user_id', $user->id)
->get();
if(count($like) == 0){
return response()->json('no likes');
} else{
return response()->json($like);
}
}
It worked in postman, but I was not able to implement it in Vuejs, because I could not get the user_id without a v-for. So I thought I should get the user_id in the posts_query but I couldn't do it.
Do you have any ideas?
Based on the details you gave me in the comments, I can suggest you to try this.
(I have not tested it yet so ther might be some syntax errors)
In your Vue script part :
data() {
return {
currentUserId: null,
items: null,
}
},
mounted() {
this.getCurrentUserId()
this.getPosts()
},
methods: {
getCurrentUserId() {
// returns the ID of the current user
},
likes() {
// your method
},
getPosts() {
axios.get(MY_URL)
.then (res => {
const posts = res.data
/*
* creates a new array that contains each post + a boolean that indicates if
* the current user has liked or not.
*/
this.items = posts.map(post => ({
...post,
liked: this.isPostLiked(post.likes)
}))
})
.catch (err => {
console.error(err)
})
},
/*
* Not sure if your likes array is composed like this.
* This method looks for the currentUserId inside the
* likes array passed as an argument. Returns true when
* it finds one, otherwise returns false.
*/
isPostLiked(likesArray) {
likesArray.forEach(like => {
if (like.user_id === this.currentUserId) {
return true
}
}
return false
}
},
Now we should obtain an array of objects that contains each post with its liked state.
Then you only have to loop through it with a v-for in your template:
<div v-if="items !== null" class="like-buttons">
<button
v-for="(item, index) in items"
:key="'item_' + index"
class="btn btn-light"
#click="likes(item.id)"
>
<i v-if="item.liked === true" class="far fa-heart" />
<i v-else class="fas fa-heart" />
</button>
</div>
Related
I've got likes system on my website (one like button that becomes empty or filled when clicking) and it works perfectly fine in terms of server side. My issue is the likes counter. I want it to refresh likes count without page reload and cannot really figure out how. I'm kinda newbie with AJAX and that's why I'm here.
Here is my code:
CommentLikeController.php
/**
* #Route("/comments/like-unlike", name="app_comment_like_unlike")
*/
public function like(Request $request, EntityManagerInterface $entityManager): Response
{
if ($request->getMethod() === 'POST'){
//retrieve commentId from AJAX request
$commentId = $request->request->get('entityId');
//check if comment exists
$comment = $entityManager->getRepository(Comment::class)->findOneBy(['id'=> $commentId]);
// return void if not
if (!$comment){
return new JsonResponse();
}
// retrieve csrf Token from AJAX request
$submittedToken = $request->request->get('csrfToken');
// check if it's valid
if ($this->isCsrfTokenValid('comment' . $comment->getId(), $submittedToken)){
$user = $this->getUser();
$commentAlreadyLiked = $entityManager->getRepository(CommentLike::class)
->findOneBy(['user' => $user, 'comment' => $comment]);
// if user unlikes the comment, remove it from DB
if($commentAlreadyLiked){
$entityManager->remove($commentAlreadyLiked);
$entityManager->flush();
return new JsonResponse();
// if user likes the comment, add record to DB
} else{
$like = new CommentLike();
$like->setUser($user);
$like->setComment($comment);
$entityManager->persist($like);
$entityManager->flush();
}
}
}
return new JsonResponse();
}
index.html.twig
<div class="js-likes-unlikes">
<a href="{{ path('app_comment_like_unlike') }}"
id="comment-like"
data-entity-id="{{ comment.id }}"
data-csrf-token="{{ csrf_token('comment' ~ comment.id) }}"
data-liked="{{ comment.commentLikes.isEmpty == true ? '0' : '1' }}"
data-likes-counter="{{ comment.commentLikes.count }}"
class="btn-like">
<i class="♡ {{ comment.commentLikes.isEmpty == true ? '' : 'liked' }}">
{{ comment.commentLikes.isEmpty == true ? '♡' : '♥' }}
</i>
</a>
<span class="counter">{{ comment.commentLikes.count }}</span>
</div>
{% block javascripts %}
{{ parent() }}
<script src="{{ asset('js/comments_like_unlike.js') }}"></script>
{% endblock %}
comments_like_unlike.js
$(document).on('click', '#comment-like', function (e) {
e.preventDefault();
var url = $(this).attr('href');
var entityId = $(this).attr('data-entity-id');
var csrfToken = $(this).attr('data-csrf-token');
var isLiked = $(this).attr('data-liked');
var likesCounter = $(this).attr('data-likes-counter');
if (isLiked === '0') {
$(this).attr('data-liked', 1);
$('.♡').addClass('liked').text('♥')
likesCounter++;
} else {
$(this).attr('data-liked', 0);
$('.♡').removeClass('liked').text('♡')
likesCounter--;
}
$.ajax({
type: 'POST',
dataType: 'json',
data: {'entityId': entityId, 'csrfToken': csrfToken, 'likesCounter': likesCounter},
url: url,
success: function () {
console.log("success");
},
error: function () {
}
});
});
Your help and any explanations are greatly appreciated!
I tried checking and using others' examples of this part on the web but it didn't work out
Here you can do return number likes from server:
else{
$like = new CommentLike();
$like->setUser($user);
$like->setComment($comment);
$entityManager->persist($like);
$entityManager->flush();
return new JsonResponse(
'countLikes' => $like->getComment()->getCommentLikes()->count()
)
}
In twig add id to this span
<span class="counter" id="count-likes-{{ comment.id }}">{{ comment.commentLikes.count }}</span>
Ajax
success: function (response) {
// countLikes is returned in json response from the server
$('#count-likes-' + entityId).text(response['countLikes']);
},
or you can do it directly in the success function without any change in the controller and without return the numbers of likes from the server
success: function (response) {
$('#count-likes-' + entityId).text(parseInt(likesCounter) + 1);
},
I'm building a function in Laravel along with the datatables and ajax. I have a fully working page with multiple functions that return data into the databale however one of the functions doesn't like to search properly and doesn't return any data into the table.
I have a datapicker with the following code:
<div class=" input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-clock"></i></span>
</div>
<input class="form-control" type="text" data-plugin-datepicker id="lastLogged" name="lastLogged" placeholder="Owner has not logged in since:">
</div>
My search button is called: search_data
My ajax call is as followed:
<script>
$(document).on("click", "#search_data", function (e) {
e.preventDefault();
$(this).html("<i class='fa fa-circle-o-notch fa-spin'></i>");
})
$.ajax({
url: "/search/user",
type: "POST",
dataType: "json",
headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') },
data: {
loginUser : $('#lastLogged').val()
}
})
.done(function(data) {
console.log(data);
table.ajax.reload();
$('#search_data').html('<i class="fas fa-search"></i>');
})
.fail(function(data) {
console.log(data);
$('#search_data').html('<i class="fas fa-search"></i>');
});
});
My PHP controller:
public function Building(Request $request)
{
if ($request->ajax())
{
$buildings = building::with('ownerinfo');
$data = array();
$totalData = building::count();
$totalFiltered = $totalData;
$start = $request->input('start');
$order = 'id';
$dir = $request->input('order.0.dir');
// Other if statements here with functions
if(isset($request->login))
{
$date = date("Y-m-d H:i:s",strtotime($request->login));
$users = Users::where('last_login_in', '<=', $date)->get();
foreach($users as $user) {
$buildings = $buildings->where('owner', $user->id);
}
}
$buildings = $buildings->get();
if(!empty($buildings))
{
foreach ($building as $building)
{
$nestedData['id'] = $building->id;
$nestedData['name'] = $building->buildingName;
$nestedData['view'] = '<a class="button is-small full-width is-hovered" href="/view/building/' . $building->id . '">View</a>';
$data[] = $nestedData;
}
$json_data = array(
"data" => $data,
"draw" => intval($request->input('draw')),
"recordsTotal" => intval($totalData),
"recordsFiltered" => intval($totalFiltered)
);
return json_encode($json_data);
}
}
}
This keeps on returning no data at all. I am using 1 January 2019 from the datepicker to search, it has the value: 2019-01-01 00:00:00 and the data of one of the users in the database has 2018-08-20 07:11:34. I checked the queries with var_dumps and it returns the correct users, however it doesn't show any results in the buildings datatable.
The idea behind this is to let an administrator select a specific date, the database runs the search and returns buildings of users that have not logged in since the selected date.
What am I doing wrong?
The $users return the correct users but the $buildings are empty?
Try to use a hasMany relation between the User and Building it will be a better solution than this:
foreach($users as $user) {
$buildings = $buildings->where('owner', $user->id);
}
Took a few snippets from the different areas I worked on the code. I tried copying and altering the code to delete one product. Currently there is no response when clicking the delete all button I created.
Service
public function deleteAllProductsByVendorId($vendorId)
{
$this->productRepository->deleteAllProductsByVendorId($vendorId);
}
Repository
public function deleteAllProductsByVendorId($vendorId)
{
// #Todo: revisit this at a later date and determine if the vendor id is actually required
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->delete("Thinkfasttoys\Mapwatch\Entity\Product","p")
->andWhere($qb->expr()->eq('p.vendor_id', ':vendor_id'))
->setParameter(':vendor_id', $vendorId)
->getQuery()
->getResult();
}
Controller
/**
* #Route("/admin/vendor/{vendorId}/product/deleteAll", name="admin_vendor_product_delete_all_ajax", defaults={"vendorId"=""})
* #Route("/admin/vendor/{vendorId}/product/deleteAll", name="admin_vendor_product_delete_all"))
* #Secure(roles="ROLE_ADMIN")
*/
public function deleteAllProductForVendorAction($vendorId)
{
$request = $this->container->get('request');
if ($id == '') {
$this->get('session')->getFlashBag()->add('notice-error', 'Vendor Id must be supplied!');
return $this->redirect($this->generateUrl('admin_vendors_list'));
}
$vendorService = $this->get('Thinkfasttoys.MapWatch.Vendors');
$vendor = $vendorService->getProfileById($id);
if (!$vendor) {
$this->get('session')->getFlashBag()->add('notice-error', 'Vendor does not exist!');
return $this->redirect($this->generateUrl('admin_vendors_list'));
}
$user = $vendor->getUser();
if (!$user) {
$this->get('session')->getFlashBag()->add('notice-error', 'User for this Vendor does not exist!');
return $this->redirect($this->generateUrl('admin_vendors_list'));
}
if ($request->isXmlHttpRequest()) {
$productService = $this->get('Thinkfasttoys.MapWatch.Products');
$productService->deleteAllProductsByVendorId($vendorId);
return new Response(json_encode(array('status' => 'ok')),200,array('Content-Type'=>'application/json'));//make sure it has the correct content type
} else {
return $this->redirect($this->generateUrl('admin_vendor_products_edit', array('id' => $vendorId)));
}
}
View
<div class="btn-toolbar">
<a data-toggle="modal" href="#importProductsModal" id="importProducts" class="btn btn-danger">Import Products</a>
<a data-toggle="modal" href="#productModal" id="addProduct" class="btn btn-primary pull-right">Add New Product</a>
<a class="btn btn-danger pull-right" id="deleteall">Delete All</a>
</div>
Created Var deletePathAll
var vendorId = {{ vendorId }};
var getPath = '{{ path('admin_vendor_product_get_ajax', { id: vendorId } ) }}';
var editPath = '{{ path('admin_vendor_product_edit', { id: vendorId } ) }}';
var deletePath = '{{ path('admin_vendor_product_delete_ajax', { id: vendorId } ) }}';
var deletePathAll = '{{ path('admin_vendor_product_delete_all_ajax', { vendorId: vendorId } ) }}';
JS
$('#deleteall').on('click', 'table#products', function(e){
e.preventDefault();
var aData = $('#products').dataTable().fnGetData(aPos);
row.find('a').attr('disabled', true);
var rowId = aData['id'];
$.ajax({
type: "POST",
url: deletePathAll,
success: function(data) {
oTable.fnReloadAjax();
},
error: function(data) {
row.find('a').attr('disabled', false);
}
});
});
Pretty sure your Product entity doesn't have the property vendor_id but vendor.
In this case this should correct the issue
->andWhere($qb->expr()->eq('p.vendor_id', ':vendor_id'))
should be replaced with
->andWhere($qb->expr()->eq('p.vendor', ':vendor_id'))
I am doing a project in laravel and i want to change a value of a column from 0 to 1 when a button is clicked.
i am using ajax to do this.
view.blade
<td><button type="button" class="btn btn-primary" id="j-approve-user" onclick="approveLogin('{{ route('approve', $user->id) }}')">Approve</button></td>
ajax script:
let getToken = function() {
return $('meta[name=csrf-token]').attr('content')
}
function approveLogin(url){
let data = { '_token': getToken() }
$.ajax({
'url': url,
'method': 'POST',
'data': data,
}).done(function(response) {
//window.location.reload()
})
}
Controller:
public function approve($user_id)
{
$user = User::find($user_id);
$user->update(['loginapproval'=>'1']);
return "ok";
}
However, i am getting a status code of 500 when i click the button.
Can anyone please help?
500 error is caused because a variety of erros, things you may look it up:
have you checked your laravel error log? storage/logs/laravel.log The answer may be there!
is your model loginapprovalattribute fillable, not mass assignment?
have you check whether the $user_id or the mode is null then you're trying to update a null model:
Your code.
public function approve($user_id)
{
$user = User::find($user_id);
if (!is_null($user)) {
$user->update(['loginapproval'=>'1']);
return "ok";
}
}
I'm to trying to store a sort order to each article within a help centre for my new site using Laravel 5 and having a bit of trouble getting it to work. I'm using jQuery UI's .sortable for arranging the elements on the page, and since there are going to be multiple sections throughout the site where areas are sortable, my jQuery script is built in a way for a 'one script for all' purposes. Hence the use of data-* attributes and route name references.
Here is the code I've got so far:
routes.php
Route::post('admin/help-centre/category/{category_id}/section/{section_id}/article/sort-order', 'AdminHelpCentreArticleController#sortOrder');
AdminHelpCentreArticleController.php
public function sortOrder($category_id, $section_id)
{
/* Return ------------------------------------- */
return [
'category_id' => $category_id,
'section_id' => $section_id
];
}
show.blade.php (Admin Article Listing)
<ul id="help-center-articles-sort" class="sortable">
#foreach ($helpCentreArticles as $helpCentreArticle)
<li class="sortable-element" data-sortable-element-id="{{ $helpCentreArticle->id }}">
{{ $helpCentreArticle->title }}
</li>
#endforeach
</ul>
Save Order
scripts.js (includes CSRF Token _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);
},
});
});
});
Everything so far is working in terms of the return response in the console, which is Object {category_id: "1", section_id: "1"}. But no matter what I try, I cannot seem to pass through the data map to the controller to use it.
I've tried a bunch of guesswork since I cannot find a single decent tutorial on AJAX in Laravel 5 anywhere, and I've tried things such as adding a $data parameter to the sortOrder() method, I've tried Input::all() and Request::all but it all returns errors (I'm guessing cause it's not an actual form?).
Once I've got the data to be passed through to the controller I'll be able to save the sort order to the database easily enough. But I can't quite get to that stage, any ideas?
EDIT
I should probably note that I do have a HelpCentreArticle model and a HelpCentreArticleRequest request too, here's some of the code from each file in case they are also needed:
HelpCentreArticle.php
class HelpCentreArticle extends Model {
protected $fillable = [
'category_id',
'section_id',
'title',
'content',
'excerpt',
'is_visible',
'sort_order',
'created_by',
'updated_by',
];
}
HelpCentreArticleRequest.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;
}
}
I wasn't sure if I needed to add HelpCentreSectionRequest $request as the last parameter of the sortOrder() method, so I could use $request->all() but it just returns a 422 (Unprocessable Entity) in the console log.
So it appears that the correct way was to use Input::get('id_array'); instead of $_POST['id_array'];, which I tried, but when I originally tried this I wasn't including use Input; at the top of my controller, as I thought this was already accessible, but it wasn't.
Adding use Input;, and using Input::get(); is now working as expected.
Here is the updated code:
AdminHelpCentreArticleController.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];
}
Then you can obviously access success for an if else statement in your jQuery to manipulate the page.
My implementation of UI sortable with Laravel
index.blade.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>
scripts.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();
}