Laravel - Pagination doesn't work well - php

I have a view with a table and pagination for this table but when i use de pagination the view is duplicated.
my controller function:
public function index()
{
$items = Items::where('active', '=', 1)->paginate(5);
if (Request::ajax())
{
return View::make('app/items.index')->with('items', $items)->render();
}
else
{
return view('app/items.index', array('items' => $items));
}
}
my jquery:
function pagination()
{
$(document).on("click", ".pagination a", function(e)
{
e.preventDefault();
alert($(this).attr('href'));
$.ajax({
url: $(this).attr('href'),
})
.done(function(data)
{
console.log(data);
$('#listSearchItems').html(data);
});
});
}
my view:
#section('content')
<div class="header"></div>
<div id="listSearchItem" class="content">
<table>
</table>
#if($items->render())
<nav class="pagination">
<a href="{{$items->previousPageUrl()}}">
<i class="material-icons">arrow_back</i>
</a>
<a href="{{$items->nextPageUrl() }}">
<i class="material-icons">arrow_forward</i>
</a>
</nav>
#endif</div>#stop
And when i click at pagination button, the view code is all duplicated within the , the table information is updated but also adds all existing html of view, duplicating code.
Anyone can help me? I already search a lot about this problem, i don't know if is the how to return the information in the controller.
Thank's

there have some problems with your code.
first why you need ajax to render your datas?
if you need use ajax render datas, your controller should be like this:
public function index()
{
$items = Items::where('active', '=', 1)->paginate(5);
if (Request::ajax())
{
$datas = $items->items();
$results = '';
foreach ($datas as $item) {
$results .="<tr><td>{$item->whateverInYourTable}</td><td>{$item->whateverInYourTable}</td></tr>"
}
return $results;
}
else
{
return view('app/items.index', array('items' => $items));
}
}
if you don't need ajax controller should be like this:
public function index()
{
$items = Items::where('active', '=', 1)->paginate(5);
return view('app.items.index', array('items' => $items));
}
view like this:
<nav class="pagination">
{!! $items->render() !!}
</nav>

Related

search filter is not fetching data until clicking on search button

It's a laravel vuejs project. Here is the photo of my product page :
Products were supposed to display at that page, but it's completely null until I am clicking on the search button . After clicking on the search button, the page loads the products and the search option working as well.
My codes are :
web.php ->
Route::get('/', 'App\Http\Controllers\Mastercontroller#index');
Route::get('/search', 'App\Http\Controllers\Mastercontroller#search');
Route::any('{slug}', 'App\Http\Controllers\Mastercontroller#index');
Mastercontroller.php ->
<?php
namespace App\Http\Controllers;
use App\Models\myproductcase;
use Illuminate\Http\Request;
class Mastercontroller extends Controller
{
public function index(){
return view('welcome');
}
public function search(Request $r){
$search = $r->get('q');
return myproductcase::where('name','LIKE','%'.$search.'%')->get();
}
}
productpage ->
<template>
<div>
<div class="search"><input v-model="search" type=text></input><button
#click.prevent="makesearch()">Search</button></div>
<div class="product-list">
<div v-if="showsearch==true">
<div v-for="getresult in getdata" v-bind:key="getresult.id">
<div class="product">
<h1>{{getresult.name}}</h1>
<h3>{{getresult.price}}</h3>
<p>{{getresult.description}}</p>
</div>
</div>
<div v-if="showsearch==false">
no data found
</div>
</div>
</div>
</div>
</template>
<script>
export default{
data(){
return{
search : '',
showsearch : false,
getdata : []
}
},
methods : {
async makesearch(){
fetch('/search?q='+this.search).then(hi=>hi.json()).then(hi=>{
console.log();
this.getdata = hi;
this.search = '';
this.showsearch = true;
}).catch(err=>{
console.log(err);
});
}
},
}
</script>
The problem is when you load the page for the first time, there is not get query parameter in your url, so in the line
$search = $r->get('q'); // Is equal to NULL
The query that you are doing the first time is:
return myproductcase::where('name','LIKE','%NULL%')->get();
You could use the syntax below for setting up a default parameter
$search = $r->get('q', 'default value' );
PD: Be careful with SQL Injection Read this
Edit:
Also in your Component call in your mounted method the makesearch method.
data(){
...
}
...
mounted(){
this.makesearch()
}

Passing multiple variable with axios to controller laravel

I'm trying to insert a lecture id a students table. I need to pass the student's id as well as the lecture's to the controller. I'm using axios to post 2 parameters to the controller. My codes not working, did i do it wrong? New in Laravel. thanks
Vue Component
<i class="fas fa-user-plus"></i>
<script>
export default {
data () {
return {
student:'',
lecture_id:this.$route.params.id,
}
},
methods:{
setLectureFK($student_id){
axios.post('/api/internship/setLecture/'+$lecture_id,'/'+$student_id);
}
},
}
Controller
public function setLecture($lecture,$student)
{
$student = student::findOrFail($student);
$student->lecture_id_FK = $lecture;
$student->save();
}
API.PHP
Route::post('internship/setLecture/{lecture}/{student}', 'API\InternshipController#setLecture')->name('internship.setLecture');
As far as I can see there is the syntax error in your vue component .
In this line
axios.post('/api/internship/setLecture/'+$lecture_id,'/'+$student_id);
You have put the comma instead of + it should be like this
axios.post('/api/internship/setLecture/'+$lecture_id+'/'+$student_id);
Try this:
Vue Component
<i class="fas fa-user-plus"></i>
<script>
export default {
data () {
return {
student:'',
lecture_id:this.$route.params.id,
}
},
methods:{
setLectureFK(student_id){
axios.post('/api/internship/setLecture',{student_id:student_id,lecture_id:this.lecture_id});
}
},
}
Controller
public function setLecture(Request $request)
{
$student = student::findOrFail($request->student_id);
$student->lecture_id_FK = $request->lecture_id;
$student->save();
}
api.php
Route::post('internship/setLecture', 'API\InternshipController#setLecture')->name('internship.setLecture');

Display list Vue Axios with Laravel

I'm new to laravel, axios and vue and I used this tutorial to help make a ToDo list:
I want to tweak the basic tutorial by allowing different users to store and view their tasks. I added new user registration and login, but each user would see everyone's list, not only theirs. So I made a one to many relationship between the User and Task model and added these methods to the models:
class User extends Authenticatable
{
...
public function tasks()
{
return $this->hasMany('App\Task');
}
}
class Task extends Model
{
...
public function user()
{
return $this->belongsTo('App\User');
}
}
I updated TaskController.php and TaskList.vue to display only the active user's tasks, but now in the view no list appears and new tasks can't be added.
Here is the code for the two. Everything is the same as the tutorial, except I commented next to the parts that I added:
<?php
namespace App\Http\Controllers;
use App\Task;
use Illuminate\Http\Request;
class TaskController extends Controller
{
$user = Auth::user(); //Added by me
public function index()
{
return Task::latest()->where('user_id', $user->id)->get(); //Added by me,
//this query returns whats expected in php artisan tinker
//was previously return Task::latest()->get();
//I also tried this: return $this->user->tasks->toJSON()
}
public function store(Request $request)
{
$this->validate($request, [
'body' => 'required|max:500'
]);
return Task::create([
'body' => request('body'),
'user_id' => $user->id //Added by me
]);
}
public function destroy($id)
{
$task = Task::findOrFail($id);
$task->delete();
return 204;
}
}
In TaskList.vue
<template>
<div class='row'>
<h1>My Tasks</h1>
<h4>New Task</h4>
<form action="#" #submit.prevent="createTask()">
<div class="input-group">
<input v-model="task.body" type="text" name="body" class="form-control" autofocus>
<span class="input-group-btn">
<button type="submit" class="btn btn-primary">New Task</button>
</span>
</div>
</form>
<h4>All Tasks</h4>
<ul class="list-group">
<li v-if='list.length === 0'>There are no tasks yet!</li>
<li class="list-group-item" v-for="(task, index) in list">
{{ task.body }}
<button #click="deleteTask(task.id)" class="btn btn-danger btn-xs pull-right">Delete</button>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
list: [],
task: {
id: '',
body: '',
user_id: '' ///Added by me
}
};
},
created() {
this.fetchTaskList();
},
methods: {
fetchTaskList() {
axios.get('api/tasks').then((res) => {
this.list = res.data;
});
},
createTask() {
axios.post('api/tasks', this.task)
.then((res) => {
this.task.body = '';
this.task.user_id = ''; ///added by me
this.edit = false;
this.fetchTaskList();
})
.catch((err) => console.error(err));
},
deleteTask(id) {
axios.delete('api/tasks/' + id)
.then((res) => {
this.fetchTaskList()
})
.catch((err) => console.error(err));
},
}
}
</script>
</script>
The app worked until I added the few lines mentioned above. Now nothing shows in the display and no new tasks can be added. I am new to laravel and totally new to axios and vue, but to me it seems like what I added should work. There are no error messages when I run it, it just doesn't produce what I want.

Laravel 5: Call to a member function sum() on null and other persistence issues

I have a threaded-comments list each with an upvote/downvote button using jquery.upvote.js.
The voting action is done through ajax and it works, making an upvote or a downvote gets registered in the database with the correct values. Removing the vote will delete the record from the database. So technically it works as intended.
However, I have 2 problems:
The votes that the user has made do not persist after page reload which is important otherwise users won't know what they voted on.
When I add this chunk of code {{ $each_comment->commentvotes->sum('value') }} to the view to grab the sum of the votes on a given comment, I get the following error:
Call to a member function sum() on null
Routes
Route::resource('votes', 'VotesController');
Route::resource('commentvotes', 'CommentVotesController');
I'd like to point out that I've used the same method successfully on posts' votes with Vote model and VoteController.
CommentVote model
class CommentVote extends Model
{
protected $table = 'commentvotes';
protected $fillable = [
'value',
'comment_id',
'user_id'
];
public function user() {
return $this->belongsTo('App\User');
}
public function posts() {
return $this->belongsTo('App\Comment');
}
}
CommentVotesController
class CommentVotesController extends Controller
{
public function __construct() {
$this->middleware('auth', ['only' => ['create', 'edit'] ]);
}
public function store(Requests\CommentVoteRequest $request)
{
$commentId = $request->input('commentId');
$userId = $request->user()->id;
$value = $request->input('value');
// Check to see if there is an existing vote
$vote = CommentVote::whereCommentId($commentId)->whereUserId($userId)->first();
if (!$vote)
{
// First time the user is voting
CommentVote::create(['comment_id' => $commentId, 'user_id' => $userId, 'value' => $value]);
} else {
$vote->value == $value ? $vote->delete() : $vote->update(['value' => $value]);
}
// AJAX JSON RESPONSE
return response()->json(['status' => 'success',
'msg' => 'Vote has been added.']);
}
}
Javascript
$(document).ready(function() {
$('.topic').upvote();
$('.comment').upvote();
$('.vote').on('click', function (e) {
e.preventDefault();
var $button = $(this);
var postId = $button.data('post-id');
var value = $button.data('value');
$.post('http://localhost/r2/public/votes', {postId:postId, value:value}, function(data) {
if (data.status == 'success')
{
// Do something if you want..
}
}, 'json');
});
$('.commentvote').on('click', function (e) {
e.preventDefault();
var $button = $(this);
var commentId = $button.data('comment-id');
var value = $button.data('value');
$.post('http://localhost/r2/public/commentvotes', {commentId:commentId, value:value}, function(data) {
if (data.status == 'success')
{
// Do something if you want..
}
}, 'json');
});
});
Relevant part of the view comment_list.blade.php
#foreach($comments as $each_comment)
<div class="col-md-1">
<div class="upvote comment" data-comment="{{ $each_comment->id }}">
<a class="upvote commentvote {{ $each_comment->commentvotes && $each_comment->commentvotes->contains('user_id', Auth::id()) ? ($each_comment->commentvotes->where('user_id', Auth::id())->first()->value > 0 ? 'upvote-on' : null) : null}}" data-value="1" data-comment-id="{{ $each_comment->id }}"></a>
<!-- Notice how we set the sum of the votes for this post here -->
<span class="count">{{ $each_comment->votes->sum('value') }}</span>
<a class="downvote commentvote {{ $each_comment->commentvotes && $each_comment->commentvotes->contains('user_id', Auth::id()) ? ($each_comment->commentvotes->where('user_id', Auth::id())->first()->value < 0 ? 'downvote-on' : null) : null}}" data-value="-1" data-comment-id="{{ $each_comment->id }}"></a>
</div>
</div>
#endforeach
You have to define the relation inside the Comments model. Otherwise the CommentVotes will not be accessible to Comment entities.

jQuery: Comment list disappears on ajax form submission

This may be a bit confusing but I will do my best to explain what I'm trying to achieve.
I have a comment form on each post page, users can submit comments via an ajax form and the submitted comment will be displayed below the form without page reload.
All of this works, until I instruct the comments to show based on their post_id and the current post id I'm viewing.
When I do that, each post will start showing its comments only but when I try to submit a comment, the comment_list.blade.php loads an empty list of comments instead of adding the new comment to the already existing ones. I have to refresh the page manually to be able to see the comments.
I have 4 views for the comments:
leave_a_comment.blade.php (has 2 includes to comment_fields and
comment_list)
comment_fields.blade.php (the comment form)
comment_list.blade.php (the comment list)
cancel_reply.blade.php (to
close a reply window)
EDIT: I think I found the problem. in comment.js the comment_done_handler() function is not returning any data.
So if I comment out $('.comment-list').html(data.comment_list); the comment list doesn't disappear on new submission. But of course the newly added comment isn't visible until I reload the page.
EDIT 2: actually it's data.comment_list that is being returned empty in comment.js comment_done_handler(data) method.
comment.js
$(document).on('click', 'a.post-this-comment', function(){
var form_data = {
'per_page': $('.comments_per_page').val(),
'commenter_parent': $('#commenter_parent').val(),
'commenter_post': $('#commenter_post').val(),
'commenter_comment': $('#commenter_comment').val(),
'postid': $('#postid').val(),
};
var arr = [
'commenter_parent',
'commenter_post',
'commenter_comment',
'postid'
];
for (var i in arr, i < arr.length, i++) {
var elem = arr[i];
form_data[elem] = $('#' + elem).val();
}
// console.log(form_data); // something like => Object {per_page: "some_value", commenter_parent: "some_value", commenter_user_id: "some_value", commenter_comment: "some_value"}
var request = $.ajax({
type: 'POST',
url: 'post_this_comment',
data: form_data,
dataType: 'json'
});
request.done(comment_done_handler);
request.fail(comment_fail_handler);
});
function comment_done_handler(data){
console.log(data); // data is sent from server
$('.comment-content').append($('.reply-content .comment-fields'));
$('.comment-list').html(data.comment_list); // put new list
$('#captcha-image').attr('src', data.captcha); // put new captchas
clear_input_fields();
remove_error_messages(data);
hide_comment_fields();
}
Comment Model
public static function root_comments($postId) {
return self::child_comments(0, 'desc')->where('post_id', $postId);
}
public static function child_comments($parent_id, $order='asc'){
return self::where('parent_id', $parent_id)->orderBy('created_at', $order)->get();
}
public function posts() {
return $this->belongsTo('App\Post');
}
public function user() {
return $this->belongsTo('App\User');
}
CommentController
protected function comment_list($per_page, Request $request, Post $post) {
$postId = $post->id;
$root_comments = Comment::root_comments($postId);
$root_with_replies = $this->include_replies_for($root_comments);
$paginated_comments = $this->paginate($root_with_replies, $per_page, $request);
return $paginated_comments;
}
public function index(Request $request, Post $post){
$view_data = self::view_data($request, $post);
return view('eastgate.comment.leave_a_comment', $view_data);
}
public static function view_data(Request $request, Post $post) {
$instance = new Self;
$per_page = session('per_page')?session('per_page'):config('constants.per_page'); // default per page on opening the comment page
$result['per_page'] = $per_page;
$result['comments'] = $instance->comment_list($per_page, $request, $post);
$result['total_comments'] = $instance->total_comments();
$result['captcha_builder'] = $instance->captcha_builder();
return $result;
}
public function post_this_comment(Request $request, Post $post) {
$comment = new Comment;
$comment->user_id = Auth::id();;
$comment->comment = Input::get('commenter_comment');
$comment->post_id = Input::get('commenter_post');
$comment->parent_id = Input::get('commenter_parent');
if($comment->parent_id > 0){
$my_parent = Comment::find($comment->parent_id);
$comment->parents = $my_parent->parents.'.'.$comment->parent_id;
}else{
$comment->parents = '0';
}
$comment->save();
$per_page = Input::get('per_page');
$comment_list = view('eastgate.comment.comment_list')
->with('comments', $this->comment_list($per_page, $request, $post))
->with('total_comments', $this->total_comments())
->with('per_page', $per_page)
->render();
$response = array(
'status' => 'success',
'msg' => 'Comment Saved!',
'comment_list' => $comment_list,
'captcha' => $this->captcha_builder()->inline()
);
return Response::json($response);
}
comment_fields.blade.php
<div class="comment-fields">
<div class="row commenter-comment">
<div class="form-group col-md-12">
<textarea id="commenter_comment" name="commenter_comment" class="form-control comment-field" title="User's comment" placeholder="Comment Text"></textarea>
</div>
</div>
<div class="row commenter-name-email">
<input type="hidden" id="commenter_parent" name="commenter_parent" class="commenter-parent" value="0">
<input type="hidden" id="commenter_post" name="commenter_post" class="commenter-post" value="{{ $post->id }}">
</div>
<div class="row commenter-captcha">
<div class="col-md-3">
Comment
</div>
</div>
</div>
comment_list.blade.php
<div class="comment-list">
<div class="row">
<div class="col-xs-12">
<h2>{!! $total_comments !!} comment(s) </h2>
#foreach($comments as $each_comment)
<?php
$name_for_display = $each_comment->user->name;
$date_for_display = $each_comment->created_at->diffForHumans();
$parent_name_for_display = '';
if($each_comment->parent_id > 0){
$parent_comment = $each_comment->parent();
$parent_name_for_display = $parent_comment != null && $parent_comment->name
? $parent_comment->name : 'Anonymous';
$parent_name_for_display = '<span class="glyphicon glyphicon-share-alt" title="Reply to"> </span>'.$parent_name_for_display;
}
$parents_count = substr_count($each_comment->parents, '.');
$offset_length = $parents_count;
$comment_length = 12 - $offset_length;
?>
<div class="col-xs-offset-{!! $offset_length !!} col-xs-{!! $comment_length !!}">
<input type="hidden" id="postid" name="postid" class="post-id" value="{{ $each_comment->post_id }}">
<ul class="list-inline">
<li class="comment-by">{!! $name_for_display !!}</li>
#if($parents_count > 0)
<li class="reply-to">{!! $parent_name_for_display !!}</li>
#endif
<li class="separator"></li>
<li class="comment-on">{!! $date_for_display !!}</li>
</ul>
<p>{!! $each_comment->comment !!}</p>
Reply
<div class="reply-content reply{!! $each_comment->id !!}"></div>
<hr>
</div>
#endforeach
</div>
</div>
<div class="row">
<div class="col-xs-12">
{!! $comments->render() !!}
</div>
</div>
<div class="row">
<div class="col-xs-12">
Show <input type="text" name="comments_per_page" class="comments_per_page" value="{!! $per_page !!}" size="2" title="Number of comments per page"> comments per page
</div>
</div>
</div>
Please note that if I remove where('post_id', $postId) from Comment Model, it will start working and reloads the correct comment_list with the newly added comment.
I hope that makes sense, and shows the problem I'm facing.
I didn't attempt to execute the code, but this is suspicious:
public static function root_comments($postId) {
return self::child_comments(0, 'desc')->where('post_id', $postId);
}
public static function child_comments($parent_id, $order='asc'){
return self::where('parent_id', $parent_id)->orderBy('created_at', $order)->get();
}
root_comments(referenced in the controller's comment_list action) is chaining child_comments. Except child_comments does not return a query builder object, it returns a collection. You need to remove the get() call from child_comments, and instead only use get() when you're completely done with building your query.
Also, check out query scopes which is a much nicer way of accomplishing what you are trying to do.
Edit 1 - Example (using scopes):
I did not run this code, so there my be syntax errors. This is to better explain the concept.
//First, you need to create scopes on the model
public function scopeByParent($query, $parentId, $order = 'asc') {
return $query->where('parent_id', $parentId)->orderBy('created_at', $order);
}
public function scopeForPost($query, $postId) {
return $query->where('post_id', $postId);
}
//Then, change your existing methods...
public static function root_comments($postId) {
return self::byParent(0, 'desc')->forPost($postId)->get();
}
public static function child_comments($parent_id, $order = 'asc') {
return self::byParent($parent_id, $order)->get();
}
Now these are both returning collections as you'd expect. And you can reuse these scopes elsewhere when you need to retrieve the comment records.
Edit 2:
The above is part of the problem. The second part of the problem is that you were never retrieving the post that the comment was posted for. I made this change locally and it started to work:
public function post_this_comment(Request $request, Post $post) {
//...
$per_page = Input::get('per_page');
//After line 148. The $post that is created by the IoC container is just a reference to the class. You still must load the post from the DB to get the proper data from it.
$post = $post->find($request->commenter_post);
$comment_list = view('eastgate.comment.comment_list')
//...
}
EDIT:
Try this:
public static function root_comments($postId) {
return self::child_comments(0, 'desc')->where('post_id', $postId)->get();
}
-- Before edit ---
Your comment_done_handler doesn't fetch the newly created comment list.
You should make another ajax request inside, or maybe as a separate function
function comment_done_handler(data){
var data = $.ajax({
// ......
// params sent for this request to comment_list controller method
data: {
per_page: 10,
request: request,
post: post_id
},
type: 'GET',
url: 'comment_list'
// ......
}).done(function() {
// ....
}).fail(function(){
// ....
});
console.log(data); // data is retrieved from server
$('.comment-content').append($('.reply-content .comment-fields'));
$('.comment-list').html(data.comment_list); // put new list
$('#captcha-image').attr('src', data.captcha); // put new captchas
clear_input_fields();
remove_error_messages(data);
hide_comment_fields();
}

Categories