Laravel Display a record details while grouped by year or month - sql

I just moved to the laravel framework and am starting to migrate some legacy sites and I have hit a problem with SQL or blade - dunno which.
I have to display a load of rows 'sports classes' which are grouped by year and then month. each needs to show attendance etc.
I am unsure which way to proceed.
I am able to display all rows and sort by date - easy squeezy
I am able to groupBy year AND month - fiddly but sorted it.
These are all displayed in an accordian.
Click the month - the individual rows drop down - you get the idea
I can get a number of rows per month/year
What I am unable to figure out is how to actually display the rows.
The groupBy is this:
$LinkClasses = DB::table('classes_lists')
->select('id, class, teacher, size')
->select(DB::raw('YEAR(date) AS year, MONTH(date) AS month, MONTHNAME(date) AS month_name, COUNT(*) post_count'))
->groupBy('year')
->groupBy('month')
->orderBy('year', 'desc')
->orderBy('month', 'desc')
->orderBy('id', 'desc')

If the code you provided is within your controller, then you can append ->get() after your last ->orderBy(). This will return a Collection. You can then do whatever you want with the Collection (http://laravel.com/api/master/Illuminate/Support/Collection.html), including conversion to an array using ->toArray(), but I think it would be best to utilize the Eloquent ORM if possible.
Anyway, once you have it in the format you want, just pass it to the view like so:
return view('your.view', compact('LinkClasses'));
Then, inside the your.view blade template, you can access this by using the following:
#foreach ($LinkClasses as $currentRow)
<tr>
<td>{{ $currentRow['id'] }}</td>
<td>{{ $currentRow['class'] }}</td>
<td> ... </td>
</tr>
#endforeach
Best guess I can offer without seeing the blade template to get a better idea of what you're doing. Hope that helps!
UPDATE BASED ON OP FEEDBACK:
Since you are only receiving a single record, it seems as though the issue lies in your query. I suggest you simplify your query to fetch all records and then do your sorting within an array. Something like this in your controller:
$allClasses = DB::table('classes_lists')->all();
foreach ($allClasses as $currentClass) {
$yearMonth = date('Y-m', $currentClass['date']);
$classesByYearMonth[$yearMonth][] = $currentClass;
}
ksort($classesByYearMonth);
/* now you have an array of all classes sorted by year-month like this:
// $classesByYearMonth[2014-01] = array(
// [0] => array(1, 'class name', 'teacher name', 23),
// [1] => array(2, 'another class', 'different teacher', 25),
// ...
// );
//
// $classesByYearMonth[2014-02] = ...
*/
return view('your.view', compact('classesByYearMonth'));
Then, inside your blade template:
#foreach ($classesByYearMonth as $yearMonth => $classListArray)
Found {{ sizeof($classListArray) }} classes for {{ $yearMonth }}
#foreach ($classListArray as $currentClass)
<div>
<div>ID: {{ $currentClass['id'] }}</div>
<div>Class: {{ $currentClass['class'] }}</div>
<div>Teacher: {{ $currentClass['teacher'] }}</div>
<div>Size: {{ $currentClass['size'] }}</div>
</div>
#endforeach
#endforeach
I will leave it to you to fix the formatting to make your accordion work. But hopefully that will get you on the right path.

DNoe - thank you so much.
Your reply put me on exactly the right track.
I had to mod some bits due to laravel ambiguities and add the strtotime but the logic was all there.
foreach ($allClasses as $currentClass) {
$ym = $currentClass['date'];
$yearMonth = date("Y-m",strtotime($ym));
$classesByYearMonth[$yearMonth][] = $currentClass;
}
krsort($classesByYearMonth);
return View::make('classes.index', compact('classesByYearMonth'));
The css is simple from here.
I owe you some beers. And thanks for helping me take my head from my butt!
Send me a pm and i would be very very happy to forward beer donation :o
Great work and thank you again. :)

Also, part of the problem was that the results were throwing an stdObject rather than an array.
Being able to compare your code with my own has enabled me to create a dbquery with multiple joins from which meaningfull data is selected and then converted to an array.
$classes = DB::table('table2')
->join('table1', 'table2.id', '=', 'table1.id2' )
->join('table3', 'table1.id3', '=', 'table3.id' )
->orderBy('classes_lists.date','DESC')
->get(array('table1.id', 'teacher', 'date', 'size', 'students', 'fname', 'classname', 'table1.notes'));
$cfr = count($classes);
foreach($classes as $object)
{
$arrays[] = (array) $object;
}
foreach ($arrays as $currentClass){
$ym = $currentClass['date'];
$yearMonth = date("Y-m",strtotime($ym));
$clazByYearMonth[$yearMonth][] = $currentClass;
}
krsort($clazByYearMonth);
This was the output into blade:
Not formatted :
#foreach ($clazByYearMonth as $yearMonth => $classListArray)
Found {{ sizeof($classListArray) }} classes for {{ $yearMonth }}
#foreach ($classListArray as $currentClass)
<div>
date: {{ $currentClass['date'] }} | class: {{ $currentClass['classname'] }} | Size: {{ $currentClass['size'] }} Teacher: {{ $currentClass['fname'] }} |
</div>
#endforeach
#endforeach

Related

filter an object key:val in vue

I have an object with key:val I want to filter the object by value like "ג6"
how i do that? I dont have alias name for search
this is the object
specialityTest={
"4969": "ג6",
"4973": "ג19",
"5163": "ה",
"5165": "ה1",
"5200": "ה2",
"5486": "גן1"
}
I want to do
this.nurseListSpeciality2 = this.specialityTest.filter((el) => {
return el.value == "fffff";
});
I get an error:
this.specialityTest.filter is not a function
how can I filter this object?
You can use Object.keys for filtering your keys where the values match.
this.nurseListSpeciality2 = Object.keys(this.specialityTest).filter((val) => this.specialityTest[val] === "ג6");
Finally, when rendering you can loop over the array of keys that will be returned and the render values associated with those keys
<ul>
<li v-for="val in nurseListSpeciality2" :key="val">
{{ specialityTest[val] }}
</li>
</ul>

ASP.NET Core MVC Group by query with LINQ

I am trying to query the country column from one of my table and trying to group them so that one country name appears only once.
The controller code is
ViewBag.Countries = (from pT in _context.InfoProducts
group pT by new { pT.Country } into g
select new
{
Country = g.Key.Country
}).ToList();
In my view I am trying to show this list of countries in a dropdown like this
<div class=" form-group">
#Html.Label("Country")
<div class="col-md-12 ">
#Html.DropDownList("Country", new SelectList(ViewBag.Countries, "Country"), "Select Country", new { #class = "col-form-label col-md-12 label-align" })
</div>
</div>
The problem I am facing is though it is returning the expected names of the countries, the result is generating as a key, value pair something like
{Country = USA}
{Country = Canada}
The HTML generated copied from inspect element is given below
<select class="col-form-label col-md-12 label-align" id="Country" name="Country">
<option value="">Select Country</option>
<option>{ Country = USA}</option>
<option>{ Country = Canada}</option>
</select>
How can I get only the country name in the dropdown instead of the result I am currently getting.
Rather than using group by, it sounds like distinct would be a better fit:
_context.InfoProducts.Select(x => x.Country).Distinct().ToList();
This will give you back a list of strings to use, which won't give you the key-value pair problem you're currently having.
One more thing, when you use new SelectList(ViewBag.Countries, "Country") this overload of SelectList's constructor will try to set the value of Country as the selected item, but this doesn't exist in your list, so Select Country will always appear as selected. If you want that to select an actual country, then it would have to look something like:
new SelectList(ViewBag.Countries, "Canada")
where you would fetch Canada from the data for the current product.

How do I check if collection contains an object with a specific key in handlebars

Assuming custom_fields contains this data, and I want to find out if it has an item/object with the name = "hide_options". I want to pass this to a component.
WARNING
Using occurrences in this way is a hack. If the name isn't unique enough, you may get false-positives
[
{"id":"12","name":"hide_options","value":"true"},
{"id":"13","name":"state","value":"colorado"},
{"id":"14","name":"city","value":"colorado, springs"}
]
The closest I've come up with is this:
templates\components\products\product-view.html
{{> components/products/conditionallyVisibile
hideOptions=(occurrences (join (pluck product.custom_fields "name") ",") "hide_options")
}}
components/products/conditionallyVisibile.html
<div>
hideOptions {{ hideOptions }}
</div>
Am I missing an easier Array or Collection helper that would make this easier? Most of the Array/Collection helpers are block helpers.
EDIT:
I was missing a significantly easier way to do this via the Filter Array Helper
{{#filter product.custom_fields "hide_options" property="name"}}
{{> components/products/conditionallyVisibile hideOptions=true }}
{{else}}
{{> components/products/conditionallyVisibile hideOptions=false }}
{{/filter}}
EDIT 2:
the scalar-form of
(occurrences (join (pluck product.custom_fields "name") ",") "hide_options")
is almost-equivalent to the block-form
{{#inArray (pluck product.custom_fields 'name') 'hide_options' }}

how can get index & count in vuejs

I have code like this (JSFiddle)
<li v-for="(itemObjKey, catalog) in catalogs">this index : {{itemObjKey}}</li>
Output:
this index: 0
this index: 1
My question is:
How can I get value index first begin: 1 for example I want
output like this: this index: 1 this index: 2
How can I get count from index, i.e. output like this: this index: 1 this index: 2 this count: 2 field
you can just add 1
<li v-for="(catalog, itemObjKey) in catalogs">this index : {{itemObjKey + 1}}</li>
to get the length of an array/objects
{{ catalogs.length }}
In case, your data is in the following structure, you get string as an index
items = {
am:"Amharic",
ar:"Arabic",
az:"Azerbaijani",
ba:"Bashkir",
be:"Belarusian"
}
In this case, you can use extra variable to get the index in number:
<ul>
<li v-for="(item, key, index) in items">
{{ item }} - {{ key }} - {{ index }}
</li>
</ul>
Source: https://alligator.io/vuejs/iterating-v-for/
Alternatively, you can just use,
<li v-for="catalog, key in catalogs">this is index {{++key}}</li>
This is working just fine.
The optional SECOND argument is the index, starting at 0. So to output the index and total length of an array called 'some_list':
<div>Total Length: {{some_list.length}}</div>
<div v-for="(each, i) in some_list">
{{i + 1}} : {{each}}
</div>
If instead of a list, you were looping through an object, then the second argument is key of the key/value pair. So for the object 'my_object':
var an_id = new Vue({
el: '#an_id',
data: {
my_object: {
one: 'valueA',
two: 'valueB'
}
}
})
The following would print out the key : value pairs. (you can name 'each' and 'i' whatever you want)
<div id="an_id">
<span v-for="(each, i) in my_object">
{{i}} : {{each}}<br/>
</span>
</div>
For more info on Vue list rendering: https://v2.vuejs.org/v2/guide/list.html
Using Vue 1.x, use the special variable $index like so:
<li v-for="catalog in catalogs">this index : {{$index + 1}}</li>
alternatively, you can specify an alias as a first argument for v-for directive like so:
<li v-for="(itemObjKey, catalog) in catalogs">
this index : {{itemObjKey + 1}}
</li>
See : Vue 1.x guide
Using Vue 2.x, v-for provides a second optional argument referencing the index of the current item, you can add 1 to it in your mustache template as seen before:
<li v-for="(catalog, itemObjKey) in catalogs">
this index : {{itemObjKey + 1}}
</li>
See: Vue 2.x guide
Eliminating the parentheses in the v-for syntax also works fine hence:
<li v-for="catalog, itemObjKey in catalogs">
this index : {{itemObjKey + 1}}
</li>
Hope that helps.
Why its printing 0,1,2...?
Because those are indexes of the items in array, and index always starts from 0 to array.length-1.
To print the item count instead of index, use index+1. Like this:
<li v-for="(catalog, index) in catalogs">this index : {{index + 1}}</li>
And to show the total count use array.length, Like this:
<p>Total Count: {{ catalogs.length }}</p>
As per DOC:
v-for also supports an optional second argument (not first) for
the index of the current item.
this might be a dirty code but i think it can suffice
<div v-for="(counter in counters">
{{ counter }}) {{ userlist[counter-1].name }}
</div>
on your script add this one
data(){return {userlist: [],user_id: '',counters: 0,edit: false,}},

Vue.js When applying multiple filters a list, how can you display a count/total of the results

lets say I have a large object of people. and I want to filter them by hair color and gender. Once the filtering has taken place - how can i display the total number of results?
here is some pseudo code to help explain:
Vue.filter('hairFilter', function(person, color){
return person.filter(function( item ){
return item.hair == color
})
});
Vue.filter('genderFilter', function(person, gender){
return person.filter(function( item ){
return item.gender == gender
})
});
<h1>Total Results: [TOTAL FILTERED RESULTS NUMBER HERE]</h1>
<ul>
<li v-for="person in people | hairFilter 'red'| genderFilter 'male'">{{person.name}}</li>
</ul>
Thanks in advance
You can use a computed property and $eval.
{
computed: {
filteredPeople: function () {
return this.$eval("person in people | hairFilter 'red'| genderFilter 'male'");
}
}
}
Then in your template do like:
<h1>Results {{ filteredPeople.length }}</h1>
<ul>
<li v-for="person in filteredPeople">{{ person.name }}</li>
</ul>