AngularJS ng-options/Typeahead expression syntax - angularjs

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":"..."}, .. ];
}

Related

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

Angular : Getting values of check box when it is checked

This is my view I want to get the values such as diabetes , or htn etc cause I want to store them in a string format. But the way I am dooing it right now I get it in an object format
font(color ='green', size ='3')
strong Past History
.checkbox
label
input(type='checkbox', value='',name = 'diabetes', ng-model = 'formData.history.diabetes')
| DIABETES
.checkbox
label
input(type='checkbox', value='',name = 'htn', ng-model = 'formData.history.htn')
| HTN
.checkbox
label
input(type='checkbox', value='',name = 'asthma', ng-model = 'formData.history.asthma')
| ASTHMA/COPD
Now in my controllers when I
console.log($scope.formData.history)
I get an output like:
`{diabetes : true}`
But I want to send this data to my backend in a String form. Any idea how to get only "diabetes" or "htn" . thank you
The type of the value binded to the checkbox model is by default a boolean. That's why you get true or false as values.
Use the directives ng-true-value and/or ng-false-value if you want to change that. Here is an example, in html:
<input type="checkbox" name="htn" ng-model="formData.history.htn" ng-true-value="'htn'">
By your scenario you should declare data-ng-model as Array.
Your answer is here
<input type="checkbox" ng-model='formData.history[1]' ng-true-value="'htn'">
font(color ='green', size ='3')
strong Past History
.checkbox
label
input(type='checkbox', value='', data-ng-true-value='diabetes', name = 'diabetes', ng-model = 'formData.history.diabetes')
| DIABETES
.checkbox
label
input(type='checkbox', value='', data-ng-true-value='htn', name = 'htn', ng-model = 'formData.history.htn')
| HTN
.checkbox
label
input(type='checkbox', value='', data-ng-true-value='asthma', name = 'asthma', ng-model = 'formData.history.asthma')
| ASTHMA/COPD
Check how I used data-ng-true-value attribute if checked that will contain the value. Similarly you can have data-ng-false-value when it is unchecked. That should give you {diabetes : diabetes}, {htn: htn} But the way you have written your ng-model it will act like radio button if you need multiple selection your ng-model need to be modified to fit the scenario. Hope that helps
JSON.stringify($scope.formData.history)
This should solve your problem if you want your data in a JSON format.

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?

How to filter a certain object property value with angular select box

I would like to filter out a object that has a property value of "None". The object CounterParty has 2 properties, CounterPartyId and CounterPartyName.
The first object in the db has CounterPartyName: "None", I do not want this to show in the select box options.
I setup a plunker but the select-box is not working and there are no errors in the console:
Plunker
<select ng-model="search.CounterParty"
ng-options="c.CounterPartyName as c.CounterPartyName for c in counterPsList | unique: 'CounterPartyName'">
{{c.CounterParty}}
</select>
Json
$scope.counterParties = [
{"$id":"1","CounterPartyId":1,"CounterPartyName":"None","Documents":null},
{"$id":"2","CounterPartyId":2,"CounterPartyName":"CounterParty A","Documents":null},
{"$id":"3","CounterPartyId":3,"CounterPartyName":"Counter Party B","Documents":null},
{"$id":"4","CounterPartyId":4,"CounterPartyName":"Counter Party C","Documents":null},
{"$id":"5","CounterPartyId":5,"CounterPartyName":"Counter Party D","Documents":null}
];
You don't need to use angular-ui's unique filter here - its purpose is something else.
If you just need to filter out based on a certain property, you could specify the filter expression like so (notice the !):
ng-options = '...in counterPsList | filter: { CounterPartyName: "!None" }'
plunker

Attempting to pass an expression as an argument to a directive. Being taken literally instead of value

I'm trying to pass the value from an that is displayed through an ng-repeat into a function in my controller. The value displays properly in the HTML but when I get over to the function it displays the AngularJS expression instead of the actual value.
The HTML is as follows:
<li ng-repeat="account in accounts | filter:accountQuery" ng-click="setDisplayedFilters('{{account.AccountId}}')">
<span>{{account.Name}}</span>
</li>
When I inspect the element inside of a browser (Chrome in this case) it displays the actual AccountId like it is supposed to.
The setDisplayedFilters function is as follows:
$scope.setDisplayedFilters = function(accountId){
alert(accountId);
$.each($scope.accounts, function(i, item){
if(item.AccountId == accountId)
{
alert("Selected Account Id: " + accountId + "Matching Id in accounts Array: " + item.AccountId);
}
});
};
The first alert in the javascript will execute and displays "{{account.AccountId}}". The second one won't because it's comparing {{account.AccountId}} against the actual account Ids. So what I'm wondering is, what am I missing that is causing angular to interpret the AngularJS expresion literally rather than the value that should go in it's place?
-> setDisplayedFilters(account.AccountId)

Resources