I have a JSON result from a query that looks like this:
{
"id":1,
"user_id":"1",
"message":"Hello, world",
"created_at":"2016-09-22 00:32:20",
"updated_at":"2016-09-22 00:32:20",
"stats": [
...
]
},
{
"id":2,
"user_id":"1",
"message":"Hello, world",
"created_at":"2016-09-22 00:32:20",
"updated_at":"2016-09-22 00:32:20",
},
{
... more results
}
Notice that sometimes the result has a stats property and sometimes it does not (despite every record having a stats relationship). Don't ask why, that's just how I have it set up in the backend.
I want to loop through these results in my view, like this:
#foreach ($posts as $post)
#if (isset($post->stats) && !empty($post->stats)
{{ $post->stats->total }}
#endif
#endforeach
However, for post id 2, the loop will also output the $post->stats->total value because it lazy loads the stats.
How can I prevent it from lazy loading the stats relationship?
That happens because you are accessing $post->stats. You can instead check if the stats relationship is loaded or not by using the relationLoaded() method defined in Illuminate\Database\Eloquent\Model:
#foreach ($posts as $post)
#if ($post->relationLoaded('stats'))
{{ $post->stats->total }}
#endif
#endforeach
Related
I'm trying to use the PLUCK method to display two columns of a table when selecting them
$driverItems = Driver::pluck('driverName','id')->toArray();
I need to display the driver name and the Licence
pluck() will always create a single collection array (for multiple column pluck, it will be single object). Such as, this query output might look like:
{
"driverName1": 1,
"driverName2": 2,
}
You may try like following:
$driverItems = Driver::select('driverName','id')->get();
This will output like:
[
{
"id": 1,
"driverName": "driverName1"
},
{
"id": 4,
"driverName": "driverName2"
},
]
and for dropdown you can show it like:
<select >
#foreach($driveItems as $item)
<option id="" value="{{$item.id}}"> {{ $item.driverName }} </option>
#endforeach
Using pluck you can populate select
$driverItems = Driver::pluck('driverName','id')->prepend("---Select---","");
and in blade
<select name="driver_id">
#foreach($driverItems as $key=>$value)
<option value="{{$key}}">{{$value}}</option>
#endforeach
</select>
You can do it by pluck() and use Form Facade in the view file.
use Illuminate\Support\Arr;
$data = Driver::get();
$data= Arr::pluck($data, 'driverName','id');
In view file,to create dropdown use below code:
{{ Form::select('element_name',$data,['class'=>'form-control','id'=>'driver_list','placeholder'=>'-- Select --']) }}
It will create dropdown with place holder.
I want to display all user's profile into views and they posts. It's pretty simple:
#foreach($profiles as $profile)
{{ $profile->name }}
#foreach($profile->posts as $post)
{{$post->title}}
#endforeach
#endforeach
But I want to display only the latests posts (->orderBy('created_at', 'desc')->limit(4) ) and only accepted posts (->where('accept', 1)). How can I do that?
You already have what you need. You just need to put it all together.
#foreach($profile->posts()->where('accept', 1)->orderBy('created_at', 'desc')->limit(4)->get() as $post)
I would consider creating a query scope on your profile model. That way you can do something like $profile->latestPosts.
Or you can use the relationship to return exactly what you need.
public function latestPosts() {
return $this->posts()->where('accept', 1)->orderBy('created_at', 'desc')->limit(4)->get();
}
Then you could use it as:
#foreach($profile->latestPosts() as $post)
{{$post->title}}
#endforeach
A better solution would be to lazy load the posts you need when loading the profiles in the controller.
$profile = Profile::with(['posts' => function ($post) {
$post->where('accept', 1)->orderBy('created_at', 'desc')->limit(4);
}])->limit(10)->get();
then in the blade you can do the same as before
#foreach($profiles as $profile)
{{ $profile->name }}
#foreach($profile->posts as $post)
{{$post->title}}
#endforeach
#endforeach
if you want to use a scope for latestAccepted, you can on the Post model
class Post extends Model
{
public function scopeLatestAccepted($query)
{
return $query->where('accept', 1)->orderBy('created_at', 'desc')->limit(4)
}
}
Then lazy load it
$profile = Profile::with(['posts' => function ($post) {
$post->latestAccepted();
}])->limit(10)->get();
what you have to do is pretty simple.
create table users
create table post
create a relationships between the 2 tables
write you code in controller to join the table and query all the users post based on his/her username or password
see sample screenshot for table relationships
//Controller
Public function ViewPost(){
$data['data']=DB::table('useratable')
->where('useratable.username','=', $uname)
->where('useratable.password','<=',$pwd)
->leftjoin('posttable', 'useratable.idusertable', '=', 'posttable.userid')
->orderby('posttable.idposttable','desc')
->get();
}
//Route
Route::get('/view-post','YourController#ViewPost')
//view
#foreach($data as $r)
{{ $r->fullname}} <br>
{{ $r->email}} <br>
{{ $r->topic }} <br>
{{ $r->content }} <br>
{{ $r->datetime}} <br>
...
#endforeach
You need some codes like it on controller:
$profiles = Profile::with(['posts' => function ($query) {
$query->where('accept', 1)
->orderBy('created_at', 'desc');
}])->get();
And add this one to blade file:
#foreach($profiles as $profile)
{{ $profile->name }}
#foreach($profile->posts as $post)
{{$post->title}}
#if ($loop->iteration == 4)
#break
#endif
#endforeach
#endforeach
I am discovering php, laravel, vuejs at the same time and I guess there are some things I didn't get well yet ;)
I made a new component "tableau" which is a basic table and would like to use it at many places in my app, where I would just specify its title, columns and data.
FootballerController is the place where I get all my data.
Here is what is working now:
app.js
const tableau = new Vue({
components:{tableau:Tableau
},
data: function() {
return {
title: "the best footballers",
searchQuery: '',
gridColumns: ['footballer', 'cote', 'nationalite'],
gridData: [
{ footballer: 'Remond', cote: 951, nationalite:'USA' },
{ footballer: 'Marcel', cote: 935, nationalite:'ESP' },
{ footballer: 'Stian', cote: 923, nationalite:'NOR' },
{ footballer: 'Martin', cote: 923, nationalite:'USA' },
{ footballer: 'Pierre', cote: 918, nationalite:'ESP' },
]
}
}
}).$mount('#tableau');
footballer.blade.php
<tableau
v-bind:titre="title"
:rows="gridData"
:columns="gridColumns "
:filter-key="searchQuery" >
</tableau>
TableauComponent
<template>
<div >
<h1 >{{titre}}</h1>
<table >
<thead>
<tr>
<th v-for="key in columns"
{{ key | capitalize }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="entry in rows">
<td v-for="key in columns">
{{entry[key]}}
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
name:'tableau',
props: {
rows: Array,
columns: Array,
titre: String
}
}
</script>
This works.
Then, here is what I would like: being able to put my values from the controller into footballer.blade.php, which is using TableauComponent.vue
FootballerController
public function footballer($id){
//process to get all this data in DB ($footballer, $gridData, $gridColumns, $title)
$footballer= (Footballer::select(SOME REQUEST)->where('id', '=', $id)->get())[0];
return view('footballers/footballer', ['footballer' => $footballer,
'gridData' => $gridData,
'gridColumns' => $gridColumns,
'title' => $title] );
}
And in footballer.blade.php
<tableau
v-bind:titre="{{ $title }}"
:rows="{{ $gridData }}"
:columns="{{ $gridColumns }}" >
</tableau>
Then in app.js I wouldn't need data anymore
const tableau = new Vue({
components:{tableau:Tableau
}
}).$mount('#tableau');
But this doesn't work and tells me "Property or method is not defined on the instance but referenced during render"
I don't manage at all and am worndering is I have the good way of doing: Should I not get my data in FootballerController? If not, where can I get it then?
Thanks a lot in advance.
When you use {{ value }} in both Blade & javascript framework at the same time. You need to use #{{ value }} to avoid collision between Blade & Vue.
try
<tableau
v-bind:titre="#{{ $title }}"
:rows="#{{ $gridData }}"
:columns="#{{ $gridColumns }}" >
</tableau>
Besides that, when you use :rows="value", the value must be javascript syntax, otherwise when rows="value", the value would be treated as string.
You might need to use json_encode to format your data from the Laravel, or use #json if you're using Laravel 5.5^.
Your are using ':' symbol before your attributes in your blade, which means 'v-bind' as the doc says : VueJS Shorthands.
So first, for assigning a String to a props, you don't need ':' before 'titre'.
Then, to solve your problem you could try to add a default value to your props, for example :
props: {
rows: {
default: []
},
columns: {
default: []
},
titre: {
default: ''
}
}
I didn't try but I think it should works.
Thanks a lot, indeed the php array to javascript array was the issue.
In the php controller, I parse my data into json
'gridData' =>json_encode($gridData),
In the php view footballer.blade.php
<tableau
titre="{{ $title }}"
rows="{{ $gridData }}">
</tableau>
And in my Vue view, I was getting an array, and changed the code for this:
rows: {
type: String,
default: ""
}
var rowsArray = JSON.parse(this.rows)
Now it seems like the data I get after my request isn't properly parsed, but that's another point :)
I am passing one of my views a document object. Within my view, if I do
{{ $document }}
I can see the document
{
"id":2,
"projectId":1,
"name":"DocumentA"
}
This document has data, the form data that was submitted. In my view, if I do
{{ $document->documentData }}
I can see
[
{
"id":1,
"documentId":2,
"key":"_token",
"value":"WJGplDnTuMpDK7X3AD9dgIliX2SliBSz2sjxivVy"
},
{
"id":2,
"documentId":2,
"key":"teamLeader",
"value":"Jason Sullivan"
},
{
"id":3,
"documentId":2,
"key":"clientName",
"value":"Google"
},
{
"id":4,
"documentId":2,
"key":"projectName",
"value":"Analytics"
}
]
So all of this data is related to DocumentA, linked by documentId.
So my view now has this document object, and I can access the data for the document. The key is the input field, and the value was the inputted data. An input in my view generally looks like the following
{!! Form::label('teamLeader', 'Team Leader:', array('class' => 'col-sm-5 control-label green')) !!}
{!! Form::textArea('teamLeader', old('$document->documentData'), array('class' => 'form-control')) !!}
As you can see, I am trying to get the old data displayed in my edit form. This input is for teamLeader, so it should display the value where teamLeader is the key. So in the data I outputted above, you can see that this field should display Jason Sullivan.
How would I go about getting it to do this?
Thanks
Here's my category model:
public function products() {
return $this->hasMany('Product');
}
Then i am printing all products that each category has:
#foreach($category->products as $product)
{{ $product->title }}
#endforeach
However it prints every related product to this category. How can i use pagination in that case? I've tried to print pagination links at the bottom:
<div class="pager">
{{ $category->products()->paginate(12)->links() }}
</div>
It does print pagination links correctly, but when i change the page - content is not changing.
Before sending data to view first paginate the result like this.
$products = $category->products()->paginate(12);
now pass this value to the view and just iterate it.
#foreach($products as $product)
{{$product->title}}
#endforeach
To display links just call links method on the products in the view.
{{$products->links()}}
You want to call paginate your products first:
public function products() {
return $this->hasMany('Product');
}
public function recentProducts() {
return $this->products()->paginate(12);
}
Then in your view you loop through
#foreach($category->recentProducts() as $product)
{{ $product->title }}
#endforeach
Then your links
<div class="pager">
{{ $category->recentProducts()->links() }}
</div>
Pass paginated collection to the view:
// controller
$products = $category->products()->paginate(12);
// view
#foreach ($products as $product)
// do what you need
#endforeach
// links:
$products->links();