Sort an object's assocation in Ember.js - sorting

I'm looking to sort an object's association - for instance, I am on a Group (object) page and the Group has many Posts that I show on that page. How would I sort those Posts to arrange them by created_at, or some other property?

You can use an ArrayController for your collection of Posts and then use the built in sortProperties and sortAscending properties.
App.GroupRoute = Ember.Route.extend({
setupController : function(controller,model){
this._super(controller,model);
this.controllerFor('posts').set('content',model.get('posts'));
}
});
App.GroupController = Ember.ObjectController.extend({
needs : ['posts']
});
App.PostsController = Ember.ArrayController.extend({
sortProperties : ['createdAt'],
sortAscending : false
});
By calling render in your group template, you can get access to a controller that has been needed by your main controller. So then your group template looks something like this:
<h2>Group : {{name}}</h2>
{{ render 'posts' }}
And then the posts template might be:
<ul>
{{#each post in arrangedContent}}
<li>{{ post.title }}</li>
{{/each}}
</ul>
Note that it's using arrangedContent as the name of the collection. You can change the sort order dynamically by setting sortProperties and sortAscending on PostsController.
Here's a JSFiddle of the general idea (but with different model names).
http://jsfiddle.net/YeKCf/
Click on the column headings in the table to see dynamic sorting in action.

Related

How to get Unique value in blade file laravel

I want to fetch unique value for filters of all products.
My db structure as follows
id Product category_id format attribute
1 demo1 5 HD test1
2 demmo2 4 SD test3
3 demmo3 4 HD test2
4 demmo4 3 HD test3
I want add filters of format and attribute in product page. But in that HD comming 3 times. I want to display that one only.
I am not getting how to display only single time.
Below is my controller code:
$item = Item::where('active_status', 1)->where('status', "1");
$data['item_count'] = $item;
$data['item'] = $item->paginate(20);
return view('frontend.pages.explore', compact('data'));
Below is blade file
<div class="filter-btn">
#foreach($data['item'] as $resolution)
<a class="btn btn-white-outline display-4" href="">{{array_unique($resolution->format)}}</a>
#endforeach
</div>
I am not getting how to display unique value only. Anyone have idea then let me know
since you are paginating your data, your "first page" might not have all the formats, so you have to do another query to your database:
$formats = DB::table('items')->select('format')->distinct()->get()
...
view(..., compact('data', 'formats'))
in the blade table:
#foreach($formats as $resolution)
<a class="btn btn-white-outline display-4" href="">{{$resolution->format}}</a>
#endforeach
If I am correct about your query, then you need to use groupby to list the items in your controller.
$items = Item::groupBy('format')->get();
The solution would be to create a sperate model for Formatand relationship between it and Product or whatever model that needs format , then fetch formats from its table and apply eager load .
this may look longer than your solution , but this is standards shoiuld be taken for vrious reasons :
less sql queries
more flexibility and options regarding our new table
better and less code to crud format
single source for change
less database data and faster load
...
Product.php
public function format(){
return $this->belongsTo(Format::class);
}
Format.php
public function products(){
return $this->hasMany(Product::class);
}
Usage
in controller
// get all formts eager loaded with products
$formats = Format::with('products')->get();
//get all products
$product = Format::latest()->paginate(20);
return view('frontend.pages.explore', compact( 'products' ,'formats'));
in your view
// all prodcuts
#foreach($formats as $format)
<a class="btn btn-white-outline display-4" href="">{{$format->name}}</a>
#endforeach
// in filter ( at clicking ) no additional query
#foreach($format->products as $product)
...
#endforeach

How to prevent loops in laravel global variable

I've created file GlobalVariable.php inside app\Composers
public function compose($view)
{
$categories = \App\Models\Category::all();
$view->with('globCategory', $categories);
}
then register to AppServiceProvider the code view()->composer('*', GlobalVariable::class);
I use global $globCategory for creating dynamic navbar
<ul class="nav nav-tabs border-0 flex-column flex-lg-row">
#foreach ($globCategory as $item)
<li class="nav-item">
{{$item->name}}
</li>
#endforeach
</ul>
the only problem here when I see laravel debuggar it show repetition of categories query.
here is the result
How to avoid this looping query? is there correct way?
The way you're registering your view composer (using '*' instead of a particular view name), it's going to call the compose method for every single rendered view + subview.
What you can do is instead of this:
view()->composer('*', GlobalVariable::class);
Have this:
\View::share('globCategory', \App\Models\Category::all());
This will globally share your categories (within views), and run the query only once.
View composers, as described from the laravel documentation, bind data to a view every time it is rendered. They clean our code by getting fetching data once and passing it to the view.
While it is possible to get the data in every controller method and pass it to the single view, this approach may be undesirable.
Replace the view name with an asterisk wildcard.

laravel 5.5 multiple controller inside one view

How to show TeamController#index and ProductController#index both show list of team and product inside one view main.blade.php
Looks like you want to show two datasets on one page. Basically, it means you have to execute two controller methods but it's not necessary to follow each and everything that official documentation says.
For example, if Products belong to a team, you can execute only TeamController#index and show products as given below.
#foreach($teams as $team)
#foreach($team->products as $product)
{{ $product->name }}
#endforeach
#endforeach
If no teams and products are two different entities and does not have any relation, you can just pass teams and products like this:
TeamController.php
public function index()
{
$teams = Team::all();
$products = Product::all(); // Don't forget to include 'use App\Product'
return view('index',compact(['teams','products']);
}
and then you can show teams and products like this:
index.blade.php
#foreach($teams as $team)
{{ $team->name }}
#endforeach
#foreach($products as $product)
{{ $product->name }}
#endforeach
Getting information from two different models does not mean you have to execute two different controller functions.
Still, if you want to get data from two different controllers, you can setup index.blade.php and create two ajax requests that will get data from two different URLs (two different controller methods).
Let me know if you have any more questions.
You can't show results from two controllers like that. Create a view that includes both the view that TeamController#index and ProductController#index return. be aware that both might be extending a layout which will probably try to load your page twice, so keep in mind to split the views into smaller components and include only those.
More info here
https://laravel.com/docs/5.6/views#creating-views

Laravel Sub-menu Within View

Hi I am very new to Laravel and MVC frameworks in general and am looking to create a list of links (in a view within a template) that links to some content. I am using this to display a list of nine people and to display their profile description when the link is clicked on. I have created a model of what the page looks like at http://i.imgur.com/8XhI2Ba.png. The portion that I am concerned with is in blue. Is there a way to route these links to something like /about/link2 or /about?link2 while maintaining the same exact page structure but modifying the ‘link content’ section (on the right of the link menu) to show the specific link's content? I would greatly appreciate it if someone could point me in the right direction, as I have literally no clue where to go with this!
There are a couple ways you can go about doing this.
Templates
Create your route.
Im assuming a lot about your app here but hopefully you get the picture. If you need help with anything in particular, be sure to update your question with the code youve tried so it will be easier to help you.
Route::get('about/{page}', function($page)
{
$profile = Profile::where('name', $page)->first();
return View::make('about')->with('profile', $profile);
});
Modify Template.blade.php
Put this line where you wish for About.blade.php to appear.
#yield('content')
Create your view which will extend your template
#extends('Template')
#section('content')
<h2>User Profile</h2>
<ul>
<li>Name: {{ $profile->name }}</li>
<li>Last Updated: {{ $profile->updated_at }}</li>
</ul>
#stop
AJAX
This solution will utilize AJAX to grab the data from the server and output it on the page.
Route for initial page view
Route::get('about', function($page)
{
$profiles = Profile::all();
return View::make('about')->with('profiles', $profiles);
});
Feel free to follow the same templating structure as before but this time we need to add some javascript into the template to handle the AJAX. Will also need to id everything which needs to be dynamically set so we can easily set it with jquery.
#extends('Template')
#section('content')
<h2>Links</h2>
#foreach($profiles as $profile)
{{ $profile->name }}
#endforeach
<h2>User Profile</h2>
<ul>
<li>Name: <span id="profile_name">{{ $profile->name }}</span></li>
<li>Last Updated: <span id="profile_updated_at">{{ $profile->updated_at }}</span></li>
</ul>
<script>
function setProfile(a)
{
$.ajax({
method: 'get',
url: 'getProfile',
dataType: 'json',
data: {
profile: $(a).data('id')
},
success: function(profile) {
$('#profile_name').html(profile.name);
$('#profile_updated_at').html(profile.updated_at);
},
error: function() {
alert('Error loading data.');
}
});
}
</script>
#stop
Route to handle the AJAX request
Route::get('getProfile', function()
{
$profile_id = Input::get('profile');
$profile = Profile::find($profile_id);
return $profile->toJson();
});
Now, the page should not have to reload and only the profile information should be updated.
Making some assumptions here as no code posted and assuming you're using the latest version of Laravel, Laravel 5.
Lets say you have a table in your database named users and you have a Model named Users (Laravel 5 comes with the Users model as default, see app/Users.php). The users will be the base of our data for the links.
Firstly, you want to register a route so you can access the page to view some information. You can do this in the routes file. The routes file can be found here: app/Http/routes.php.
To register a route add the following code:
Route::get('users', ['uses' => 'UserController#index']);
Now what this route does is whenever we hit the URL http://your-app-name/public/users (URL might be different depending on how you have your app set up, i.e. you may not have to include public) in our web browser it will respond by running the index method on the UserController.
To respond to that route you can set up your UserController as so:
<?php namespace App\Http\Controllers;
class UserController extends Controller {
public function index()
{
}
}
Controllers should be stored in app/Http/Controllers/.
Now lets flesh out the index method:
public function index()
{
// grab our users
$users = App\Users::all();
// return a view with the users data
return view('users.index')->with('users');
}
This grabs the users from the database and loads up a view passing the users data.
Here's what your view could look like:
<!DOCTYPE html>
<html>
<head>
<title>Users Page</title>
</head>
<body>
#foreach($users as $user)
<a href="{{ URL::route('user', ['id' => $user->id]) }}">
{{ $user->username }}
</a>
#endforeach
</body>
</html>
The view code will loop through each user from the $users data we passed to the view and create a link to their user page which is different for each user based on their id (their unique identifier in the DB)
Due to the way I've named it, this would be found in app/views/users/index.blade.php - if you save files ending in blade.php you can use Laravel's templating language, blade.
Now you need to finally set up another route to respond to a user page, for example http://your-app-name/public/user/22.
Route::get('user/{id}', ['uses' => 'UserController#show']);
Then add the show method to UserController
public function show($id)
{
// this will dump out the user information
return \App\User::find($id);
}
Hope that helps a little! Wrote most of it off the top of my head so let me know if you get any errors via comment.
This question is very bare, and it is difficult to actually help your situation without you showing any code. Just to point you in the right direction though, here is what you would need.
A Model called People, this is how you will access your data.
A controller. In this controller you will do the following
Get the ID of the profile you want from the functions parameters
Find that persons information e.g. People::find($person_id);
return the profile view with that persons data e.g. return view('profile')->with('person', $person);
In your view you can then use that data on that page e.g. {{ $person->name }}
For the page that needs to display the links to the people you would have a method in your controller which..
Get all the people data e.g. People::all();
Return a view with that data return view('all-people')->with('people', $people);
You will then need a route to access an individual person. The route will need to pass the persons ID into a controller method e.g.
Route::get('get-person/{id}',
[ 'as' => 'get-person',
'uses' => 'PeopleController#getPerson' ]);
You can then use this route in your view to get the links to each person
#foreach($people as $person)
{{$person->name}}
#endforeach
This would produce the list of links you want.

Ember.js: How do I access a specific item in a CollectionView?

First off I want to say that I really like ember.js. I have tried both Knockout and Angular but found them a bit to obtrusive and everything had to be done their way. I feel like ember allows me a bit more freedom to structure things how you see fit. With that said I have a couple of questions.
1. I would like to do something like the following which obviously doesn't work:
<h3>{{ content.name }}</h3>
Instead I would have to create a binding:
<a {{ bindAttr href="url" }}><h3>{{ content.name }}</h3></a>
How do i create the url path in the view? I could easily create a computed property called url on the model but that feels horrible and not very MVC. Do I have to create a new view for the element or register a helper which feels a bit cumbersome?
Here's the complete code:
App = Ember.Application.create();
var sampleData = [ Ember.Object.create({ id: '123456789', name: 'John' }), Ember.Object.create({ id: '987654321', name: 'Anne' }) ]
App.itemController = Ember.ArrayController.create({
content: sampleData,
removeItem: function(item) {
this.content.removeObject(item);
}
});
App.ItemListView = Ember.View.extend({
itemDetailView: Ember.CollectionView.extend({
contentBinding: 'App.itemController',
itemViewClass: Ember.View.extend({
tagName: 'li',
url: '' // HOW TO GET '/item/123456789'
deleteButton: Ember.Button.extend({
click: function(event) {
var item = this.get('content');
App.itemController.removeItem(item);
}
})
})
})
});
<script type="text/x-handlebars">
{{#view App.ItemListView}}
<ul id="item-list">
{{#collection itemDetailView}}
<div class="item">
<a {{ bindAttr href="url" }}><h3>{{ content.name }}</h3></a>
{{#view deleteButton class="btn" contentBinding="content"}}Delete{{/view}}
</div>
{{/collection}}
</ul>
{{/view}}
</script>
2. I feel that the view "owns" the controller and not the other way around. Shouldn't the view be unaware of which controller it is hooked up to so you can reuse the view? I'm thinking about these to lines in the view:
contentBinding: 'App.itemController',
and
App.itemController.removeItem(item);
How do you structure this?
3. I realize everything is a work in progress and quite new with the name change and all but the documentation is quite unclear. The examples use the old namespace SC and there are lot of things missing on emberjs.com compared to the Sproutcore 2.0 guides, for example collections, arraycontrollers. I read somewhere here that collections will be phased out. Is that true and should I use #each instead?
Thanks for your help and for an awesome framework!
1.) If you want to use <a href="...">, you will need a computed property. It could be on your model or on a view. Another technique would be to use Ember.Button: {{#view Ember.Button tagName="a" target="..." action="..."}}...{{/view}}
2.) Typically you'll want to declare your controller binding in the template, rather than in the view. For example: {{#view App.ItemListView contentBinding="App.itemController"}}
3.) The #collection helper will likely be deprecated, so you should probably use an #each instead.

Resources