Sort by function, on angular js, clicking header table - angularjs

I'm attempting to learn angular. I've been using the default hr schema from Oracle and I'm using a web API to bring back the employee collection and the department collection.
I'm rendering an HTML table to display the employee info. For the department column I have a function that takes the emp.department_id, does a lookup on the department collection and returns the department name.
I have headers on the table that when clicked sort the table in ascending or descending.
However I'm struggling with the sort on the department name column since department name is not actually a field on the employee collection. I tried to sort by the function I was using to get the value but I'm not quite getting it.
In my controller I have the following function to get the department name:
$scope.getDeptName = function(id){
for (var i=0; < model.departments.length; i++{
if(model.departments[i].department_id == id){
return model.departments[i].department_name;
}}}
My table headers:
<tr><th><a href="#" ng-click=orderByField='last_name'; reverseSort =! reverseSort>Name</a><th>
<th><a href="#" ng-click=orderByField='getDeptName(department_id)'; reverseSort =! reverseSort>Dept Name</a><th></tr>
<tr> ng-repeat="emp in model.employees |orderBy:orderByField:reverseSort">
The sort by Department Name is not working, I'm unsure how to sort by the function.

The orderByField must be set to the function allowing to get the name of the employee. Not to a string containing a call to this function. The correct way is thus
ng-click="orderByField = getDeptNameFromEmployee"
which, in JS, is equivalent to
$scope.orderByField = $scope.getDeptNameFromEmployee;
But beware: getDeptNameFromEmployee must take an employee object as parameter, and not an employee ID, for this to work. So it should look like
$scope.getDeptNameFromEmployee = function(employee) {
return $scope.getDeptName(employee.deptId);
};

Take the quotes off the function call:
<a href="#" ng-click=orderByField='getDeptName(department_id)'; reverseSort =! reverseSort>Dept Name</a>
should be:
Dept Name

Related

How to display multiple selected value from db based of their ID in Laravel

I want to show array of data based on their id. I have two tables.
first one is "languages"
Other is "user"
each user has one or more languages.
so I have stored languages id in user table in array form.
now I want to show languages in- show user detail page-.
I used the following controller:
``` public function show()
{
$user=auth()->user()->Consult;
$languagess=Lang::all();
$selected = explode(",", $con->languages);
$collection = [];
foreach($selected as $r){
$collection[] = DB::table('language')->where('id', $r['languages'])->first();
}
dd($collection);
return View('consultacy.showPro',compact('user','languages'));
}```
I used following view :
<span >{{ $languagess['name']}}</span>
#endforeach
the error :
Illegal string offset 'languages'
Any tutorial or method to do this

AngularJS orderby refining

I have a table of names starting with a title (Mr, Mrs, etc) and dates stored as strings plus some other data.
I am currently sorting it using
<tr dir-paginate="booking in bookingResults | orderBy:sortType:sortReverse | filter:searchPassenger | itemsPerPage: 15">
How could I refine my orderBy to sort names excluding the title (Mr, Mrs, etc) and dates as parsed dates not strings.
What would be best practice here?
EDIT :
I don't want to change the names in the model by the way - I want the format to remain "Mr Foo" and "Mr Bar" but when I sort them I want them to act as if they were just "Foo" and "Bar".
EDIT EDIT :
AngularJS 1.5.6
getting the right data in the right format
title & name
I'd use a regexp to pull the title from the name:
var regex = /((Dr\.|Mr\.|Ms\.|Miss|Mrs\.)\s*)/gmi
objName.replace(regex, '')
date
I'm assuming you're getting either a date object or a standard date string. If it's the latter, just create a Date object via new Date(incomingDateString). Then you can call:
objDate.getTime() //returns epoch in milliseconds
sorting
Some people might dislike this but I hate dirtying up view controllers with methods that NG directives need to use for things like ordering. Instead, I added some ng-flagged properties using ng-init on each row item. Then I can sort based off that. I didn't do it for the date in the example but you could extrapolate and apply.
ng-init w. ng-flagged properties
<tr ng-repeat="row in vc.listData | orderBy:vc.sortKey track by $index"
ng-init="row.$name = row.name.replace(vc.regexp, '')">
So in other words your objects go from this:
{
name:'Mr. Fred Rogers',
date:<date-object>
}
to this thanks to ng-init:
{
name:'Mr. Fred Rogers',
date:<date-object>,
$name:'Fred Rogers',
$date:1466192224091
}
And then via your sorting UI, you can set your $scope.sortKey to either $name or $date.
code pen
I made a sample in code pen but I did it with my template which is coffeescript and jade. You can probably figure out what I'm doing.
pen - http://codepen.io/jusopi/pen/aZZjgG?editors=1010
Ok, after some research, I found that the easiest solution is upgrading to AngularJS version 1.5.7 which introduces the comparator into the orderBy filter.
So I've changed my repeater to use an order by comparator
<tr dir-paginate="booking in Results | orderBy:Variable:TrueOrFalse:bookingComparator">
Variable is a string which I bound to the table headings so you can change the order by key, TrueOrFalse is a boolean which alternates between ascending and descending if you click the table heading and bookingComparator is my actual comparator.
My booking comparator looks like this
$scope.bookingComparator = function (a, b) {
var getTitle = /((Mrs|Mr|Mstr|Miss|Dr)\s*)/g;
var isDate = /(-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-)/g
if (getTitle.test(a.value)) {
var aName = a.value, bName = b.value;
return aName.replace(getTitle, '') < bName.replace(getTitle, '') ? -1 : 1
}
if (isDate.test(a.value)) {
var aDate = new Date(a.value), bDate = new Date(b.value);
return aDate.getTime() < bDate.getTime() ? -1 : 1
}
return a.index < b.index ? -1 : 1
}
The comparator is basically a function acting like the javascript .sort() method.
If the value contains a title (Mr, Mrs, etc) it is a name so I strip the titles and compare the actual names regardless of title.
If the variable matches a -Month- pattern, it's a date string and I compare the parsed date objects.
Hope this is helpful to someone, took me a while to figure out. I'm open to suggestions if you think there's a better way of doing this, and feel free to post an answer for people who want to use AngularJS =< 1.5.6

AngularJS ng-options/Typeahead expression syntax

I was trying to find the AngularJS select with ng-options or Typeahead expression syntax but I couldn't find the whole thing in one place, so I gather information from here and there and this is what I came up with:
Expression syntax (This is the full syntax, most of it are optional):
(ObjectForModel) as (stringRepresentation for the UI) for (OneObjectFromList) in (ListOfObjects) | (Filter1) | (Filter2) ...
Example: Lets say we have a list of Students:
var StudentList = [{firstName: "Jhon",lastName:"Smith" id:1},{firstName: "Clint",lastName:"Eastwood" id:2} ];
Lets say that we wanna use this list in a typeAhead input but:
1. We want our popup drop down to display: "first name - last name" but when a user select an item we want the whole item from the list to be populate in the ng-model.
2. We want to filter the select to show only 5 elements
3. We want the pop up drop down list to display only what is relevant base on the user input.
So this is how it looks like:
uib-typeahead="student as (student.firstName +' - ' + student.lastName) for student in studentList | filter:$viewValue | limitTo:5"
If you guys have something more to add please do, I know I could have use it...
You can also change the template ( for example displaying a field in a particular way, and on click set the input with another one )
in the html file :
<script type="text/ng-template" id="deterFormACTemplate.html">
<a ng-bind-html="match.model.displayed | unsafe"></a>
</script>
<input typeahead-template-url="deterFormACTemplate.html"
uib-typeahead="item as item.field for item in autocomplete(...)"
typeahead-on-select="mymodel=$model.field;"
typeahead-wait-ms="500" />
in the controller
$scope.autocomplete = function ( ){
return [ {'field':'..', "displayed":"..."},{'field':'..', "displayed":"..."}, .. ];
}

assigning id to new added object in ngrepeat

i am using Xeditable Angular,
Working fine.
The issue is when i added a new data as a new row to table. and i made a ajax call to server, server saved it, and returned new id, i want to assign this id to the new added model. how i do that.
When i added a new item, it added instantly to model by xeditable, its fine, but its id field is null, i want to change the null to the return value from server. how select the item of last edited by its track by id
<tr ng-cloak ng-repeat="school in results = (content.data | filter: content.search | orderBy:sortType:sortReverse | offset: (content.currentPage-1) * content.pageSize | limitTo: content.pageSize) track by school.id">
<td><input type="checkbox" ng-model="content.deleteList[school.id]" ng-checked="content.head"></td><td>{{school.id}}</td> .......................................
Only part of desplayed
What you can do is update the id when you get a reply form the server :
$scope.addData = function(user) {
yourFactory.addData(user).then(function(result) {
user.id = result.data.id;
});
}
I may be able to help you better if you provide more code

Filter ng-repeat more times

I'm creating an application to manage restaurant orders.
I create the menu from $http so I've this list:
<div class="row vertical" style="background-image: url(/gest/images/etichette/ANTIPASTI.png);border-color: #0CF">
<div class="card piatti col s2" ng-repeat="anti in antis | filter:{tipo:'ANTIPASTI'}">
<div class="card-content"> <span class="card-title truncate red darken-3">{{anti.piatto}}</span> </div>
<div class="card-action"> {{n}}</div>
</div>
</div>
The div with class "row vertical" contain one time starters, then pasta, then beef ecc.
So I use ng-repeat each time, and filter by tipo.
My question is: is there any way to make ng-repeat only one time to show all menu (orderer before by starters, then pasta, beef ecc)?
I have this data (is a restaurant menu):
piatto: name of the the dish
tipo: category of the dish (like pasta, beef, fish, starters ecc)
I would show with only one repeat all the dishes ordered so:
starters, pasta, beef, fish, dessert etc.
And I would create each time a new row
From what I understand you already have all your date on the antis and you just want to filter it by type or do you want to OrderIt by a certain type?
This fiddle for example would order by name, but you can also provide an array with functions to retrieve each type in the way that you like, you can read about it here.
But basically you'd do
anti in antis | orderBy:'+tipo'
or
anti in antis | orderBy: [ function(){}, function(){} ]
EDIT:
As #yarons mentioned you can also chain strings to filter even further. I've updated the Fiddle so now the filter would be anti in antis | orderBy:['+tipo', '+piato']" which indicates that first the tipo would be alphabetically ordered ascending (+ indication) and after that the piato would also be alphabetically ascending.
If you'd want to define a different order than the alphabetical one I think you can use a sort of ENUM for the tipo as in:
var tipoENUM = {};
tipoENUM['ANIPASTI'] = 0;
tipoENUM['PASTA'] = 1;
tipoENUM['PIZZA'] = 2;
tipoENUM['BEEF'] = 3;
tipoENUM['DESERT'] = 4;
So that way you'd avoid using the string for the order, see following fiddle for the example.
EDIT 2:
Ok, so if you receive the data via the HTTP request it's better if you create a order function to help you, check this updated fiddle, like so:
// The enum would be defined as before but:
$scope.orderTipo = function (dish) {
return tipoENUM[dish.tipo];
}
On the HTMl you'll do:
ng-repeat="anti in antis | orderBy:[orderTipo, '+piato']"
Ok your example is perfect but I would repeat each time the "tipo" and then the relative "piato" in a list....something like this:
ANTIPASTI
- bruschetta
- suppli
- fritto
PRIMI
- caqrbonara
- amatriciana
etc.
Is it possible?

Resources